Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 32x 32x 32x 32x 37x 37x 37x 37x 19x 19x 25x 19x 19x 21x 19x 6x 6x 6x 6x 10x 16x 18x 17x 17x 3x 17x 16x 16x 37x | import { invariant } from "hey-listen" import { VisualElement } from "../render/types" import { animateVisualElement, stopAnimation } from "../render/utils/animation" import { setValues } from "../render/utils/setters" import { AnimationControls, PendingAnimations } from "./types" /** * @public */ export function animationControls(): AnimationControls { /** * Track whether the host component has mounted. */ let hasMounted = false /** * Pending animations that are started before a component is mounted. * TODO: Remove this as animations should only run in effects */ const pendingAnimations: PendingAnimations[] = [] /** * A collection of linked component animation controls. */ const subscribers = new Set<VisualElement>() const controls: AnimationControls = { subscribe(visualElement) { subscribers.add(visualElement) return () => void subscribers.delete(visualElement) }, start(definition, transitionOverride) { /** * TODO: We only perform this hasMounted check because in Framer we used to * encourage the ability to start an animation within the render phase. This * isn't behaviour concurrent-safe so when we make Framer concurrent-safe * we can ditch this. */ if (hasMounted) { const animations: Array<Promise<any>> = [] subscribers.forEach((visualElement) => { animations.push( animateVisualElement(visualElement, definition, { transitionOverride, }) ) }) return Promise.all(animations) } else { return new Promise<void>((resolve) => { pendingAnimations.push({ animation: [definition, transitionOverride], resolve, }) }) } }, set(definition) { invariant( hasMounted, "controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook." ) return subscribers.forEach((visualElement) => { setValues(visualElement, definition) }) }, stop() { subscribers.forEach((visualElement) => { stopAnimation(visualElement) }) }, mount() { hasMounted = true pendingAnimations.forEach(({ animation, resolve }) => { controls.start(...animation).then(resolve) }) return () => { hasMounted = false controls.stop() } }, } return controls } |