{"version":3,"file":"AnimationManager.js","sourceRoot":"","sources":["../../src/web/AnimationManager.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\n\nimport { ImageTransition } from '../Image.types';\n\ntype Callbacks = {\n onReady?: (() => void) | null;\n onAnimationFinished?: (() => void) | null;\n onMount?: (() => void) | null;\n onError?: (() => void) | null;\n};\n\nexport type AnimationManagerNode = [\n key: string,\n renderFunction: (\n renderProps: NonNullable\n ) => (className: string, style: React.CSSProperties) => React.ReactElement\n];\n\nconst SUPPORTED_ANIMATIONS: ImageTransition['effect'][] = [\n 'cross-dissolve',\n 'flip-from-left',\n 'flip-from-right',\n 'flip-from-top',\n 'flip-from-bottom',\n];\n\ntype NodeStatus = 'mounted' | 'in' | 'active' | 'out' | 'errored';\n\nfunction useAnimationManagerNode(node: AnimationManagerNode | null, initialStatus?: NodeStatus) {\n const newNode = React.useMemo(() => {\n if (!node) {\n return null;\n }\n const [animationKey, renderFunction] = node;\n // key, ReactElement, ref, callbacks\n return {\n animationKey,\n persistedElement: renderFunction,\n status: (initialStatus || 'mounted') as NodeStatus,\n };\n }, [node?.[0]]);\n return newNode;\n}\n\nfunction validateTimingFunctionForAnimation(\n animationClass: ImageTransition['effect'],\n timingFunction: ImageTransition['timing']\n) {\n if (animationClass?.includes('flip')) {\n if (timingFunction?.includes('ease')) {\n return 'ease-in-out';\n }\n return 'linear';\n }\n return timingFunction || null;\n}\n\nfunction validateAnimationClass(effect: ImageTransition['effect']) {\n if (SUPPORTED_ANIMATIONS.includes(effect)) {\n return effect;\n }\n return 'cross-dissolve';\n}\n\nexport function getAnimatorFromTransition(transition: ImageTransition | null | undefined) {\n if (!transition?.duration) {\n return null;\n }\n const animationClass = validateAnimationClass(transition.effect);\n if (!animationClass) {\n return {\n startingClass: '',\n animateInClass: '',\n animateOutClass: '',\n containerClass: '',\n timingFunction: 'linear',\n animationClass: '',\n duration: 0,\n };\n }\n\n const timingFunction = validateTimingFunctionForAnimation(animationClass, transition.timing);\n const timingClass = `image-timing-${timingFunction}`;\n\n return {\n startingClass: `${animationClass}-start`,\n animateInClass: [animationClass, 'transitioning', `${animationClass}-active`, timingClass].join(\n ' '\n ),\n animateOutClass: [animationClass, `${animationClass}-end`, timingClass].join(' '),\n containerClass: `${animationClass}-container`,\n timingFunction,\n animationClass,\n duration: transition?.duration || 0,\n };\n}\n\ntype MountedAnimationNode = {\n animationKey: string;\n persistedElement: (\n renderProps: Callbacks\n ) => (className: string, style: React.CSSProperties) => React.ReactElement;\n status: NodeStatus;\n};\n\nexport default function AnimationManager({\n children: renderFunction,\n initial,\n transition,\n recyclingKey,\n}: {\n children: AnimationManagerNode;\n initial: AnimationManagerNode | null;\n transition: ImageTransition | null | undefined;\n recyclingKey?: string | null | undefined;\n}) {\n const animation = getAnimatorFromTransition(transition);\n\n const initialNode = useAnimationManagerNode(initial, 'active');\n\n const [nodes, setNodes] = React.useState(\n initialNode ? [initialNode] : []\n );\n\n const [prevRecyclingKey, setPrevRecyclingKey] = React.useState(recyclingKey ?? '');\n if (prevRecyclingKey !== (recyclingKey ?? '')) {\n setPrevRecyclingKey(recyclingKey ?? '');\n setNodes(initialNode ? [initialNode] : []);\n }\n\n const removeAllNodesOfKeyExceptShowing = (key?: string) => {\n setNodes((n) =>\n n.filter(\n (node) =>\n (key ? node.animationKey !== key : false) ||\n node.status === 'in' ||\n node.status === 'active'\n )\n );\n };\n\n const newNode = useAnimationManagerNode(renderFunction);\n\n React.useEffect(() => {\n setNodes((n) => {\n if (!newNode) {\n return n;\n }\n const existingNodeIndex = n.findIndex((node) => node.animationKey === newNode.animationKey);\n if (existingNodeIndex >= 0) {\n if (animation) {\n return n.map((n2) =>\n n2.animationKey === newNode.animationKey\n ? { ...newNode, status: 'in' }\n : { ...n2, status: 'out' }\n );\n } else {\n return [{ ...newNode, status: 'in' }];\n }\n }\n return [...n, newNode];\n });\n }, [newNode]);\n\n function wrapNodeWithCallbacks(node: MountedAnimationNode) {\n if (renderFunction[0] === node.animationKey) {\n return renderFunction[1]({\n onReady: () => {\n if (animation) {\n setNodes((nodes) =>\n nodes.map((n) => (n === newNode ? { ...n, status: 'in' } : { ...n, status: 'out' }))\n );\n } else {\n setNodes([{ ...node, status: 'in' }]);\n }\n },\n onAnimationFinished: () => {\n setNodes([{ ...node, status: 'in' }]);\n },\n onError: () => {\n setNodes((nodes) => nodes.map((n) => (n === node ? { ...n, status: 'errored' } : n)));\n },\n });\n }\n if (initial?.[0] === node.animationKey) {\n return initial[1]({\n onAnimationFinished: () => {\n if (node.status === 'out') {\n removeAllNodesOfKeyExceptShowing(node.animationKey);\n }\n },\n onError: () => {\n setNodes((nodes) => nodes.map((n) => (n === node ? { ...n, status: 'errored' } : n)));\n },\n });\n }\n return node.persistedElement({\n onAnimationFinished: () => {\n removeAllNodesOfKeyExceptShowing(node.animationKey);\n },\n });\n }\n const styles = {\n transitionDuration: `${animation?.duration || 0}ms`,\n transitionTimingFunction: animation?.timingFunction || 'linear',\n };\n const classes = {\n in: animation?.animateInClass,\n out: animation?.animateOutClass,\n mounted: animation?.startingClass,\n };\n\n return (\n <>\n {[...nodes]\n .filter((n) => n.status !== 'errored')\n .map((n) => (\n
\n {wrapNodeWithCallbacks(n)(classes[n.status], styles)}\n
\n ))}\n \n );\n}\n"]}