UNPKG

react-transition-preset

Version:

Lightweight, zero-dependency transition component for React with common preset transition

110 lines (107 loc) 3.75 kB
import { useState, useRef } from 'react'; import { useDidUpdate } from './hooks/use-did-update.js'; import { useIsomorphicLayoutEffect } from './hooks/use-isomorphic-layout-effect.js'; import { useMemoizedFn } from './hooks/use-memoized-fn.js'; import { secToMs } from './utils.js'; // src/use-transition.ts var TransitionStatus = /* @__PURE__ */ ((TransitionStatus2) => { TransitionStatus2["entered"] = "entered"; TransitionStatus2["exited"] = "exited"; TransitionStatus2["entering"] = "entering"; TransitionStatus2["exiting"] = "exiting"; TransitionStatus2["preExiting"] = "pre-exiting"; TransitionStatus2["preEntering"] = "pre-entering"; return TransitionStatus2; })(TransitionStatus || {}); function useTransition(props) { const { duration: durationInSec, initial, exitDuration: exitDurationInSec, timingFunction, mounted, reduceMotion, onEnter, onExit, onEntered, onExited, enterDelay: enterDelayInSec, exitDelay: exitDelayInSec } = props; const [duration, exitDuration, enterDelay, exitDelay] = [ durationInSec, exitDurationInSec, enterDelayInSec, exitDelayInSec ].map(secToMs); const [transitionDuration, setTransitionDuration] = useState(reduceMotion ? 0 : duration); const [transitionStatus, setStatus] = useState(() => { if (mounted) { return initial ? "pre-entering" /* preEntering */ : "entered" /* entered */; } return "exited" /* exited */; }); const transitionTimeoutRef = useRef(-1); const delayTimeoutRef = useRef(-1); const rafRef = useRef(-1); const handleStateChange = useMemoizedFn((shouldMount) => { const preHandler = shouldMount ? onEnter : onExit; const handler = shouldMount ? onEntered : onExited; window.clearTimeout(transitionTimeoutRef.current); const newTransitionDuration = reduceMotion ? 0 : shouldMount ? duration : exitDuration; setTransitionDuration(newTransitionDuration); if (newTransitionDuration === 0) { typeof preHandler === "function" && preHandler(); typeof handler === "function" && handler(); setStatus(shouldMount ? "entered" /* entered */ : "exited" /* exited */); } else { rafRef.current = requestAnimationFrame(() => { setStatus(shouldMount ? "pre-entering" /* preEntering */ : "pre-exiting" /* preExiting */); rafRef.current = requestAnimationFrame(() => { typeof preHandler === "function" && preHandler(); setStatus(shouldMount ? "entering" /* entering */ : "exiting" /* exiting */); transitionTimeoutRef.current = window.setTimeout(() => { typeof handler === "function" && handler(); setStatus(shouldMount ? "entered" /* entered */ : "exited" /* exited */); }, newTransitionDuration); }); }); } }); const handleTransitionWithDelay = useMemoizedFn((shouldMount) => { window.clearTimeout(delayTimeoutRef.current); const delay = shouldMount ? enterDelay : exitDelay; if (typeof delay !== "number") { handleStateChange(shouldMount); return; } delayTimeoutRef.current = window.setTimeout( () => { handleStateChange(shouldMount); }, shouldMount ? enterDelay : exitDelay ); }); useDidUpdate( () => { handleTransitionWithDelay(mounted); }, { deps: [mounted], initialMounted: initial && mounted } ); useIsomorphicLayoutEffect( () => () => { window.clearTimeout(transitionTimeoutRef.current); cancelAnimationFrame(rafRef.current); }, [] ); return { transitionDuration, transitionStatus, transitionTimingFunction: timingFunction || "ease" }; } export { TransitionStatus, useTransition };