{"version":3,"file":"effects.mjs","sources":["../../../../src/animation/animate/effects.ts"],"sourcesContent":["import { invariant, removeItem } from \"motion-utils\"\nimport { AnimateEffect } from \"../../effects/utils/create-effect\"\nimport { frame } from \"../../frameloop\"\nimport { positionalKeys } from \"../../render/utils/keys-position\"\nimport { MotionValue, motionValue } from \"../../value\"\nimport { animateMotionValue } from \"../interfaces/motion-value\"\nimport { AnimationElement } from \"../keyframes/types\"\nimport {\n    AnimationPlaybackControlsWithThen,\n    AnyResolvedKeyframe,\n    UnresolvedValueKeyframe,\n    ValueTransition,\n} from \"../types\"\n\n/**\n * Effects registered via `animate.addEffect()`, most recent first.\n */\nconst effects: AnimateEffect<any>[] = []\n\nexport function addEffect(effect: AnimateEffect<any>): void {\n    invariant(\n        typeof effect.test === \"function\" && typeof effect.read === \"function\",\n        \"Effects passed to animate.addEffect() need test() and read().\",\n        \"effect-missing-test\"\n    )\n\n    removeEffect(effect)\n    effects.unshift(effect)\n}\n\nexport function removeEffect(effect: AnimateEffect<any>): void {\n    removeItem(effects, effect)\n}\n\nexport function findEffect(subject: unknown): AnimateEffect | undefined {\n    return effects.find((effect) => effect.test(subject))\n}\n\nexport interface EffectKeyframes {\n    [key: string]:\n        | UnresolvedValueKeyframe\n        | UnresolvedValueKeyframe[]\n        | Record<string, unknown>\n        | undefined\n    transition?: Record<string, unknown>\n    transitionEnd?: Record<string, AnyResolvedKeyframe>\n}\n\n/**\n * Effect subjects can expose any key, so per-key transition overrides\n * are keyed by arbitrary strings.\n */\nexport type EffectTransition = ValueTransition & {\n    reduceMotion?: boolean\n    skipAnimations?: boolean\n} & Record<string, unknown>\n\n/**\n * Animate each key in `keyframes` on the motion value `getValue` returns\n * for it. `element` is what the keyframe resolver uses to read, render\n * and measure the subject when the effect defers resolution to it.\n */\nexport function animateValues(\n    getValue: (key: string) => MotionValue,\n    keyframes: EffectKeyframes,\n    transition: EffectTransition = {},\n    element?: AnimationElement\n): AnimationPlaybackControlsWithThen[] {\n    const animations: AnimationPlaybackControlsWithThen[] = []\n    const { velocity, path } = transition\n    const reduceMotion = transition.reduceMotion ?? element?.shouldReduceMotion\n\n    /**\n     * Only elements have x/y to move along a path. path claims them by\n     * deleting them, so hand it a copy.\n     */\n    if (path?.animateValues && element) {\n        keyframes = { ...keyframes }\n        path.animateValues(getValue, keyframes, transition, 0, animations)\n    }\n\n    for (const key in keyframes) {\n        if (key === \"transition\" || key === \"transitionEnd\") continue\n\n        const target = keyframes[key]\n        if (target === undefined) continue\n\n        const value = getValue(key)\n\n        /**\n         * If the value is already at the defined target, skip the animation.\n         * We still re-assert the value via frame.update to take precedence\n         * over any stale transitionEnd callbacks from previous animations.\n         */\n        const current = value.get()\n        if (\n            current !== undefined &&\n            !value.isAnimating() &&\n            !Array.isArray(target) &&\n            target === current &&\n            !velocity\n        ) {\n            frame.update(() => value.set(target))\n            continue\n        }\n\n        value.start(\n            animateMotionValue(\n                key,\n                value,\n                target as any,\n                reduceMotion && positionalKeys.has(key)\n                    ? { type: false }\n                    : transition,\n                element\n            )\n        )\n\n        value.animation &&\n            animations.push(\n                value.animation as AnimationPlaybackControlsWithThen\n            )\n    }\n\n    const { transitionEnd } = keyframes\n    if (transitionEnd) {\n        const applyTransitionEnd = () =>\n            frame.update(() => {\n                for (const key in transitionEnd) {\n                    getValue(key).set(transitionEnd[key])\n                }\n            })\n\n        animations.length\n            ? Promise.all(animations).then(applyTransitionEnd)\n            : applyTransitionEnd()\n    }\n\n    return animations\n}\n\n/**\n * Animate the keys of `subject` via `effect`. Motion values are created on\n * first animation and bound to the subject through the effect for the\n * rest of its life.\n *\n * Without `element`, a new value is seeded synchronously from the first\n * keyframe or `effect.read()`. With it, the value starts undefined and the\n * keyframe resolver reads the subject (batched, with unit conversion by\n * measurement) via `element`.\n */\nexport function animateEffectSubject<Subject extends object>(\n    effect: AnimateEffect<Subject>,\n    subject: Subject,\n    keyframes: EffectKeyframes,\n    transition?: EffectTransition,\n    element?: AnimationElement\n): AnimationPlaybackControlsWithThen[] {\n    return animateValues(\n        (key) => {\n            let value = effect.get(subject, key)\n\n            if (!value) {\n                let initial: AnyResolvedKeyframe | undefined\n\n                if (!element) {\n                    const target = keyframes[key] as\n                        | UnresolvedValueKeyframe\n                        | UnresolvedValueKeyframe[]\n                    initial =\n                        firstKeyframe(target) ??\n                        effect.read(subject, key, target)\n\n                    invariant(\n                        initial !== undefined,\n                        `\"${key}\" can't be read from the animated subject. Provide [from, to] keyframes.`,\n                        \"effect-unreadable-value\"\n                    )\n                }\n\n                value = motionValue(initial, { owner: element })\n                effect(subject, { [key]: value })\n            }\n\n            return value\n        },\n        keyframes,\n        transition,\n        element\n    )\n}\n\nfunction firstKeyframe(\n    target: UnresolvedValueKeyframe | UnresolvedValueKeyframe[] | undefined\n) {\n    const first = Array.isArray(target) ? target[0] : undefined\n    return first === null ? undefined : first\n}\n"],"names":[],"mappings":"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"}