@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 19.7 kB
Source Map (JSON)
{"version":3,"file":"useFlipTransition.mjs","names":[],"sources":["../../../src/Image/viewer/useFlipTransition.ts"],"sourcesContent":["import type { MotionValue } from 'motion/react';\nimport { animate, motionValue } from 'motion/react';\nimport { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';\n\nimport type { Rect } from './geometry';\n\nexport const OPEN_SPRING = { bounce: 0.15, type: 'spring' as const, visualDuration: 0.3 };\n// bounce: 0 — a full-viewport push with overshoot would visibly slide past\n// the resting position and snap back.\nconst PUSH_SPRING = { bounce: 0, type: 'spring' as const, visualDuration: 0.3 };\nconst FADE = { duration: 0.15, ease: 'easeOut' as const };\nconst CHROME_FADE = { delay: 0.15, duration: 0.2, ease: 'easeOut' as const };\nconst FADE_SCALE = 0.92;\nconst SWITCH_FADE_SCALE = 0.96;\nconst SETTLE_FALLBACK_MS = 1000;\n\ninterface Animation {\n stop: () => void;\n}\n\nexport interface FlipTransformValues {\n flipX: MotionValue<boolean>;\n flipY: MotionValue<boolean>;\n rotate: MotionValue<number>;\n scale: MotionValue<number>;\n x: MotionValue<number>;\n y: MotionValue<number>;\n}\n\nexport interface UseFlipTransitionOptions {\n animated: boolean;\n getCloseSource: () => HTMLImageElement;\n getFitRect: () => Rect;\n getInitialScale: () => number;\n getViewportWidth: () => number;\n onClosed: () => void;\n source: HTMLImageElement;\n transform: FlipTransformValues;\n}\n\nexport interface CloseTransitionOptions {\n fade?: boolean;\n}\n\nexport interface UseFlipTransitionResult {\n backdropRef: (node: HTMLElement | null) => void;\n chromeRef: (node: HTMLElement | null) => void;\n close: (options?: CloseTransitionOptions) => void;\n imageRef: (node: HTMLImageElement | null) => void;\n isClosing: () => boolean;\n isTransitioning: () => boolean;\n switchTo: (apply: () => void, direction?: 1 | -1) => void;\n}\n\nconst measureSource = (element: HTMLImageElement): DOMRect | null => {\n if (!element.isConnected) return null;\n const rect = element.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return null;\n if (rect.bottom <= 0 || rect.right <= 0) return null;\n if (rect.top >= window.innerHeight || rect.left >= window.innerWidth) return null;\n return rect;\n};\n\nconst sourceTransform = (rect: DOMRect, fit: Rect) => ({\n scale:\n fit.width > 0 && fit.height > 0\n ? Math.max(rect.width / fit.width, rect.height / fit.height)\n : 1,\n x: rect.left + rect.width / 2 - (fit.x + fit.width / 2),\n y: rect.top + rect.height / 2 - (fit.y + fit.height / 2),\n});\n\nconst readTransform = (transform: FlipTransformValues) =>\n [\n `translate3d(${transform.x.get()}px, ${transform.y.get()}px, 0)`,\n `scale(${transform.scale.get()})`,\n `rotate(${transform.rotate.get()}deg)`,\n `scaleX(${transform.flipX.get() ? -1 : 1})`,\n `scaleY(${transform.flipY.get() ? -1 : 1})`,\n ].join(' ');\n\nconst useBoundNode = <T extends HTMLElement>(apply: (node: T) => void) => {\n const nodeRef = useRef<T | null>(null);\n const applyRef = useRef(apply);\n applyRef.current = apply;\n\n const setNode = useCallback((node: T | null) => {\n nodeRef.current = node;\n if (node) applyRef.current(node);\n }, []);\n\n const refresh = useCallback(() => {\n const node = nodeRef.current;\n if (node) applyRef.current(node);\n }, []);\n\n const getNode = useCallback(() => nodeRef.current, []);\n\n return useMemo(() => ({ getNode, refresh, setNode }), [getNode, refresh, setNode]);\n};\n\nexport const useFlipTransition = ({\n animated,\n getCloseSource,\n getFitRect,\n getInitialScale,\n getViewportWidth,\n onClosed,\n source,\n transform,\n}: UseFlipTransitionOptions): UseFlipTransitionResult => {\n const [opacity] = useState(() => ({\n backdrop: motionValue(0),\n chrome: motionValue(0),\n image: motionValue(animated ? 1 : 0),\n }));\n\n const image = useBoundNode<HTMLImageElement>(\n useCallback(\n (node) => {\n node.style.transform = readTransform(transform);\n node.style.opacity = String(opacity.image.get());\n },\n [opacity, transform],\n ),\n );\n\n const backdrop = useBoundNode<HTMLElement>(\n useCallback(\n (node) => {\n node.style.opacity = String(opacity.backdrop.get());\n },\n [opacity],\n ),\n );\n\n const chrome = useBoundNode<HTMLElement>(\n useCallback(\n (node) => {\n node.style.opacity = String(opacity.chrome.get());\n },\n [opacity],\n ),\n );\n\n const runningRef = useRef<Animation[]>([]);\n const closingRef = useRef(false);\n const transitioningRef = useRef(true);\n\n const onClosedRef = useRef(onClosed);\n onClosedRef.current = onClosed;\n\n const getFitRectRef = useRef(getFitRect);\n getFitRectRef.current = getFitRect;\n\n const getCloseSourceRef = useRef(getCloseSource);\n getCloseSourceRef.current = getCloseSource;\n\n const getInitialScaleRef = useRef(getInitialScale);\n getInitialScaleRef.current = getInitialScale;\n\n const getViewportWidthRef = useRef(getViewportWidth);\n getViewportWidthRef.current = getViewportWidth;\n\n const ghostRef = useRef<HTMLImageElement | null>(null);\n const removeGhost = useCallback(() => {\n ghostRef.current?.remove();\n ghostRef.current = null;\n }, []);\n\n const run = useCallback((animations: Animation[]) => {\n runningRef.current = [...runningRef.current, ...animations];\n }, []);\n\n const stopAll = useCallback(() => {\n for (const animation of runningRef.current) animation.stop();\n runningRef.current = [];\n }, []);\n\n const isTransitioning = useCallback(() => transitioningRef.current, []);\n const isClosing = useCallback(() => closingRef.current, []);\n\n // stopAll() only stops tracked Animation objects; a bare window.setTimeout\n // has no way to be cancelled by it. Track a fallback timer the same way, so\n // a later stopAll() (a new open/close/switch superseding an interrupted one)\n // clears the old timer along with the animations it was backing — otherwise\n // it can fire mid-way through the new phase and flip transitioningRef false\n // while something else is legitimately still in flight.\n const trackTimeout = useCallback(\n (callback: () => void, ms: number) => {\n const id = window.setTimeout(callback, ms);\n run([{ stop: () => window.clearTimeout(id) }]);\n },\n [run],\n );\n\n // A future animate() call on one of these shared motion values (e.g. a refit\n // triggered by a natural-size change) silently cancels whichever animation is\n // already running on it — motion's animate() stops the prior one without ever\n // firing its onComplete. Track completion by count for the common case, but\n // always back it with a fallback timer so onSettled fires exactly once no\n // matter what: a cancelled axis can never leave this permanently unfired.\n const animateSettling = useCallback(\n (axes: [MotionValue<number>, number][], onSettled: () => void) => {\n let pending = axes.length;\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n onSettled();\n };\n const onAxisComplete = () => {\n pending -= 1;\n if (pending === 0) finish();\n };\n run(\n axes.map(([value, target]) =>\n animate(value, target, { ...OPEN_SPRING, onComplete: onAxisComplete }),\n ),\n );\n trackTimeout(finish, SETTLE_FALLBACK_MS);\n },\n [run, trackTimeout],\n );\n\n useLayoutEffect(() => {\n const unsubscribes = [\n ...[\n transform.flipX,\n transform.flipY,\n transform.rotate,\n transform.scale,\n transform.x,\n transform.y,\n opacity.image,\n ].map((value) => value.on('change', image.refresh)),\n opacity.backdrop.on('change', backdrop.refresh),\n opacity.chrome.on('change', chrome.refresh),\n ];\n\n return () => {\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n }, [backdrop, chrome, image, opacity, transform]);\n\n useLayoutEffect(() => {\n const rect = animated ? measureSource(source) : null;\n transitioningRef.current = true;\n const markSettled = () => {\n transitioningRef.current = false;\n };\n\n // Resting scale is whatever defaultZoom resolved to, not necessarily fit.\n const resting = getInitialScaleRef.current();\n\n if (rect) {\n const start = sourceTransform(rect, getFitRectRef.current());\n transform.scale.set(start.scale);\n transform.x.set(start.x);\n transform.y.set(start.y);\n opacity.image.set(1);\n animateSettling(\n [\n [transform.scale, resting],\n [transform.x, 0],\n [transform.y, 0],\n ],\n markSettled,\n );\n } else {\n opacity.image.set(0);\n if (animated) transform.scale.set(resting * FADE_SCALE);\n run([animate(opacity.image, 1, { ...FADE, onComplete: markSettled })]);\n if (animated) run([animate(transform.scale, resting, FADE)]);\n trackTimeout(markSettled, SETTLE_FALLBACK_MS);\n }\n\n run([animate(opacity.backdrop, 1, FADE), animate(opacity.chrome, 1, CHROME_FADE)]);\n\n return () => {\n stopAll();\n removeGhost();\n };\n }, [\n animateSettling,\n animated,\n opacity,\n removeGhost,\n run,\n source,\n stopAll,\n trackTimeout,\n transform,\n ]);\n\n const close = useCallback(\n (options?: CloseTransitionOptions) => {\n if (closingRef.current) return;\n closingRef.current = true;\n transitioningRef.current = true;\n stopAll();\n removeGhost();\n\n let finished = false;\n const finish = () => {\n if (finished) return;\n finished = true;\n transitioningRef.current = false;\n onClosedRef.current();\n };\n const rect = animated && !options?.fade ? measureSource(getCloseSourceRef.current()) : null;\n\n run([animate(opacity.backdrop, 0, FADE), animate(opacity.chrome, 0, FADE)]);\n\n if (rect) {\n const target = sourceTransform(rect, getFitRectRef.current());\n animateSettling(\n [\n [transform.x, target.x],\n [transform.y, target.y],\n [transform.scale, target.scale],\n ],\n finish,\n );\n return;\n }\n\n if (animated) run([animate(transform.scale, transform.scale.get() * FADE_SCALE, FADE)]);\n run([animate(opacity.image, 0, { ...FADE, onComplete: finish })]);\n trackTimeout(finish, SETTLE_FALLBACK_MS);\n },\n [animateSettling, animated, opacity, run, stopAll, trackTimeout, transform],\n );\n\n const switchTo = useCallback(\n (apply: () => void, direction?: 1 | -1) => {\n if (closingRef.current) return;\n stopAll();\n removeGhost();\n transitioningRef.current = true;\n\n const markSettled = () => {\n transitioningRef.current = false;\n };\n\n const node = image.getNode();\n const width = getViewportWidthRef.current();\n\n if (animated && direction && node && width > 0) {\n // The clone snapshots the outgoing visual state wholesale — src,\n // fitRect positioning and the current zoom/rotate/flip transform —\n // so the live <img> stays the single element every other system\n // (gestures, FLIP close, refit) keeps operating on.\n const ghost = node.cloneNode() as HTMLImageElement;\n ghost.dataset.ghost = 'true';\n ghost.setAttribute('aria-hidden', 'true');\n ghost.style.pointerEvents = 'none';\n const base = ghost.style.transform;\n node.parentElement?.insertBefore(ghost, node);\n ghostRef.current = ghost;\n\n const progress = motionValue(0);\n const unsubscribe = progress.on('change', (p) => {\n ghost.style.transform = `translateX(${-direction * width * p}px) ${base}`;\n });\n const finishGhost = () => {\n unsubscribe();\n if (ghostRef.current === ghost) removeGhost();\n else ghost.remove();\n };\n\n apply();\n transform.x.jump(direction * width);\n\n run([\n animate(progress, 1, { ...PUSH_SPRING, onComplete: finishGhost }),\n animate(transform.x, 0, { ...PUSH_SPRING, onComplete: markSettled }),\n { stop: finishGhost },\n ]);\n trackTimeout(() => {\n finishGhost();\n markSettled();\n }, SETTLE_FALLBACK_MS);\n return;\n }\n\n const tasks: Animation[] = [];\n if (animated) tasks.push(animate(transform.scale, SWITCH_FADE_SCALE, FADE));\n tasks.push(\n animate(opacity.image, 0, {\n ...FADE,\n onComplete: () => {\n apply();\n run([animate(opacity.image, 1, { ...FADE, onComplete: markSettled })]);\n },\n }),\n );\n run(tasks);\n trackTimeout(markSettled, SETTLE_FALLBACK_MS);\n },\n [animated, image, opacity, removeGhost, run, stopAll, trackTimeout, transform],\n );\n\n return {\n backdropRef: backdrop.setNode,\n chromeRef: chrome.setNode,\n close,\n imageRef: image.setNode,\n isClosing,\n isTransitioning,\n switchTo,\n };\n};\n"],"mappings":"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"}