import * as React from 'react'; import { onceTransitionEnd, beforeFutureCssLayout as frameThrower, setCssEndEvent, // @ts-ignore } from '@rcaferati/wac'; import AwesomeButton, { ButtonType } from '../AwesomeButton'; import { getClassName } from '../../helpers/components'; const ROOTELM = 'aws-btn'; const LOADING_ANIMATION_STEPS = 3; const IS_WINDOW = typeof window !== 'undefined'; const useStateSync = (initial: any) => { const [value, setValue] = React.useState(initial); const ref = React.useRef(initial); const setSyncValue = (newValue: any) => { const newState = { ...ref.current, ...newValue, }; ref.current = newState; setValue(newState); }; return [value, setSyncValue, ref.current]; }; type ButtonTypeModified = Omit; export type ButtonProgressType = { onPress: (event: React.MouseEvent, next: () => void) => void; loadingLabel?: string; resultLabel?: string; releaseDelay?: number; }; const AwesomeButtonProgress = ({ onPress = null, rootElement = null, loadingLabel = 'Wait..', resultLabel = 'Success!', disabled = false, cssModule = null, children = null, size = null, type = null, releaseDelay = 500, ...extra }: ButtonProgressType & ButtonTypeModified) => { const root = rootElement || ROOTELM; const timeout = React.useRef(null); const content = React.useRef(null); const [state, setState, stateRef] = useStateSync({ loadingEnd: false, loadingStart: false, loadingError: false, errorLabel: null, active: false, }); React.useEffect(() => { return () => { if (timeout?.current) { clearTimeout(timeout.current); } }; }, []); const getRootClassName = () => { const { loadingStart, loadingEnd, loadingError } = stateRef; const className = [ (loadingStart && `${root}--start`) || null, (loadingEnd && `${root}--end`) || null, (loadingError && `${root}--errored`) || null, `${root}--progress`, ]; return className.join(' ').trim().replace(/[\s]+/gi, ' '); }; const endLoading = (endState = true, errorLabel: any = null) => { setState({ loadingEnd: true, loadingError: !endState, errorLabel, }); }; const startLoading = () => { frameThrower(4, () => { setState({ loadingStart: true, }); }); }; const clearLoading = (callback: any) => { setState({ loadingStart: false, loadingEnd: false, active: false, }); frameThrower(2, callback); }; const clearStagedWrapperAnimation = () => { timeout.current = setTimeout(() => { if (!IS_WINDOW) { return; } frameThrower(2, () => { clearLoading(() => { setState({ loadingError: false, errorLabel: null, }); }); }); }, releaseDelay); }; const handleActivation = React.useCallback(() => { setState({ active: true, }); }, [setState]); const handleAction = async (event: React.MouseEvent) => { if (stateRef?.loadingStart === true) { return; } startLoading(); await onceTransitionEnd(content.current); onPress && onPress(event, endLoading); setCssEndEvent(content.current, 'transition', { tolerance: LOADING_ANIMATION_STEPS, }).then(clearStagedWrapperAnimation); }; const { active, errorLabel } = stateRef; return ( } {...extra}> {children} ); }; export default AwesomeButtonProgress;