UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

68 lines (67 loc) 2.29 kB
'use client'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { useIsoLayoutEffect } from '@base-ui-components/utils/useIsoLayoutEffect'; import { AnimationFrame } from '@base-ui-components/utils/useAnimationFrame'; /** * Provides a status string for CSS animations. * @param open - a boolean that determines if the element is open. * @param enableIdleState - a boolean that enables the `'idle'` state between `'starting'` and `'ending'` */ export function useTransitionStatus(open, enableIdleState = false, deferEndingState = false) { const [transitionStatus, setTransitionStatus] = React.useState(open && enableIdleState ? 'idle' : undefined); const [mounted, setMounted] = React.useState(open); if (open && !mounted) { setMounted(true); setTransitionStatus('starting'); } if (!open && mounted && transitionStatus !== 'ending' && !deferEndingState) { setTransitionStatus('ending'); } if (!open && !mounted && transitionStatus === 'ending') { setTransitionStatus(undefined); } useIsoLayoutEffect(() => { if (!open && mounted && transitionStatus !== 'ending' && deferEndingState) { const frame = AnimationFrame.request(() => { setTransitionStatus('ending'); }); return () => { AnimationFrame.cancel(frame); }; } return undefined; }, [open, mounted, transitionStatus, deferEndingState]); useIsoLayoutEffect(() => { if (!open || enableIdleState) { return undefined; } const frame = AnimationFrame.request(() => { ReactDOM.flushSync(() => { setTransitionStatus(undefined); }); }); return () => { AnimationFrame.cancel(frame); }; }, [enableIdleState, open]); useIsoLayoutEffect(() => { if (!open || !enableIdleState) { return undefined; } if (open && mounted && transitionStatus !== 'idle') { setTransitionStatus('starting'); } const frame = AnimationFrame.request(() => { setTransitionStatus('idle'); }); return () => { AnimationFrame.cancel(frame); }; }, [enableIdleState, open, mounted, setTransitionStatus, transitionStatus]); return React.useMemo(() => ({ mounted, setMounted, transitionStatus }), [mounted, transitionStatus]); }