UNPKG

react-widgets-up

Version:

An à la carte set of polished, extensible, and accessible inputs built for React

144 lines (139 loc) 4.36 kB
import React, { useState, useEffect, useRef, useCallback } from 'react'; // Transition states export const TRANSITION_STATES = { ENTERING: 'entering', ENTERED: 'entered', EXITING: 'exiting', EXITED: 'exited' }; // Transition component props interface // Internal callback interface // Custom Transition component export const Transition = ({ in: inProp, timeout: _timeout = 300, appear: _appear = false, enter: _enter = true, exit: _exit = true, mountOnEnter: _mountOnEnter = false, unmountOnExit: _unmountOnExit = false, nodeRef, addEndListener, onEnter, onEntering, onEntered, onExit, onExiting, onExited, children }) => { const [status, setStatus] = useState(() => { if (inProp) { return _appear ? TRANSITION_STATES.EXITED : TRANSITION_STATES.ENTERED; } return _mountOnEnter || _unmountOnExit ? null : TRANSITION_STATES.EXITED; }); const timeoutRef = useRef(null); const nextCallbackRef = useRef(null); const getNode = useCallback(() => { return (nodeRef == null ? void 0 : nodeRef.current) || null; }, [nodeRef]); const getTimeout = useCallback(phase => { if (typeof _timeout === 'number') { return _timeout; } return _timeout[phase] || 0; }, [_timeout]); const clearTimeoutHandler = useCallback(() => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = null; } }, []); const setNextCallback = useCallback(callback => { let active = true; const nextCallback = () => { if (active) { callback(); } }; nextCallback.cancel = () => { active = false; }; nextCallbackRef.current = nextCallback; return nextCallback; }, []); const performEnter = useCallback(() => { const node = getNode(); if (!_enter) { setStatus(TRANSITION_STATES.ENTERED); onEntered == null || onEntered(node || undefined); return; } onEnter == null || onEnter(node || undefined); setStatus(TRANSITION_STATES.ENTERING); onEntering == null || onEntering(node || undefined); const next = setNextCallback(() => { setStatus(TRANSITION_STATES.ENTERED); onEntered == null || onEntered(node || undefined); }); if (addEndListener && node) { addEndListener(node, next); } else { timeoutRef.current = setTimeout(next, getTimeout('enter')); } }, [_enter, onEnter, onEntering, onEntered, setNextCallback, getTimeout, getNode, addEndListener]); const performExit = useCallback(() => { const node = getNode(); if (!_exit) { setStatus(TRANSITION_STATES.EXITED); onExited == null || onExited(node || undefined); return; } onExit == null || onExit(node || undefined); setStatus(TRANSITION_STATES.EXITING); onExiting == null || onExiting(node || undefined); const next = setNextCallback(() => { setStatus(TRANSITION_STATES.EXITED); onExited == null || onExited(node || undefined); }); if (addEndListener && node) { addEndListener(node, next); } else { timeoutRef.current = setTimeout(next, getTimeout('exit')); } }, [_exit, onExit, onExiting, onExited, setNextCallback, getTimeout, getNode, addEndListener]); useEffect(() => { if (inProp && (status === TRANSITION_STATES.EXITED || status === null)) { if (status === null) { setStatus(TRANSITION_STATES.EXITED); } performEnter(); } else if (!inProp && (status === TRANSITION_STATES.ENTERED || status === TRANSITION_STATES.ENTERING)) { performExit(); } }, [inProp, status, performEnter, performExit]); useEffect(() => { return () => { var _nextCallbackRef$curr; clearTimeoutHandler(); if ((_nextCallbackRef$curr = nextCallbackRef.current) != null && _nextCallbackRef$curr.cancel) { nextCallbackRef.current.cancel(); } }; }, [clearTimeoutHandler]); // Handle mounting/unmounting logic if (_mountOnEnter && status === null) { return null; } if (_unmountOnExit && status === TRANSITION_STATES.EXITED) { return null; } if (typeof children === 'function') { return /*#__PURE__*/React.createElement(React.Fragment, null, children(status, nodeRef)); } return /*#__PURE__*/React.cloneElement(children, { transitionStatus: status, ref: nodeRef }); };