1 |
- {"mappings":"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","sources":["packages/react/presence/src/index.ts","packages/react/presence/src/Presence.tsx","packages/react/presence/src/useStateMachine.tsx"],"sourcesContent":["export { Presence } from './Presence';\nexport type { PresenceProps } from './Presence';\n","import * as React from 'react';\nimport * as ReactDOM from 'react-dom';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { useLayoutEffect } from '@radix-ui/react-use-layout-effect';\nimport { useStateMachine } from './useStateMachine';\n\ninterface PresenceProps {\n children: React.ReactElement | ((props: { present: boolean }) => React.ReactElement);\n present: boolean;\n}\n\nconst Presence: React.FC<PresenceProps> = (props) => {\n const { present, children } = props;\n const presence = usePresence(present);\n\n const child = (\n typeof children === 'function'\n ? children({ present: presence.isPresent })\n : React.Children.only(children)\n ) as React.ReactElement;\n\n const ref = useComposedRefs(presence.ref, (child as any).ref);\n const forceMount = typeof children === 'function';\n return forceMount || presence.isPresent ? React.cloneElement(child, { ref }) : null;\n};\n\nPresence.displayName = 'Presence';\n\n/* -------------------------------------------------------------------------------------------------\n * usePresence\n * -----------------------------------------------------------------------------------------------*/\n\nfunction usePresence(present: boolean) {\n const [node, setNode] = React.useState<HTMLElement>();\n const stylesRef = React.useRef<CSSStyleDeclaration>({} as any);\n const prevPresentRef = React.useRef(present);\n const prevAnimationNameRef = React.useRef<string>('none');\n const initialState = present ? 'mounted' : 'unmounted';\n const [state, send] = useStateMachine(initialState, {\n mounted: {\n UNMOUNT: 'unmounted',\n ANIMATION_OUT: 'unmountSuspended',\n },\n unmountSuspended: {\n MOUNT: 'mounted',\n ANIMATION_END: 'unmounted',\n },\n unmounted: {\n MOUNT: 'mounted',\n },\n });\n\n React.useEffect(() => {\n const currentAnimationName = getAnimationName(stylesRef.current);\n prevAnimationNameRef.current = state === 'mounted' ? currentAnimationName : 'none';\n }, [state]);\n\n useLayoutEffect(() => {\n const styles = stylesRef.current;\n const wasPresent = prevPresentRef.current;\n const hasPresentChanged = wasPresent !== present;\n\n if (hasPresentChanged) {\n const prevAnimationName = prevAnimationNameRef.current;\n const currentAnimationName = getAnimationName(styles);\n\n if (present) {\n send('MOUNT');\n } else if (currentAnimationName === 'none' || styles?.display === 'none') {\n // If there is no exit animation or the element is hidden, animations won't run\n // so we unmount instantly\n send('UNMOUNT');\n } else {\n /**\n * When `present` changes to `false`, we check changes to animation-name to\n * determine whether an animation has started. We chose this approach (reading\n * computed styles) because there is no `animationrun` event and `animationstart`\n * fires after `animation-delay` has expired which would be too late.\n */\n const isAnimating = prevAnimationName !== currentAnimationName;\n\n if (wasPresent && isAnimating) {\n send('ANIMATION_OUT');\n } else {\n send('UNMOUNT');\n }\n }\n\n prevPresentRef.current = present;\n }\n }, [present, send]);\n\n useLayoutEffect(() => {\n if (node) {\n /**\n * Triggering an ANIMATION_OUT during an ANIMATION_IN will fire an `animationcancel`\n * event for ANIMATION_IN after we have entered `unmountSuspended` state. So, we\n * make sure we only trigger ANIMATION_END for the currently active animation.\n */\n const handleAnimationEnd = (event: AnimationEvent) => {\n const currentAnimationName = getAnimationName(stylesRef.current);\n const isCurrentAnimation = currentAnimationName.includes(event.animationName);\n if (event.target === node && isCurrentAnimation) {\n // With React 18 concurrency this update is applied\n // a frame after the animation ends, creating a flash of visible content.\n // By manually flushing we ensure they sync within a frame, removing the flash.\n ReactDOM.flushSync(() => send('ANIMATION_END'));\n }\n };\n const handleAnimationStart = (event: AnimationEvent) => {\n if (event.target === node) {\n // if animation occurred, store its name as the previous animation.\n prevAnimationNameRef.current = getAnimationName(stylesRef.current);\n }\n };\n node.addEventListener('animationstart', handleAnimationStart);\n node.addEventListener('animationcancel', handleAnimationEnd);\n node.addEventListener('animationend', handleAnimationEnd);\n return () => {\n node.removeEventListener('animationstart', handleAnimationStart);\n node.removeEventListener('animationcancel', handleAnimationEnd);\n node.removeEventListener('animationend', handleAnimationEnd);\n };\n } else {\n // Transition to the unmounted state if the node is removed prematurely.\n // We avoid doing so during cleanup as the node may change but still exist.\n send('ANIMATION_END');\n }\n }, [node, send]);\n\n return {\n isPresent: ['mounted', 'unmountSuspended'].includes(state),\n ref: React.useCallback((node: HTMLElement) => {\n if (node) stylesRef.current = getComputedStyle(node);\n setNode(node);\n }, []),\n };\n}\n\n/* -----------------------------------------------------------------------------------------------*/\n\nfunction getAnimationName(styles?: CSSStyleDeclaration) {\n return styles?.animationName || 'none';\n}\n\nexport { Presence };\nexport type { PresenceProps };\n","import * as React from 'react';\n\ntype Machine<S> = { [k: string]: { [k: string]: S } };\ntype MachineState<T> = keyof T;\ntype MachineEvent<T> = keyof UnionToIntersection<T[keyof T]>;\n\n// 🤯 https://fettblog.eu/typescript-union-to-intersection/\ntype UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any\n ? R\n : never;\n\nexport function useStateMachine<M>(\n initialState: MachineState<M>,\n machine: M & Machine<MachineState<M>>\n) {\n return React.useReducer((state: MachineState<M>, event: MachineEvent<M>): MachineState<M> => {\n const nextState = (machine[state] as any)[event];\n return nextState ?? state;\n }, initialState);\n}\n"],"names":["Presence","React","ReactDOM","useComposedRefs","useLayoutEffect","useStateMachine","props","present","children","presence","usePresence","child","isPresent","Children","only","ref","forceMount","cloneElement","displayName","node","setNode","useState","stylesRef","useRef","prevPresentRef","prevAnimationNameRef","initialState","state","send","mounted","UNMOUNT","ANIMATION_OUT","unmountSuspended","MOUNT","ANIMATION_END","unmounted","useEffect","currentAnimationName","getAnimationName","current","styles","wasPresent","hasPresentChanged","prevAnimationName","display","isAnimating","handleAnimationEnd","event","isCurrentAnimation","includes","animationName","target","flushSync","handleAnimationStart","addEventListener","removeEventListener","useCallback","getComputedStyle","machine","useReducer","nextState"],"version":3,"file":"index.js.map"}
|