| import { getAnimationData } from './data.js'; | ||
| import { isCssVar, registerCssVariable } from './utils/css-var.js'; | ||
| import { noop } from '../../utils/noop.js'; | ||
| import { ms } from './utils/time.js'; | ||
| import { isTransform, transformAlias, addTransformToElement, asTransformCssVar, transformPropertyDefinitions } from './utils/transforms.js'; | ||
| import { stopAnimation } from './utils/stop-animation.js'; | ||
| import { isEasingList, convertEasing } from './utils/easing.js'; | ||
| import { supports } from './utils/feature-detection.js'; | ||
| import { createCssVariableRenderer, createStyleRenderer } from './utils/apply.js'; | ||
| import { animateNumber } from '../js/animate-number.js'; | ||
| function animateStyle(element, name, keyframes, options = {}) { | ||
| let { duration = 0.3, delay = 0, endDelay = 0, repeat = 0, easing = "ease", direction, offset, } = options; | ||
| const data = getAnimationData(element); | ||
| let canAnimateNatively = supports.waapi(); | ||
| let render = noop; | ||
| const valueIsTransform = isTransform(name); | ||
| keyframes = Array.isArray(keyframes) ? keyframes : [keyframes]; | ||
| /** | ||
| * If this is an individual transform, we need to map its | ||
| * key to a CSS variable and update the element's transform style | ||
| */ | ||
| if (valueIsTransform) { | ||
| if (transformAlias[name]) | ||
| name = transformAlias[name]; | ||
| addTransformToElement(element, name); | ||
| name = asTransformCssVar(name); | ||
| } | ||
| stopCurrentAnimation(data, name); | ||
| /** | ||
| * Check if this is an animation pregenerator and generate keyframes | ||
| * if so. | ||
| */ | ||
| // if (isAnimationGenerator(easing)) { | ||
| // const generatedAnimation = easing.generate(keyframes) | ||
| // easing = "linear" | ||
| // if (generatedAnimation !== false) { | ||
| // keyframes = generatedAnimation.keyframes | ||
| // duration = generatedAnimation.duration | ||
| // } | ||
| // } | ||
| /** | ||
| * Get definition of value, this will be used to convert numerical | ||
| * keyframes into the default value type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(name); | ||
| /** | ||
| * If this is a CSS variable we need to register it with the browser | ||
| * before it can be animated natively. We also set it with setProperty | ||
| * rather than directly onto the element.style object. | ||
| */ | ||
| if (isCssVar(name)) { | ||
| render = createCssVariableRenderer(element, name); | ||
| if (supports.cssRegisterProperty()) { | ||
| registerCssVariable(name); | ||
| } | ||
| else { | ||
| canAnimateNatively = false; | ||
| } | ||
| } | ||
| else { | ||
| render = createStyleRenderer(element, name); | ||
| } | ||
| /** | ||
| * If we can animate this value with WAAPI, do so. Currently this only | ||
| * feature detects CSS.registerProperty but could check WAAPI too. | ||
| */ | ||
| if (canAnimateNatively) { | ||
| /** | ||
| * Convert numbers to default value types. Currently this only supports | ||
| * transforms but it could also support other value types. | ||
| */ | ||
| if (definition) { | ||
| keyframes = keyframes.map((value) => typeof value === "number" ? definition.toDefaultUnit(value) : value); | ||
| } | ||
| if (!supports.partialKeyframes() && keyframes.length === 1) { | ||
| const initialKeyframe = isCssVar(name) | ||
| ? element.style.getPropertyValue(name) | ||
| : getComputedStyle(element)[name]; | ||
| keyframes.unshift(initialKeyframe); | ||
| } | ||
| const animationOptions = { | ||
| delay: ms(delay), | ||
| duration: ms(duration), | ||
| endDelay: ms(endDelay), | ||
| easing: !isEasingList(easing) ? convertEasing(easing) : undefined, | ||
| direction, | ||
| iterations: repeat + 1, | ||
| }; | ||
| const animation = element.animate({ | ||
| [name]: keyframes, | ||
| offset, | ||
| easing: isEasingList(easing) ? easing.map(convertEasing) : undefined, | ||
| }, animationOptions); | ||
| data.activeAnimations[name] = animation; | ||
| /** | ||
| * Polyfill finished Promise in browsers that don't support it | ||
| */ | ||
| if (!animation.finished) { | ||
| animation.finished = new Promise((resolve, reject) => { | ||
| animation.onfinish = resolve; | ||
| animation.oncancel = reject; | ||
| }); | ||
| } | ||
| const target = keyframes[keyframes.length - 1]; | ||
| animation.finished.then(() => render(target)).catch(noop); | ||
| return animation; | ||
| } | ||
| else if (valueIsTransform && keyframes.every(isNumber)) { | ||
| if (definition) { | ||
| const applyStyle = render; | ||
| render = (v) => applyStyle(definition.toDefaultUnit(v)); | ||
| } | ||
| return animateNumber(render, keyframes, options); | ||
| } | ||
| else { | ||
| const target = keyframes[keyframes.length - 1]; | ||
| render(definition && typeof target === "number" | ||
| ? definition.toDefaultUnit(target) | ||
| : target); | ||
| } | ||
| } | ||
| function stopCurrentAnimation(data, name) { | ||
| if (data.activeAnimations[name]) { | ||
| stopAnimation(data.activeAnimations[name]); | ||
| data.activeAnimations[name] = undefined; | ||
| } | ||
| } | ||
| const isNumber = (value) => typeof value === "number"; | ||
| export { animateStyle }; |
| import { AnimationData, getAnimationData } from "./data" | ||
| import { AnimationOptions, AnimationWithCommitStyles } from "./types" | ||
| import { isCssVar, registerCssVariable } from "./utils/css-var" | ||
| import { noop } from "../../utils/noop" | ||
| import { ms } from "./utils/time" | ||
| import { | ||
| addTransformToElement, | ||
| asTransformCssVar, | ||
| isTransform, | ||
| transformAlias, | ||
| transformPropertyDefinitions, | ||
| } from "./utils/transforms" | ||
| import { stopAnimation } from "./utils/stop-animation" | ||
| import { convertEasing, isEasingList } from "./utils/easing" | ||
| import { supports } from "./utils/feature-detection" | ||
| import { createCssVariableRenderer, createStyleRenderer } from "./utils/apply" | ||
| import { animateNumber } from "../js/animate-number" | ||
| export function animateStyle( | ||
| element: Element, | ||
| name: string, | ||
| keyframes: string | number | Array<string | number>, | ||
| options: AnimationOptions = {} | ||
| ) { | ||
| let { | ||
| duration = 0.3, | ||
| delay = 0, | ||
| endDelay = 0, | ||
| repeat = 0, | ||
| easing = "ease", | ||
| direction, | ||
| offset, | ||
| } = options | ||
| const data = getAnimationData(element) | ||
| let canAnimateNatively = supports.waapi() | ||
| let render: (v: any) => void = noop | ||
| const valueIsTransform = isTransform(name) | ||
| keyframes = Array.isArray(keyframes) ? keyframes : [keyframes] | ||
| /** | ||
| * If this is an individual transform, we need to map its | ||
| * key to a CSS variable and update the element's transform style | ||
| */ | ||
| if (valueIsTransform) { | ||
| if (transformAlias[name]) name = transformAlias[name] | ||
| addTransformToElement(element as HTMLElement, name) | ||
| name = asTransformCssVar(name) | ||
| } | ||
| stopCurrentAnimation(data, name) | ||
| /** | ||
| * Check if this is an animation pregenerator and generate keyframes | ||
| * if so. | ||
| */ | ||
| // if (isAnimationGenerator(easing)) { | ||
| // const generatedAnimation = easing.generate(keyframes) | ||
| // easing = "linear" | ||
| // if (generatedAnimation !== false) { | ||
| // keyframes = generatedAnimation.keyframes | ||
| // duration = generatedAnimation.duration | ||
| // } | ||
| // } | ||
| /** | ||
| * Get definition of value, this will be used to convert numerical | ||
| * keyframes into the default value type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(name) | ||
| /** | ||
| * If this is a CSS variable we need to register it with the browser | ||
| * before it can be animated natively. We also set it with setProperty | ||
| * rather than directly onto the element.style object. | ||
| */ | ||
| if (isCssVar(name)) { | ||
| render = createCssVariableRenderer(element, name) | ||
| if (supports.cssRegisterProperty()) { | ||
| registerCssVariable(name) | ||
| } else { | ||
| canAnimateNatively = false | ||
| } | ||
| } else { | ||
| render = createStyleRenderer(element, name) | ||
| } | ||
| /** | ||
| * If we can animate this value with WAAPI, do so. Currently this only | ||
| * feature detects CSS.registerProperty but could check WAAPI too. | ||
| */ | ||
| if (canAnimateNatively) { | ||
| /** | ||
| * Convert numbers to default value types. Currently this only supports | ||
| * transforms but it could also support other value types. | ||
| */ | ||
| if (definition) { | ||
| keyframes = keyframes.map((value) => | ||
| typeof value === "number" ? definition.toDefaultUnit!(value) : value | ||
| ) | ||
| } | ||
| if (!supports.partialKeyframes() && keyframes.length === 1) { | ||
| const initialKeyframe = isCssVar(name) | ||
| ? (element as HTMLElement).style.getPropertyValue(name) | ||
| : getComputedStyle(element)[name] | ||
| keyframes.unshift(initialKeyframe) | ||
| } | ||
| const animationOptions = { | ||
| delay: ms(delay), | ||
| duration: ms(duration), | ||
| endDelay: ms(endDelay), | ||
| easing: !isEasingList(easing) ? convertEasing(easing) : undefined, | ||
| direction, | ||
| iterations: repeat + 1, | ||
| } | ||
| const animation = element.animate( | ||
| { | ||
| [name]: keyframes, | ||
| offset, | ||
| easing: isEasingList(easing) ? easing.map(convertEasing) : undefined, | ||
| } as PropertyIndexedKeyframes, | ||
| animationOptions | ||
| ) as AnimationWithCommitStyles | ||
| data.activeAnimations[name] = animation | ||
| /** | ||
| * Polyfill finished Promise in browsers that don't support it | ||
| */ | ||
| if (!animation.finished) { | ||
| ;(animation as any).finished = new Promise((resolve, reject) => { | ||
| animation.onfinish = resolve | ||
| animation.oncancel = reject | ||
| }) | ||
| } | ||
| const target = keyframes[keyframes.length - 1] | ||
| animation.finished.then(() => render(target)).catch(noop) | ||
| return animation | ||
| } else if (valueIsTransform && keyframes.every(isNumber)) { | ||
| if (definition) { | ||
| const applyStyle = render | ||
| render = (v: number) => applyStyle(definition.toDefaultUnit(v)) | ||
| } | ||
| return animateNumber(render, keyframes, options) | ||
| } else { | ||
| const target = keyframes[keyframes.length - 1] | ||
| render( | ||
| definition && typeof target === "number" | ||
| ? definition.toDefaultUnit(target) | ||
| : target | ||
| ) | ||
| } | ||
| } | ||
| function stopCurrentAnimation(data: AnimationData, name: string) { | ||
| if (data.activeAnimations[name]) { | ||
| stopAnimation(data.activeAnimations[name]!) | ||
| data.activeAnimations[name] = undefined | ||
| } | ||
| } | ||
| const isNumber = (value: string | number): value is number => | ||
| typeof value === "number" |
| import { | ||
| pointerDown, | ||
| pointerUp, | ||
| pointerEnter, | ||
| pointerLeave, | ||
| render, | ||
| } from "../../../../jest.setup" | ||
| import "../../dom/__tests__/web-animations.min-edited" | ||
| import * as React from "react" | ||
| import { animated } from "../index" | ||
| console.error = jest.fn() | ||
| const duration = 0.001 | ||
| describe("Poses", () => { | ||
| test("Components will animate from initial -> style on mount", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("child")).toHaveStyle("transform: scale(2)") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="hidden" | ||
| style="visible" | ||
| poses={{ | ||
| hidden: { opacity: 0 }, | ||
| visible: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| hidden: { transform: "none" }, | ||
| visible: { transform: "scale(2)" }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| hidden: { transform: "none" }, | ||
| visible: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Poses accept options", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("child")).toHaveStyle("transform: scale(2)") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="hidden" | ||
| style="visible" | ||
| poses={{ | ||
| hidden: { opacity: 0 }, | ||
| visible: { opacity: 1, options: { duration } }, | ||
| }} | ||
| options={{ duration: 100 }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| hidden: { transform: "none" }, | ||
| visible: { transform: "scale(2)", options: { duration } }, | ||
| }} | ||
| options={{ duration: 100 }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| hidden: { transform: "none" }, | ||
| visible: { transform: "scale(0.5)", options: { duration } }, | ||
| }} | ||
| options={{ duration: 100 }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate when the contents of the style variant changes", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("opacity: 1") | ||
| resolve(true) | ||
| } | ||
| const Component = ({ opacity }: { opacity: number }) => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| poses={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| a: { opacity: 0.75 }, | ||
| b: { opacity }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component opacity={0.5} />) | ||
| rerender(<Component opacity={1} />) | ||
| rerender(<Component opacity={1} />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate when the name of the style variant changes", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 0.5") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = ({ style }: { style: string }) => ( | ||
| <animated.div | ||
| initial="a" | ||
| style={style} | ||
| poses={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component style="b" />) | ||
| rerender(<Component style="c" />) | ||
| rerender(<Component style="c" />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate to hover variant when hover starts", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 0.5") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| hover="c" | ||
| poses={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerEnter(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate from hover variant when hover end", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle( | ||
| "opacity: 1; transform: scale(1)" | ||
| ) | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 0.75") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: none") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| hover="c" | ||
| poses={{ | ||
| a: { opacity: 0, transform: "scale(1)" }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5, transform: "scale(2)" }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerEnter(getByTestId("parent") as Element) | ||
| pointerLeave(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 100) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate to press variant when press starts", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 0.5") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| press="c" | ||
| poses={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerDown(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate from press variant when press end", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle( | ||
| "opacity: 1; transform: scale(1)" | ||
| ) | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 0.75") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: none") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| press="c" | ||
| poses={{ | ||
| a: { opacity: 0, transform: "scale(1)" }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5, transform: "scale(2)" }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| poses={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| poses={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerDown(getByTestId("parent") as Element) | ||
| pointerUp(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| }) |
| import { MotionKeyframesWithOptions, Poses } from "../types" | ||
| export function resolvePose( | ||
| definition?: MotionKeyframesWithOptions | string, | ||
| inheritedDefinition?: string, | ||
| poses: Poses = {} | ||
| ): MotionKeyframesWithOptions | undefined { | ||
| if (definition) { | ||
| return typeof definition === "string" ? poses[definition] : definition | ||
| } else if (inheritedDefinition) { | ||
| return poses[inheritedDefinition] | ||
| } | ||
| } |
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { getOptions } from "../../dom/utils/options" | ||
| import { MotionKeyframesWithOptions } from "../types" | ||
| export function updateTargetAndOptions( | ||
| target: MotionKeyframes, | ||
| options: AnimationOptionsWithOverrides, | ||
| toApply?: MotionKeyframesWithOptions | ||
| ) { | ||
| if (!toApply) return | ||
| for (const key in toApply) { | ||
| if (key === "options") continue | ||
| target[key] = toApply[key] | ||
| if (toApply.options) { | ||
| options[key] = getOptions(toApply.options, key) | ||
| } | ||
| } | ||
| } |
| import { AnimationOptions, AnimationWithCommitStyles } from "./types"; | ||
| export declare function animateStyle(element: Element, name: string, keyframes: string | number | Array<string | number>, options?: AnimationOptions): AnimationWithCommitStyles | import("../js/animate-number").Animation | undefined; |
| import { MotionKeyframesWithOptions, Poses } from "../types"; | ||
| export declare function resolvePose(definition?: MotionKeyframesWithOptions | string, inheritedDefinition?: string, poses?: Poses): MotionKeyframesWithOptions | undefined; |
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { MotionKeyframesWithOptions } from "../types"; | ||
| export declare function updateTargetAndOptions(target: MotionKeyframes, options: AnimationOptionsWithOverrides, toApply?: MotionKeyframesWithOptions): void; |
+1
-2
| export { animate } from './targets/dom/animate.js'; | ||
| export { animateValue } from './targets/dom/animate-value.js'; | ||
| export { animated } from './targets/react/index.js'; | ||
| export { animateStyle } from './targets/dom/animate-style.js'; |
| import { __rest } from 'tslib'; | ||
| import { stopAnimation } from './utils/stop-animation.js'; | ||
| import { animateValue } from './animate-value.js'; | ||
| import { animateStyle } from './animate-style.js'; | ||
| import { getOptions } from './utils/options.js'; | ||
@@ -18,3 +18,3 @@ | ||
| } | ||
| const animation = animateValue(element, key, keyframes[key], valueOptions); | ||
| const animation = animateStyle(element, key, keyframes[key], valueOptions); | ||
| animation && animations.push(animation); | ||
@@ -21,0 +21,0 @@ } |
+3
-305
@@ -7,27 +7,3 @@ 'use strict'; | ||
| var popmotion = require('popmotion'); | ||
| var React = require('react'); | ||
| var framerMotion = require('framer-motion'); | ||
| function _interopNamespace(e) { | ||
| if (e && e.__esModule) return e; | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { | ||
| return e[k]; | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| n['default'] = e; | ||
| return Object.freeze(n); | ||
| } | ||
| var React__namespace = /*#__PURE__*/_interopNamespace(React); | ||
| function stopAnimation(animation) { | ||
@@ -422,3 +398,3 @@ animation.commitStyles(); | ||
| function animateValue(element, name, keyframes, options = {}) { | ||
| function animateStyle(element, name, keyframes, options = {}) { | ||
| let { duration = 0.3, delay = 0, endDelay = 0, repeat = 0, easing = "ease", direction, offset, } = options; | ||
@@ -556,3 +532,3 @@ const data = getAnimationData(element); | ||
| } | ||
| const animation = animateValue(element, key, keyframes[key], valueOptions); | ||
| const animation = animateStyle(element, key, keyframes[key], valueOptions); | ||
| animation && animations.push(animation); | ||
@@ -610,281 +586,3 @@ } | ||
| function hasChanged(a, b) { | ||
| if (typeof a !== typeof b) | ||
| return true; | ||
| if (Array.isArray(a) && Array.isArray(b)) | ||
| return !shallowCompare(a, b); | ||
| return a !== b; | ||
| } | ||
| function shallowCompare(next, prev) { | ||
| const prevLength = prev.length; | ||
| if (prevLength !== next.length) | ||
| return false; | ||
| for (let i = 0; i < prevLength; i++) { | ||
| if (prev[i] !== next[i]) | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| function useAnimation(ref, initial, target, options, onStart, onComplete) { | ||
| const prevTarget = React.useRef(initial); | ||
| React.useEffect(() => { | ||
| const targetKeyframe = {}; | ||
| const allKeys = new Set([ | ||
| ...Object.keys(target), | ||
| ...Object.keys(prevTarget.current), | ||
| ]); | ||
| allKeys.forEach((key) => { | ||
| let next = target[key]; | ||
| if (!hasChanged(next, prevTarget.current[key])) | ||
| return; | ||
| /** | ||
| * TODO: If next is undefined, throw error or record a "base value" | ||
| * to animate back down to | ||
| */ | ||
| targetKeyframe[key] = next; | ||
| }); | ||
| if (Object.keys(targetKeyframe).length && ref.current) { | ||
| onStart === null || onStart === void 0 ? void 0 : onStart(targetKeyframe); | ||
| const animations = []; | ||
| for (const key in targetKeyframe) { | ||
| const animation = animateValue(ref.current, key, targetKeyframe[key], options); | ||
| animation && animations.push(animation); | ||
| } | ||
| Promise.all(animations.map((animation) => animation.finished)) | ||
| .then(() => onComplete === null || onComplete === void 0 ? void 0 : onComplete(targetKeyframe)) | ||
| .catch(noop); | ||
| } | ||
| prevTarget.current = target; | ||
| }); | ||
| } | ||
| function resolveVariant(definition, inheritedDefinition, variants = {}) { | ||
| if (definition) { | ||
| return typeof definition === "string" ? variants[definition] : definition; | ||
| } | ||
| else if (inheritedDefinition) { | ||
| return variants[inheritedDefinition]; | ||
| } | ||
| } | ||
| function useGestureState(target, stylesToApply, inheritedVariant, variants) { | ||
| const [isGestureActive, setGestureState] = React.useState(false); | ||
| if (isGestureActive || inheritedVariant) { | ||
| Object.assign(target, resolveVariant(stylesToApply, inheritedVariant, variants)); | ||
| } | ||
| return [isGestureActive || Boolean(inheritedVariant), setGestureState]; | ||
| } | ||
| function useHover(target, { hover, onPointerEnter, onPointerLeave, variants, } = {}, { hover: inheritedHover }, isVariantActive) { | ||
| const [isHoverActive, setHoverState] = useGestureState(target, hover, inheritedHover, variants); | ||
| isVariantActive.hover = isHoverActive; | ||
| return hover | ||
| ? { | ||
| onPointerEnter: (e) => { | ||
| onPointerEnter === null || onPointerEnter === void 0 ? void 0 : onPointerEnter(e); | ||
| setHoverState(true); | ||
| }, | ||
| onPointerLeave: (e) => { | ||
| onPointerLeave === null || onPointerLeave === void 0 ? void 0 : onPointerLeave(e); | ||
| setHoverState(false); | ||
| }, | ||
| } | ||
| : {}; | ||
| } | ||
| function usePress(target, { press, onPointerDown, variants } = {}, { press: inheritedPress }, isVariantActive) { | ||
| const [isPressActive, setPressState] = useGestureState(target, press, inheritedPress, variants); | ||
| isVariantActive.press = isPressActive; | ||
| if (!press) | ||
| return {}; | ||
| const onPointerUp = () => { | ||
| setPressState(false); | ||
| window.removeEventListener("pointerup", onPointerUp); | ||
| }; | ||
| return { | ||
| onPointerDown: (e) => { | ||
| onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(e); | ||
| setPressState(true); | ||
| window.addEventListener("pointerup", onPointerUp); | ||
| }, | ||
| }; | ||
| } | ||
| function useExit(target, { exit, variants }, { exit: inheritedExit }) { | ||
| const [isPresent, onExitComplete] = framerMotion.usePresence(); | ||
| /** | ||
| * In case we don't have an exit animation defined we still need to | ||
| * call onExitComplete if it exits so AnimatePresence knows it | ||
| * can remove this component. | ||
| */ | ||
| React.useEffect(() => { | ||
| if (!exit) | ||
| onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete(); | ||
| }, [isPresent]); | ||
| if (exit && !isPresent) { | ||
| Object.assign(target, resolveVariant(exit, inheritedExit, variants)); | ||
| return onExitComplete; | ||
| } | ||
| } | ||
| function useViewport(ref, target, { inViewport, variants, viewport = {}, onViewportEnter, onViewportLeave, }, { inViewport: inheritedInViewport }, isVariantActive) { | ||
| const { root, margin: rootMargin, once, threshold } = viewport; | ||
| const [isInViewport, setViewportState] = useGestureState(target, inViewport, inheritedInViewport, variants); | ||
| isVariantActive.inViewport = isInViewport; | ||
| let shouldObserve = !!inViewport || !!onViewportEnter || !!onViewportLeave; | ||
| if (once && isInViewport) | ||
| shouldObserve = false; | ||
| React.useEffect(() => { | ||
| if (!shouldObserve || typeof IntersectionObserver === "undefined") | ||
| return; | ||
| const observer = new IntersectionObserver(([entry]) => { | ||
| setViewportState(entry.isIntersecting); | ||
| const callback = entry.isIntersecting | ||
| ? onViewportEnter | ||
| : onViewportLeave; | ||
| callback && callback(entry); | ||
| }, { root: root === null || root === void 0 ? void 0 : root.current, rootMargin, threshold }); | ||
| observer.observe(ref.current); | ||
| return () => observer.disconnect(); | ||
| }, [ | ||
| inViewport, | ||
| onViewportEnter, | ||
| onViewportLeave, | ||
| root, | ||
| rootMargin, | ||
| threshold, | ||
| ]); | ||
| } | ||
| function convertKeyframesToStyles(keyframes) { | ||
| const initialKeyframes = {}; | ||
| const transformKeys = []; | ||
| for (let key in keyframes) { | ||
| const value = keyframes[key]; | ||
| if (isTransform(key)) { | ||
| if (transformAlias[key]) | ||
| key = transformAlias[key]; | ||
| transformKeys.push(key); | ||
| key = asTransformCssVar(key); | ||
| } | ||
| let initialKeyframe = Array.isArray(value) ? value[0] : value; | ||
| /** | ||
| * If this is a number and we have a default value type, convert the number | ||
| * to this type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(key); | ||
| if (definition) { | ||
| initialKeyframe = | ||
| typeof value === "number" ? definition.toDefaultUnit(value) : value; | ||
| } | ||
| initialKeyframes[key] = initialKeyframe; | ||
| } | ||
| if (transformKeys.length) { | ||
| initialKeyframes.transform = buildTransformTemplate(transformKeys); | ||
| } | ||
| return initialKeyframes; | ||
| } | ||
| const AnimationContext = React.createContext({}); | ||
| function createAnimatedComponent(Component) { | ||
| function Animated(props, _externalRef) { | ||
| // TODO: Support externalRef if provided | ||
| const ref = React.useRef(null); | ||
| const { options = {}, style, initial, hover, press, exit, inViewport, viewport, variants, onStart, onComplete, inherit = true } = props, forwardProps = tslib.__rest(props | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| , ["options", "style", "initial", "hover", "press", "exit", "inViewport", "viewport", "variants", "onStart", "onComplete", "inherit"]); | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| const isVariantActive = { initial: true, style: true }; | ||
| /** | ||
| * Inherit variants from the parent context, | ||
| */ | ||
| let inherited = React.useContext(AnimationContext); | ||
| if (!inherit) | ||
| inherited = {}; | ||
| const resolvedStyle = resolveVariant(style, inherited.style, variants); | ||
| const resolvedInitial = resolveVariant(initial, inherited.initial, variants); | ||
| const initialTarget = Object.assign(Object.assign({}, resolvedStyle), resolvedInitial); | ||
| const target = Object.assign(Object.assign({}, resolvedInitial), resolvedStyle); | ||
| /** | ||
| * If we haven't created a style prop for SSR yet (this is the initial render) | ||
| * make one. We provide this to React every render as beyond that with manage style | ||
| * via animations. | ||
| */ | ||
| const styleProp = React.useRef(null); | ||
| styleProp.current || (styleProp.current = convertKeyframesToStyles(initialTarget)); | ||
| /** | ||
| * Attach animation event handlers (gestures/exit/viewport appearance). | ||
| * This are called in reverse order of which styles should take priority when | ||
| * active, for example if there's a hover and press gesture active the press | ||
| * gesture will take precedence. | ||
| */ | ||
| const hoverProps = useHover(target, props, inherited, isVariantActive); | ||
| const pressProps = usePress(target, props, inherited, isVariantActive); | ||
| useViewport(ref, target, props, inherited, isVariantActive); | ||
| const onExitComplete = useExit(target, props, inherited); | ||
| /** | ||
| * Compare our final calculated style target with the one from the previous render | ||
| * and trigger any necessary animations. | ||
| */ | ||
| useAnimation(ref, initialTarget, target, options, onStart, (animation) => { | ||
| onComplete && onComplete(animation); | ||
| onExitComplete && onExitComplete(); | ||
| }); | ||
| const element = React.createElement(Component, Object.assign({}, forwardProps, hoverProps, pressProps, { | ||
| style: styleProp.current, | ||
| ref, | ||
| })); | ||
| /** | ||
| * Create a variant context to pass forward to child components. | ||
| */ | ||
| const context = variantProps.reduce((acc, key) => { | ||
| acc[key] = undefined; | ||
| if (props[key]) { | ||
| if (typeof props[key] === "string" && isVariantActive[key]) { | ||
| acc[key] = props[key]; | ||
| } | ||
| } | ||
| else if (inherited[key]) { | ||
| acc[key] = inherited[key]; | ||
| } | ||
| return acc; | ||
| }, {}); | ||
| /** | ||
| * Memoize the context so we only trigger a re-render in children if the values | ||
| * within it change. | ||
| */ | ||
| const memoizedContext = React.useMemo(() => context, Object.values(context)); | ||
| return (React__namespace.createElement(AnimationContext.Provider, { value: memoizedContext }, element)); | ||
| } | ||
| return React.forwardRef(Animated); | ||
| } | ||
| const variantProps = [ | ||
| "initial", | ||
| "style", | ||
| "hover", | ||
| "press", | ||
| "inViewport", | ||
| "exit", | ||
| ]; | ||
| const components = new Map(); | ||
| const animated = new Proxy({}, { | ||
| get: (_, key) => { | ||
| if (!components.has(key)) { | ||
| components.set(key, createAnimatedComponent(key)); | ||
| } | ||
| return components.get(key); | ||
| }, | ||
| }); | ||
| exports.animate = animate; | ||
| exports.animateValue = animateValue; | ||
| exports.animated = animated; | ||
| exports.animateStyle = animateStyle; |
@@ -1,1 +0,1 @@ | ||
| !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Motion={},t.React)}(this,(function(t,e){"use strict";function n(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}})),e.default=t,Object.freeze(e)}var r=n(e);function i(t,e){var n={};for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.indexOf(r)<0&&(n[r]=t[r]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(r=Object.getOwnPropertySymbols(t);i<r.length;i++)e.indexOf(r[i])<0&&Object.prototype.propertyIsEnumerable.call(t,r[i])&&(n[r[i]]=t[r[i]])}return n}function s(t){t.commitStyles();try{t.cancel()}catch(t){}}const a=new WeakMap;function o(t){return a.has(t)||a.set(t,{activeTransforms:[],activeAnimations:{}}),a.get(t)}const c=()=>{},u=t=>t,l=["","X","Y","Z"],f={x:"translateX",y:"translateY",z:"translateZ"},h={syntax:"<angle>",initialValue:"0deg",toDefaultUnit:t=>t+"deg"},p={translate:{syntax:"<length-percentage>",initialValue:"0px",toDefaultUnit:t=>t+"px"},rotate:h,scale:{syntax:"<number>",initialValue:1,toDefaultUnit:u},skew:h},y=new Map,m=t=>`--motion-${t}`,d=["x","y","z"];["translate","scale","rotate","skew"].forEach((t=>{l.forEach((e=>{d.push(t+e),y.set(m(t+e),p[t])}))}));const v=(t,e)=>d.indexOf(t)-d.indexOf(e),g=new Set(d),b=t=>g.has(t),w=t=>t.sort(v).reduce(O,"").trim(),O=(t,e)=>`${t} ${e}(var(${m(e)}))`,x=t=>t.startsWith("--"),j=new Set;const P=t=>1e3*t,T=t=>Array.isArray(t)&&"number"!=typeof t[0],S=t=>(t=>Array.isArray(t)&&"number"==typeof t[0])(t)?A(t):t,A=([t,e,n,r])=>`cubic-bezier(${t}, ${e}, ${n}, ${r})`,E=t=>document.createElement("div").animate(t,{duration:.001}),M={cssRegisterProperty:()=>"undefined"!=typeof CSS&&Object.hasOwnProperty.call(CSS,"registerProperty"),waapi:()=>Object.hasOwnProperty.call(Element.prototype,"animate"),partialKeyframes:()=>{try{E({opacity:[1]})}catch(t){return!1}return!0},finished:()=>Boolean(E({opacity:[0,1]}).finished)},k={},V=Object.keys(M).reduce(((t,e)=>(t[e]=()=>(void 0===k[e]&&(k[e]=M[e]()),k[e]),t)),{}),D=(t,e,n)=>(((1-3*n+3*e)*t+(3*n-6*e))*t+3*e)*t;function R(t,e,n,r){if(t===e&&n===r)return u;const i=e=>function(t,e,n,r,i){let s,a,o=0;do{a=e+(n-e)/2,s=D(a,r,i)-t,s>0?n=a:e=a}while(Math.abs(s)>1e-7&&++o<12);return a}(e,0,1,t,n);return t=>0===t||1===t?t:D(i(t),e,r)}var C=function(t,e,n){var r=e-t;return 0===r?1:(n-t)/r},$=function(t,e,n){return-n*t+n*e+t},U=function(t,e){return void 0===e&&(e="end"),function(n){var r,i,s,a=(n="end"===e?Math.min(n,.999):Math.max(n,.001))*t,o="end"===e?Math.floor(a):Math.ceil(a);return r=0,i=1,s=o/t,Math.min(Math.max(s,r),i)}};const I={ease:R(.25,.1,.25,1),"ease-in":R(.42,0,1,1),"ease-in-out":R(.42,0,.58,1),"ease-out":R(0,0,.58,1)},L=/\((.*?)\)/;function q(t){if("function"==typeof t)return t;if(Array.isArray(t))return R(...t);if(I[t])return I[t];if(t.startsWith("steps")){const e=L.exec(t);if(e){const t=e[1].split(",");return U(parseFloat(t[0]),t[1].trim())}}return u}function z(t,e){const n=t[t.length-1];for(let r=1;r<=e;r++){const i=C(0,e,r);t.push($(n,1,i))}}function _(t,e=function(t){const e=[0];return z(e,t-1),e}(t.length),n=u){const r=t.length,i=r-e.length;return i>0&&z(e,i),i=>{let s=0;for(;s<r-2&&!(i<e[s+1]);s++);let a=(o=C(e[s],e[s+1],i),Math.min(1,Math.max(o,0)));var o,c,u,l;if(Array.isArray(n)){const t=(c=0,u=n.length-1,((s-c)%(l=u-c)+l)%l+c);a=n[t](a)}else a=n(a);return $(t[s],t[s+1],a)}}class F{constructor(t,e,{easing:n="ease",duration:r=.3,delay:i=0,endDelay:s=0,offset:a,repeat:o=0,direction:c="normal"}){this.startTime=0,this.rate=1,this.t=0,this.cancelT=0,this.playState="idle",this.finished=new Promise(((t,e)=>{this.resolve=t,this.reject=e}));const u=r*(o+1),l=_(e,a,T(n)?n.map(q):q(n));this.tick=e=>{if("finished"===this.playState){const e=l(1);return t(e),void this.resolve(e)}let n=this.pauseTime?this.pauseTime:(e-this.startTime)*this.rate;this.t=n,n/=1e3,n=Math.max(n-i,0);const a=n/r;let o=Math.floor(a),f=a%1;!f&&a>=1&&(f=1),1===f&&o--;const h=o%2;("reverse"===c||"alternate"===c&&h||"alternate-reverse"===c&&!h)&&(f=1-f);const p=n>=u?1:Math.min(f,1),y=l(p);t(y);n>=u+s?(this.playState="finished",this.resolve(y)):"idle"!==this.playState&&requestAnimationFrame(this.tick)},this.play()}play(){const t=performance.now();this.playState="running",this.pauseTime?this.startTime=t-(this.pauseTime-this.startTime):this.startTime||(this.startTime=t),this.pauseTime=void 0,requestAnimationFrame(this.tick)}pause(){this.playState="paused",this.pauseTime=performance.now()}finish(){this.playState="finished",this.tick(0)}cancel(){this.playState="idle",this.tick(this.cancelT),this.reject(!1)}reverse(){this.rate*=-1}commitStyles(){this.cancelT=this.t}get currentTime(){return this.currentTime}set currentTime(t){this.pauseTime||0===this.rate?this.pauseTime=P(t):this.startTime=performance.now()-P(t)/this.rate}get playbackRate(){return this.rate}set playbackRate(t){this.rate=t}}function W(t,e,n,r={}){let{duration:i=.3,delay:a=0,endDelay:u=0,repeat:l=0,easing:h="ease",direction:p,offset:d}=r;const v=o(t);let g=V.waapi(),O=c;const A=b(e);n=Array.isArray(n)?n:[n],A&&(f[e]&&(e=f[e]),((t,e)=>{const{activeTransforms:n}=o(t);var r,i;i=e,-1===(r=n).indexOf(i)&&r.push(i),t.style.transform=w(n)})(t,e),e=m(e)),function(t,e){t.activeAnimations[e]&&(s(t.activeAnimations[e]),t.activeAnimations[e]=void 0)}(v,e);const E=y.get(e);if(x(e)?(O=((t,e)=>n=>t.style.setProperty(e,n))(t,e),V.cssRegisterProperty()?function(t){if(!j.has(t)){j.add(t);try{const{syntax:e,initialValue:n}=y.has(t)?y.get(t):{};CSS.registerProperty({name:t,inherits:!1,syntax:e,initialValue:n})}catch(t){}}}(e):g=!1):O=((t,e)=>n=>t.style[e]=n)(t,e),g){if(E&&(n=n.map((t=>"number"==typeof t?E.toDefaultUnit(t):t))),!V.partialKeyframes()&&1===n.length){const r=x(e)?t.style.getPropertyValue(e):getComputedStyle(t)[e];n.unshift(r)}const r={delay:P(a),duration:P(i),endDelay:P(u),easing:T(h)?void 0:S(h),direction:p,iterations:l+1},s=t.animate({[e]:n,offset:d,easing:T(h)?h.map(S):void 0},r);v.activeAnimations[e]=s,s.finished||(s.finished=new Promise(((t,e)=>{s.onfinish=t,s.oncancel=e})));const o=n[n.length-1];return s.finished.then((()=>O(o))).catch(c),s}if(A&&n.every(B)){if(E){const t=O;O=e=>t(E.toDefaultUnit(e))}return function(t,e=[0,1],n={}){return new F(t,e,n)}(O,n,r)}{const t=n[n.length-1];O(E&&"number"==typeof t?E.toDefaultUnit(t):t)}}const B=t=>"number"==typeof t,K=(t,e)=>t[e]?Object.assign(Object.assign({},t),t[e]):t;const X={get:(t,e)=>{var n,r;switch(e){case"finished":return t.finished;case"currentTime":const i=(null===(n=t.animations[0])||void 0===n?void 0:n[e])||0;return i?i/1e3:0;case"playbackRate":return null===(r=t.animations[0])||void 0===r?void 0:r[e];case"stop":return()=>t.animations.forEach(s);default:return()=>t.animations.forEach((t=>t[e]()))}},set:(t,e,n)=>{switch(e){case"currentTime":n*=1e3;case"currentTime":case"playbackRate":for(let r=0;r<t.animations.length;r++)t.animations[r][e]=n;return!0}return!1}};function Y(t,n,r,i,s,a){const o=e.useRef(n);e.useEffect((()=>{const e={};if(new Set([...Object.keys(r),...Object.keys(o.current)]).forEach((t=>{let n=r[t];var i,s;(i=n,s=o.current[t],typeof i==typeof s&&(Array.isArray(i)&&Array.isArray(s)?function(t,e){const n=e.length;if(n!==t.length)return!1;for(let r=0;r<n;r++)if(e[r]!==t[r])return!1;return!0}(i,s):i===s))||(e[t]=n)})),Object.keys(e).length&&t.current){null==s||s(e);const n=[];for(const r in e){const s=W(t.current,r,e[r],i);s&&n.push(s)}Promise.all(n.map((t=>t.finished))).then((()=>null==a?void 0:a(e))).catch(c)}o.current=r}))}function Z(t,e,n={}){return t?"string"==typeof t?n[t]:t:e?n[e]:void 0}function G(t,n,r,i){const[s,a]=e.useState(!1);return(s||r)&&Object.assign(t,Z(n,r,i)),[s||Boolean(r),a]}var H=e.createContext(null);var J=0,N=function(){return J++},Q=function(){return t=N,null===(n=e.useRef(null)).current&&(n.current=t()),n.current;var t,n};function tt(t,{exit:n,variants:r},{exit:i}){const[s,a]=function(){var t=e.useContext(H);if(null===t)return[!0,null];var n=t.isPresent,r=t.onExitComplete,i=t.register,s=Q();return e.useEffect((function(){return i(s)}),[]),!n&&r?[!1,function(){return null==r?void 0:r(s)}]:[!0]}();if(e.useEffect((()=>{n||null==a||a()}),[s]),n&&!s)return Object.assign(t,Z(n,i,r)),a}const et=e.createContext({});function nt(t){return e.forwardRef((function(n,s){const a=e.useRef(null),{options:o={},style:c,initial:u,hover:l,press:h,exit:p,inViewport:d,viewport:v,variants:g,onStart:O,onComplete:x,inherit:j=!0}=n,P=i(n,["options","style","initial","hover","press","exit","inViewport","viewport","variants","onStart","onComplete","inherit"]),T={initial:!0,style:!0};let S=e.useContext(et);j||(S={});const A=Z(c,S.style,g),E=Z(u,S.initial,g),M=Object.assign(Object.assign({},A),E),k=Object.assign(Object.assign({},E),A),V=e.useRef(null);V.current||(V.current=function(t){const e={},n=[];for(let r in t){const i=t[r];b(r)&&(f[r]&&(r=f[r]),n.push(r),r=m(r));let s=Array.isArray(i)?i[0]:i;const a=y.get(r);a&&(s="number"==typeof i?a.toDefaultUnit(i):i),e[r]=s}return n.length&&(e.transform=w(n)),e}(M));const D=function(t,{hover:e,onPointerEnter:n,onPointerLeave:r,variants:i}={},{hover:s},a){const[o,c]=G(t,e,s,i);return a.hover=o,e?{onPointerEnter:t=>{null==n||n(t),c(!0)},onPointerLeave:t=>{null==r||r(t),c(!1)}}:{}}(k,n,S,T),R=function(t,{press:e,onPointerDown:n,variants:r}={},{press:i},s){const[a,o]=G(t,e,i,r);if(s.press=a,!e)return{};const c=()=>{o(!1),window.removeEventListener("pointerup",c)};return{onPointerDown:t=>{null==n||n(t),o(!0),window.addEventListener("pointerup",c)}}}(k,n,S,T);!function(t,n,{inViewport:r,variants:i,viewport:s={},onViewportEnter:a,onViewportLeave:o},{inViewport:c},u){const{root:l,margin:f,once:h,threshold:p}=s,[y,m]=G(n,r,c,i);u.inViewport=y;let d=!!r||!!a||!!o;h&&y&&(d=!1),e.useEffect((()=>{if(!d||"undefined"==typeof IntersectionObserver)return;const e=new IntersectionObserver((([t])=>{m(t.isIntersecting);const e=t.isIntersecting?a:o;e&&e(t)}),{root:null==l?void 0:l.current,rootMargin:f,threshold:p});return e.observe(t.current),()=>e.disconnect()}),[r,a,o,l,f,p])}(a,k,n,S,T);const C=tt(k,n,S);Y(a,M,k,o,O,(t=>{x&&x(t),C&&C()}));const $=e.createElement(t,Object.assign({},P,D,R,{style:V.current,ref:a})),U=rt.reduce(((t,e)=>(t[e]=void 0,n[e]?"string"==typeof n[e]&&T[e]&&(t[e]=n[e]):S[e]&&(t[e]=S[e]),t)),{}),I=e.useMemo((()=>U),Object.values(U));return r.createElement(et.Provider,{value:I},$)}))}const rt=["initial","style","hover","press","inViewport","exit"],it=new Map,st=new Proxy({},{get:(t,e)=>(it.has(e)||it.set(e,nt(e)),it.get(e))});t.animate=function(t,e,n){var{stagger:r=0}=n,s=i(n,["stagger"]);t=function(t){"string"==typeof t?t=document.querySelectorAll(t):t instanceof Element&&(t=[t]);return Array.from(t)}(t);const a=[];for(let n=0;n<t.length;n++){const i=t[n];for(const t in e){const o=K(s,t);r&&(o.delay||(o.delay=0),o.delay+=r*n);const c=W(i,t,e[t],o);c&&a.push(c)}}const o={animations:a,finished:Promise.all(a.map((t=>t.finished)))};return new Proxy(o,X)},t.animateValue=W,t.animated=st,Object.defineProperty(t,"__esModule",{value:!0})})); | ||
| !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Motion={})}(this,(function(t){"use strict";function e(t){t.commitStyles();try{t.cancel()}catch(t){}}const n=new WeakMap;function i(t){return n.has(t)||n.set(t,{activeTransforms:[],activeAnimations:{}}),n.get(t)}const a=()=>{},r=t=>t,s=["","X","Y","Z"],o={x:"translateX",y:"translateY",z:"translateZ"},c={syntax:"<angle>",initialValue:"0deg",toDefaultUnit:t=>t+"deg"},l={translate:{syntax:"<length-percentage>",initialValue:"0px",toDefaultUnit:t=>t+"px"},rotate:c,scale:{syntax:"<number>",initialValue:1,toDefaultUnit:r},skew:c},u=new Map,h=t=>`--motion-${t}`,f=["x","y","z"];["translate","scale","rotate","skew"].forEach((t=>{s.forEach((e=>{f.push(t+e),u.set(h(t+e),l[t])}))}));const m=(t,e)=>f.indexOf(t)-f.indexOf(e),y=new Set(f),p=t=>t.sort(m).reduce(d,"").trim(),d=(t,e)=>`${t} ${e}(var(${h(e)}))`,g=t=>t.startsWith("--"),v=new Set;const b=t=>1e3*t,T=t=>Array.isArray(t)&&"number"!=typeof t[0],w=t=>(t=>Array.isArray(t)&&"number"==typeof t[0])(t)?x(t):t,x=([t,e,n,i])=>`cubic-bezier(${t}, ${e}, ${n}, ${i})`,S=t=>document.createElement("div").animate(t,{duration:.001}),O={cssRegisterProperty:()=>"undefined"!=typeof CSS&&Object.hasOwnProperty.call(CSS,"registerProperty"),waapi:()=>Object.hasOwnProperty.call(Element.prototype,"animate"),partialKeyframes:()=>{try{S({opacity:[1]})}catch(t){return!1}return!0},finished:()=>Boolean(S({opacity:[0,1]}).finished)},A={},M=Object.keys(O).reduce(((t,e)=>(t[e]=()=>(void 0===A[e]&&(A[e]=O[e]()),A[e]),t)),{}),P=(t,e,n)=>(((1-3*n+3*e)*t+(3*n-6*e))*t+3*e)*t;function j(t,e,n,i){if(t===e&&n===i)return r;const a=e=>function(t,e,n,i,a){let r,s,o=0;do{s=e+(n-e)/2,r=P(s,i,a)-t,r>0?n=s:e=s}while(Math.abs(r)>1e-7&&++o<12);return s}(e,0,1,t,n);return t=>0===t||1===t?t:P(a(t),e,i)}var k=function(t,e,n){var i=e-t;return 0===i?1:(n-t)/i},D=function(t,e,n){return-n*t+n*e+t},E=function(t,e){return void 0===e&&(e="end"),function(n){var i,a,r,s=(n="end"===e?Math.min(n,.999):Math.max(n,.001))*t,o="end"===e?Math.floor(s):Math.ceil(s);return i=0,a=1,r=o/t,Math.min(Math.max(r,i),a)}};const $={ease:j(.25,.1,.25,1),"ease-in":j(.42,0,1,1),"ease-in-out":j(.42,0,.58,1),"ease-out":j(0,0,.58,1)},R=/\((.*?)\)/;function U(t){if("function"==typeof t)return t;if(Array.isArray(t))return j(...t);if($[t])return $[t];if(t.startsWith("steps")){const e=R.exec(t);if(e){const t=e[1].split(",");return E(parseFloat(t[0]),t[1].trim())}}return r}function V(t,e){const n=t[t.length-1];for(let i=1;i<=e;i++){const a=k(0,e,i);t.push(D(n,1,a))}}function C(t,e=function(t){const e=[0];return V(e,t-1),e}(t.length),n=r){const i=t.length,a=i-e.length;return a>0&&V(e,a),a=>{let r=0;for(;r<i-2&&!(a<e[r+1]);r++);let s=(o=k(e[r],e[r+1],a),Math.min(1,Math.max(o,0)));var o,c,l,u;if(Array.isArray(n)){const t=(c=0,l=n.length-1,((r-c)%(u=l-c)+u)%u+c);s=n[t](s)}else s=n(s);return D(t[r],t[r+1],s)}}class q{constructor(t,e,{easing:n="ease",duration:i=.3,delay:a=0,endDelay:r=0,offset:s,repeat:o=0,direction:c="normal"}){this.startTime=0,this.rate=1,this.t=0,this.cancelT=0,this.playState="idle",this.finished=new Promise(((t,e)=>{this.resolve=t,this.reject=e}));const l=i*(o+1),u=C(e,s,T(n)?n.map(U):U(n));this.tick=e=>{if("finished"===this.playState){const e=u(1);return t(e),void this.resolve(e)}let n=this.pauseTime?this.pauseTime:(e-this.startTime)*this.rate;this.t=n,n/=1e3,n=Math.max(n-a,0);const s=n/i;let o=Math.floor(s),h=s%1;!h&&s>=1&&(h=1),1===h&&o--;const f=o%2;("reverse"===c||"alternate"===c&&f||"alternate-reverse"===c&&!f)&&(h=1-h);const m=n>=l?1:Math.min(h,1),y=u(m);t(y);n>=l+r?(this.playState="finished",this.resolve(y)):"idle"!==this.playState&&requestAnimationFrame(this.tick)},this.play()}play(){const t=performance.now();this.playState="running",this.pauseTime?this.startTime=t-(this.pauseTime-this.startTime):this.startTime||(this.startTime=t),this.pauseTime=void 0,requestAnimationFrame(this.tick)}pause(){this.playState="paused",this.pauseTime=performance.now()}finish(){this.playState="finished",this.tick(0)}cancel(){this.playState="idle",this.tick(this.cancelT),this.reject(!1)}reverse(){this.rate*=-1}commitStyles(){this.cancelT=this.t}get currentTime(){return this.currentTime}set currentTime(t){this.pauseTime||0===this.rate?this.pauseTime=b(t):this.startTime=performance.now()-b(t)/this.rate}get playbackRate(){return this.rate}set playbackRate(t){this.rate=t}}function z(t,n,r,s={}){let{duration:c=.3,delay:l=0,endDelay:f=0,repeat:m=0,easing:d="ease",direction:x,offset:S}=s;const O=i(t);let A=M.waapi(),P=a;const j=(t=>y.has(t))(n);r=Array.isArray(r)?r:[r],j&&(o[n]&&(n=o[n]),((t,e)=>{const{activeTransforms:n}=i(t);var a,r;r=e,-1===(a=n).indexOf(r)&&a.push(r),t.style.transform=p(n)})(t,n),n=h(n)),function(t,n){t.activeAnimations[n]&&(e(t.activeAnimations[n]),t.activeAnimations[n]=void 0)}(O,n);const k=u.get(n);if(g(n)?(P=((t,e)=>n=>t.style.setProperty(e,n))(t,n),M.cssRegisterProperty()?function(t){if(!v.has(t)){v.add(t);try{const{syntax:e,initialValue:n}=u.has(t)?u.get(t):{};CSS.registerProperty({name:t,inherits:!1,syntax:e,initialValue:n})}catch(t){}}}(n):A=!1):P=((t,e)=>n=>t.style[e]=n)(t,n),A){if(k&&(r=r.map((t=>"number"==typeof t?k.toDefaultUnit(t):t))),!M.partialKeyframes()&&1===r.length){const e=g(n)?t.style.getPropertyValue(n):getComputedStyle(t)[n];r.unshift(e)}const e={delay:b(l),duration:b(c),endDelay:b(f),easing:T(d)?void 0:w(d),direction:x,iterations:m+1},i=t.animate({[n]:r,offset:S,easing:T(d)?d.map(w):void 0},e);O.activeAnimations[n]=i,i.finished||(i.finished=new Promise(((t,e)=>{i.onfinish=t,i.oncancel=e})));const s=r[r.length-1];return i.finished.then((()=>P(s))).catch(a),i}if(j&&r.every(F)){if(k){const t=P;P=e=>t(k.toDefaultUnit(e))}return function(t,e=[0,1],n={}){return new q(t,e,n)}(P,r,s)}{const t=r[r.length-1];P(k&&"number"==typeof t?k.toDefaultUnit(t):t)}}const F=t=>"number"==typeof t,W=(t,e)=>t[e]?Object.assign(Object.assign({},t),t[e]):t;const K={get:(t,n)=>{var i,a;switch(n){case"finished":return t.finished;case"currentTime":const r=(null===(i=t.animations[0])||void 0===i?void 0:i[n])||0;return r?r/1e3:0;case"playbackRate":return null===(a=t.animations[0])||void 0===a?void 0:a[n];case"stop":return()=>t.animations.forEach(e);default:return()=>t.animations.forEach((t=>t[n]()))}},set:(t,e,n)=>{switch(e){case"currentTime":n*=1e3;case"currentTime":case"playbackRate":for(let i=0;i<t.animations.length;i++)t.animations[i][e]=n;return!0}return!1}};t.animate=function(t,e,n){var{stagger:i=0}=n,a=function(t,e){var n={};for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&e.indexOf(i)<0&&(n[i]=t[i]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var a=0;for(i=Object.getOwnPropertySymbols(t);a<i.length;a++)e.indexOf(i[a])<0&&Object.prototype.propertyIsEnumerable.call(t,i[a])&&(n[i[a]]=t[i[a]])}return n}(n,["stagger"]);t=function(t){"string"==typeof t?t=document.querySelectorAll(t):t instanceof Element&&(t=[t]);return Array.from(t)}(t);const r=[];for(let n=0;n<t.length;n++){const s=t[n];for(const t in e){const o=W(a,t);i&&(o.delay||(o.delay=0),o.delay+=i*n);const c=z(s,t,e[t],o);c&&r.push(c)}}const s={animations:r,finished:Promise.all(r.map((t=>t.finished)))};return new Proxy(s,K)},t.animateStyle=z,Object.defineProperty(t,"__esModule",{value:!0})})); |
+7
-367
| (function (global, factory) { | ||
| typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : | ||
| typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : | ||
| (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Motion = {}, global.React)); | ||
| }(this, (function (exports, React) { 'use strict'; | ||
| typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
| typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
| (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Motion = {})); | ||
| }(this, (function (exports) { 'use strict'; | ||
| function _interopNamespace(e) { | ||
| if (e && e.__esModule) return e; | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { | ||
| return e[k]; | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| n['default'] = e; | ||
| return Object.freeze(n); | ||
| } | ||
| var React__namespace = /*#__PURE__*/_interopNamespace(React); | ||
| /*! ***************************************************************************** | ||
@@ -474,3 +452,3 @@ Copyright (c) Microsoft Corporation. | ||
| function animateValue(element, name, keyframes, options = {}) { | ||
| function animateStyle(element, name, keyframes, options = {}) { | ||
| let { duration = 0.3, delay = 0, endDelay = 0, repeat = 0, easing = "ease", direction, offset, } = options; | ||
@@ -608,3 +586,3 @@ const data = getAnimationData(element); | ||
| } | ||
| const animation = animateValue(element, key, keyframes[key], valueOptions); | ||
| const animation = animateStyle(element, key, keyframes[key], valueOptions); | ||
| animation && animations.push(animation); | ||
@@ -662,342 +640,4 @@ } | ||
| function hasChanged(a, b) { | ||
| if (typeof a !== typeof b) | ||
| return true; | ||
| if (Array.isArray(a) && Array.isArray(b)) | ||
| return !shallowCompare(a, b); | ||
| return a !== b; | ||
| } | ||
| function shallowCompare(next, prev) { | ||
| const prevLength = prev.length; | ||
| if (prevLength !== next.length) | ||
| return false; | ||
| for (let i = 0; i < prevLength; i++) { | ||
| if (prev[i] !== next[i]) | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| function useAnimation(ref, initial, target, options, onStart, onComplete) { | ||
| const prevTarget = React.useRef(initial); | ||
| React.useEffect(() => { | ||
| const targetKeyframe = {}; | ||
| const allKeys = new Set([ | ||
| ...Object.keys(target), | ||
| ...Object.keys(prevTarget.current), | ||
| ]); | ||
| allKeys.forEach((key) => { | ||
| let next = target[key]; | ||
| if (!hasChanged(next, prevTarget.current[key])) | ||
| return; | ||
| /** | ||
| * TODO: If next is undefined, throw error or record a "base value" | ||
| * to animate back down to | ||
| */ | ||
| targetKeyframe[key] = next; | ||
| }); | ||
| if (Object.keys(targetKeyframe).length && ref.current) { | ||
| onStart === null || onStart === void 0 ? void 0 : onStart(targetKeyframe); | ||
| const animations = []; | ||
| for (const key in targetKeyframe) { | ||
| const animation = animateValue(ref.current, key, targetKeyframe[key], options); | ||
| animation && animations.push(animation); | ||
| } | ||
| Promise.all(animations.map((animation) => animation.finished)) | ||
| .then(() => onComplete === null || onComplete === void 0 ? void 0 : onComplete(targetKeyframe)) | ||
| .catch(noop); | ||
| } | ||
| prevTarget.current = target; | ||
| }); | ||
| } | ||
| function resolveVariant(definition, inheritedDefinition, variants = {}) { | ||
| if (definition) { | ||
| return typeof definition === "string" ? variants[definition] : definition; | ||
| } | ||
| else if (inheritedDefinition) { | ||
| return variants[inheritedDefinition]; | ||
| } | ||
| } | ||
| function useGestureState(target, stylesToApply, inheritedVariant, variants) { | ||
| const [isGestureActive, setGestureState] = React.useState(false); | ||
| if (isGestureActive || inheritedVariant) { | ||
| Object.assign(target, resolveVariant(stylesToApply, inheritedVariant, variants)); | ||
| } | ||
| return [isGestureActive || Boolean(inheritedVariant), setGestureState]; | ||
| } | ||
| function useHover(target, { hover, onPointerEnter, onPointerLeave, variants, } = {}, { hover: inheritedHover }, isVariantActive) { | ||
| const [isHoverActive, setHoverState] = useGestureState(target, hover, inheritedHover, variants); | ||
| isVariantActive.hover = isHoverActive; | ||
| return hover | ||
| ? { | ||
| onPointerEnter: (e) => { | ||
| onPointerEnter === null || onPointerEnter === void 0 ? void 0 : onPointerEnter(e); | ||
| setHoverState(true); | ||
| }, | ||
| onPointerLeave: (e) => { | ||
| onPointerLeave === null || onPointerLeave === void 0 ? void 0 : onPointerLeave(e); | ||
| setHoverState(false); | ||
| }, | ||
| } | ||
| : {}; | ||
| } | ||
| function usePress(target, { press, onPointerDown, variants } = {}, { press: inheritedPress }, isVariantActive) { | ||
| const [isPressActive, setPressState] = useGestureState(target, press, inheritedPress, variants); | ||
| isVariantActive.press = isPressActive; | ||
| if (!press) | ||
| return {}; | ||
| const onPointerUp = () => { | ||
| setPressState(false); | ||
| window.removeEventListener("pointerup", onPointerUp); | ||
| }; | ||
| return { | ||
| onPointerDown: (e) => { | ||
| onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(e); | ||
| setPressState(true); | ||
| window.addEventListener("pointerup", onPointerUp); | ||
| }, | ||
| }; | ||
| } | ||
| /** | ||
| * @public | ||
| */ | ||
| var PresenceContext = React.createContext(null); | ||
| /** | ||
| * Creates a constant value over the lifecycle of a component. | ||
| * | ||
| * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer | ||
| * a guarantee that it won't re-run for performance reasons later on. By using `useConstant` | ||
| * you can ensure that initialisers don't execute twice or more. | ||
| */ | ||
| function useConstant(init) { | ||
| var ref = React.useRef(null); | ||
| if (ref.current === null) { | ||
| ref.current = init(); | ||
| } | ||
| return ref.current; | ||
| } | ||
| /** | ||
| * When a component is the child of `AnimatePresence`, it can use `usePresence` | ||
| * to access information about whether it's still present in the React tree. | ||
| * | ||
| * ```jsx | ||
| * import { usePresence } from "framer-motion" | ||
| * | ||
| * export const Component = () => { | ||
| * const [isPresent, safeToRemove] = usePresence() | ||
| * | ||
| * useEffect(() => { | ||
| * !isPresent && setTimeout(safeToRemove, 1000) | ||
| * }, [isPresent]) | ||
| * | ||
| * return <div /> | ||
| * } | ||
| * ``` | ||
| * | ||
| * If `isPresent` is `false`, it means that a component has been removed the tree, but | ||
| * `AnimatePresence` won't really remove it until `safeToRemove` has been called. | ||
| * | ||
| * @public | ||
| */ | ||
| function usePresence() { | ||
| var context = React.useContext(PresenceContext); | ||
| if (context === null) | ||
| return [true, null]; | ||
| var isPresent = context.isPresent, onExitComplete = context.onExitComplete, register = context.register; | ||
| // It's safe to call the following hooks conditionally (after an early return) because the context will always | ||
| // either be null or non-null for the lifespan of the component. | ||
| // Replace with useOpaqueId when released in React | ||
| var id = useUniqueId(); | ||
| React.useEffect(function () { return register(id); }, []); | ||
| var safeToRemove = function () { return onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete(id); }; | ||
| return !isPresent && onExitComplete ? [false, safeToRemove] : [true]; | ||
| } | ||
| var counter = 0; | ||
| var incrementId = function () { return counter++; }; | ||
| var useUniqueId = function () { return useConstant(incrementId); }; | ||
| function useExit(target, { exit, variants }, { exit: inheritedExit }) { | ||
| const [isPresent, onExitComplete] = usePresence(); | ||
| /** | ||
| * In case we don't have an exit animation defined we still need to | ||
| * call onExitComplete if it exits so AnimatePresence knows it | ||
| * can remove this component. | ||
| */ | ||
| React.useEffect(() => { | ||
| if (!exit) | ||
| onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete(); | ||
| }, [isPresent]); | ||
| if (exit && !isPresent) { | ||
| Object.assign(target, resolveVariant(exit, inheritedExit, variants)); | ||
| return onExitComplete; | ||
| } | ||
| } | ||
| function useViewport(ref, target, { inViewport, variants, viewport = {}, onViewportEnter, onViewportLeave, }, { inViewport: inheritedInViewport }, isVariantActive) { | ||
| const { root, margin: rootMargin, once, threshold } = viewport; | ||
| const [isInViewport, setViewportState] = useGestureState(target, inViewport, inheritedInViewport, variants); | ||
| isVariantActive.inViewport = isInViewport; | ||
| let shouldObserve = !!inViewport || !!onViewportEnter || !!onViewportLeave; | ||
| if (once && isInViewport) | ||
| shouldObserve = false; | ||
| React.useEffect(() => { | ||
| if (!shouldObserve || typeof IntersectionObserver === "undefined") | ||
| return; | ||
| const observer = new IntersectionObserver(([entry]) => { | ||
| setViewportState(entry.isIntersecting); | ||
| const callback = entry.isIntersecting | ||
| ? onViewportEnter | ||
| : onViewportLeave; | ||
| callback && callback(entry); | ||
| }, { root: root === null || root === void 0 ? void 0 : root.current, rootMargin, threshold }); | ||
| observer.observe(ref.current); | ||
| return () => observer.disconnect(); | ||
| }, [ | ||
| inViewport, | ||
| onViewportEnter, | ||
| onViewportLeave, | ||
| root, | ||
| rootMargin, | ||
| threshold, | ||
| ]); | ||
| } | ||
| function convertKeyframesToStyles(keyframes) { | ||
| const initialKeyframes = {}; | ||
| const transformKeys = []; | ||
| for (let key in keyframes) { | ||
| const value = keyframes[key]; | ||
| if (isTransform(key)) { | ||
| if (transformAlias[key]) | ||
| key = transformAlias[key]; | ||
| transformKeys.push(key); | ||
| key = asTransformCssVar(key); | ||
| } | ||
| let initialKeyframe = Array.isArray(value) ? value[0] : value; | ||
| /** | ||
| * If this is a number and we have a default value type, convert the number | ||
| * to this type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(key); | ||
| if (definition) { | ||
| initialKeyframe = | ||
| typeof value === "number" ? definition.toDefaultUnit(value) : value; | ||
| } | ||
| initialKeyframes[key] = initialKeyframe; | ||
| } | ||
| if (transformKeys.length) { | ||
| initialKeyframes.transform = buildTransformTemplate(transformKeys); | ||
| } | ||
| return initialKeyframes; | ||
| } | ||
| const AnimationContext = React.createContext({}); | ||
| function createAnimatedComponent(Component) { | ||
| function Animated(props, _externalRef) { | ||
| // TODO: Support externalRef if provided | ||
| const ref = React.useRef(null); | ||
| const { options = {}, style, initial, hover, press, exit, inViewport, viewport, variants, onStart, onComplete, inherit = true } = props, forwardProps = __rest(props | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| , ["options", "style", "initial", "hover", "press", "exit", "inViewport", "viewport", "variants", "onStart", "onComplete", "inherit"]); | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| const isVariantActive = { initial: true, style: true }; | ||
| /** | ||
| * Inherit variants from the parent context, | ||
| */ | ||
| let inherited = React.useContext(AnimationContext); | ||
| if (!inherit) | ||
| inherited = {}; | ||
| const resolvedStyle = resolveVariant(style, inherited.style, variants); | ||
| const resolvedInitial = resolveVariant(initial, inherited.initial, variants); | ||
| const initialTarget = Object.assign(Object.assign({}, resolvedStyle), resolvedInitial); | ||
| const target = Object.assign(Object.assign({}, resolvedInitial), resolvedStyle); | ||
| /** | ||
| * If we haven't created a style prop for SSR yet (this is the initial render) | ||
| * make one. We provide this to React every render as beyond that with manage style | ||
| * via animations. | ||
| */ | ||
| const styleProp = React.useRef(null); | ||
| styleProp.current || (styleProp.current = convertKeyframesToStyles(initialTarget)); | ||
| /** | ||
| * Attach animation event handlers (gestures/exit/viewport appearance). | ||
| * This are called in reverse order of which styles should take priority when | ||
| * active, for example if there's a hover and press gesture active the press | ||
| * gesture will take precedence. | ||
| */ | ||
| const hoverProps = useHover(target, props, inherited, isVariantActive); | ||
| const pressProps = usePress(target, props, inherited, isVariantActive); | ||
| useViewport(ref, target, props, inherited, isVariantActive); | ||
| const onExitComplete = useExit(target, props, inherited); | ||
| /** | ||
| * Compare our final calculated style target with the one from the previous render | ||
| * and trigger any necessary animations. | ||
| */ | ||
| useAnimation(ref, initialTarget, target, options, onStart, (animation) => { | ||
| onComplete && onComplete(animation); | ||
| onExitComplete && onExitComplete(); | ||
| }); | ||
| const element = React.createElement(Component, Object.assign({}, forwardProps, hoverProps, pressProps, { | ||
| style: styleProp.current, | ||
| ref, | ||
| })); | ||
| /** | ||
| * Create a variant context to pass forward to child components. | ||
| */ | ||
| const context = variantProps.reduce((acc, key) => { | ||
| acc[key] = undefined; | ||
| if (props[key]) { | ||
| if (typeof props[key] === "string" && isVariantActive[key]) { | ||
| acc[key] = props[key]; | ||
| } | ||
| } | ||
| else if (inherited[key]) { | ||
| acc[key] = inherited[key]; | ||
| } | ||
| return acc; | ||
| }, {}); | ||
| /** | ||
| * Memoize the context so we only trigger a re-render in children if the values | ||
| * within it change. | ||
| */ | ||
| const memoizedContext = React.useMemo(() => context, Object.values(context)); | ||
| return (React__namespace.createElement(AnimationContext.Provider, { value: memoizedContext }, element)); | ||
| } | ||
| return React.forwardRef(Animated); | ||
| } | ||
| const variantProps = [ | ||
| "initial", | ||
| "style", | ||
| "hover", | ||
| "press", | ||
| "inViewport", | ||
| "exit", | ||
| ]; | ||
| const components = new Map(); | ||
| const animated = new Proxy({}, { | ||
| get: (_, key) => { | ||
| if (!components.has(key)) { | ||
| components.set(key, createAnimatedComponent(key)); | ||
| } | ||
| return components.get(key); | ||
| }, | ||
| }); | ||
| exports.animate = animate; | ||
| exports.animateValue = animateValue; | ||
| exports.animated = animated; | ||
| exports.animateStyle = animateStyle; | ||
@@ -1004,0 +644,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -1,1 +0,1 @@ | ||
| import*as t from"react";import{useRef as e,useEffect as n,useState as r,createContext as i,useContext as s,forwardRef as a,createElement as o,useMemo as c}from"react";const l=new WeakMap;function u(t){return l.has(t)||l.set(t,{activeTransforms:[],activeAnimations:{}}),l.get(t)}const f=()=>{},h=t=>t,p=["","X","Y","Z"],y={x:"translateX",y:"translateY",z:"translateZ"},m={syntax:"<angle>",initialValue:"0deg",toDefaultUnit:t=>t+"deg"},d={translate:{syntax:"<length-percentage>",initialValue:"0px",toDefaultUnit:t=>t+"px"},rotate:m,scale:{syntax:"<number>",initialValue:1,toDefaultUnit:h},skew:m},v=new Map,g=t=>`--motion-${t}`,w=["x","y","z"];["translate","scale","rotate","skew"].forEach((t=>{p.forEach((e=>{w.push(t+e),v.set(g(t+e),d[t])}))}));const b=(t,e)=>w.indexOf(t)-w.indexOf(e),O=new Set(w),x=t=>O.has(t),S=t=>t.sort(b).reduce(A,"").trim(),A=(t,e)=>`${t} ${e}(var(${g(e)}))`,P=t=>t.startsWith("--"),T=new Set;const j=t=>1e3*t;const M=t=>Array.isArray(t)&&"number"!=typeof t[0],k=t=>(t=>Array.isArray(t)&&"number"==typeof t[0])(t)?V(t):t,V=([t,e,n,r])=>`cubic-bezier(${t}, ${e}, ${n}, ${r})`,E=t=>document.createElement("div").animate(t,{duration:.001}),D={cssRegisterProperty:()=>"undefined"!=typeof CSS&&Object.hasOwnProperty.call(CSS,"registerProperty"),waapi:()=>Object.hasOwnProperty.call(Element.prototype,"animate"),partialKeyframes:()=>{try{E({opacity:[1]})}catch(t){return!1}return!0},finished:()=>Boolean(E({opacity:[0,1]}).finished)},$={},C=Object.keys(D).reduce(((t,e)=>(t[e]=()=>(void 0===$[e]&&($[e]=D[e]()),$[e]),t)),{}),U=(t,e,n)=>(((1-3*n+3*e)*t+(3*n-6*e))*t+3*e)*t;function I(t,e,n,r){if(t===e&&n===r)return h;const i=e=>function(t,e,n,r,i){let s,a,o=0;do{a=e+(n-e)/2,s=U(a,r,i)-t,s>0?n=a:e=a}while(Math.abs(s)>1e-7&&++o<12);return a}(e,0,1,t,n);return t=>0===t||1===t?t:U(i(t),e,r)}var L=function(t,e,n){var r=e-t;return 0===r?1:(n-t)/r},R=function(t,e,n){return-n*t+n*e+t},z=function(t,e){return void 0===e&&(e="end"),function(n){var r,i,s,a=(n="end"===e?Math.min(n,.999):Math.max(n,.001))*t,o="end"===e?Math.floor(a):Math.ceil(a);return r=0,i=1,s=o/t,Math.min(Math.max(s,r),i)}};const F={ease:I(.25,.1,.25,1),"ease-in":I(.42,0,1,1),"ease-in-out":I(.42,0,.58,1),"ease-out":I(0,0,.58,1)},W=/\((.*?)\)/;function q(t){if("function"==typeof t)return t;if(Array.isArray(t))return I(...t);if(F[t])return F[t];if(t.startsWith("steps")){const e=W.exec(t);if(e){const t=e[1].split(",");return z(parseFloat(t[0]),t[1].trim())}}return h}function B(t,e){const n=t[t.length-1];for(let r=1;r<=e;r++){const i=L(0,e,r);t.push(R(n,1,i))}}function K(t,e=function(t){const e=[0];return B(e,t-1),e}(t.length),n=h){const r=t.length,i=r-e.length;return i>0&&B(e,i),i=>{let s=0;for(;s<r-2&&!(i<e[s+1]);s++);let a=(o=L(e[s],e[s+1],i),Math.min(1,Math.max(o,0)));var o,c,l,u;if(Array.isArray(n)){const t=(c=0,l=n.length-1,((s-c)%(u=l-c)+u)%u+c);a=n[t](a)}else a=n(a);return R(t[s],t[s+1],a)}}class X{constructor(t,e,{easing:n="ease",duration:r=.3,delay:i=0,endDelay:s=0,offset:a,repeat:o=0,direction:c="normal"}){this.startTime=0,this.rate=1,this.t=0,this.cancelT=0,this.playState="idle",this.finished=new Promise(((t,e)=>{this.resolve=t,this.reject=e}));const l=r*(o+1),u=K(e,a,M(n)?n.map(q):q(n));this.tick=e=>{if("finished"===this.playState){const e=u(1);return t(e),void this.resolve(e)}let n=this.pauseTime?this.pauseTime:(e-this.startTime)*this.rate;this.t=n,n/=1e3,n=Math.max(n-i,0);const a=n/r;let o=Math.floor(a),f=a%1;!f&&a>=1&&(f=1),1===f&&o--;const h=o%2;("reverse"===c||"alternate"===c&&h||"alternate-reverse"===c&&!h)&&(f=1-f);const p=n>=l?1:Math.min(f,1),y=u(p);t(y);n>=l+s?(this.playState="finished",this.resolve(y)):"idle"!==this.playState&&requestAnimationFrame(this.tick)},this.play()}play(){const t=performance.now();this.playState="running",this.pauseTime?this.startTime=t-(this.pauseTime-this.startTime):this.startTime||(this.startTime=t),this.pauseTime=void 0,requestAnimationFrame(this.tick)}pause(){this.playState="paused",this.pauseTime=performance.now()}finish(){this.playState="finished",this.tick(0)}cancel(){this.playState="idle",this.tick(this.cancelT),this.reject(!1)}reverse(){this.rate*=-1}commitStyles(){this.cancelT=this.t}get currentTime(){return this.currentTime}set currentTime(t){this.pauseTime||0===this.rate?this.pauseTime=j(t):this.startTime=performance.now()-j(t)/this.rate}get playbackRate(){return this.rate}set playbackRate(t){this.rate=t}}function Y(t,e,n,r={}){let{duration:i=.3,delay:s=0,endDelay:a=0,repeat:o=0,easing:c="ease",direction:l,offset:h}=r;const p=u(t);let m=C.waapi(),d=f;const w=x(e);n=Array.isArray(n)?n:[n],w&&(y[e]&&(e=y[e]),((t,e)=>{const{activeTransforms:n}=u(t);var r,i;i=e,-1===(r=n).indexOf(i)&&r.push(i),t.style.transform=S(n)})(t,e),e=g(e)),function(t,e){t.activeAnimations[e]&&(!function(t){t.commitStyles();try{t.cancel()}catch(t){}}(t.activeAnimations[e]),t.activeAnimations[e]=void 0)}(p,e);const b=v.get(e);if(P(e)?(d=((t,e)=>n=>t.style.setProperty(e,n))(t,e),C.cssRegisterProperty()?function(t){if(!T.has(t)){T.add(t);try{const{syntax:e,initialValue:n}=v.has(t)?v.get(t):{};CSS.registerProperty({name:t,inherits:!1,syntax:e,initialValue:n})}catch(t){}}}(e):m=!1):d=((t,e)=>n=>t.style[e]=n)(t,e),m){if(b&&(n=n.map((t=>"number"==typeof t?b.toDefaultUnit(t):t))),!C.partialKeyframes()&&1===n.length){const r=P(e)?t.style.getPropertyValue(e):getComputedStyle(t)[e];n.unshift(r)}const r={delay:j(s),duration:j(i),endDelay:j(a),easing:M(c)?void 0:k(c),direction:l,iterations:o+1},u=t.animate({[e]:n,offset:h,easing:M(c)?c.map(k):void 0},r);p.activeAnimations[e]=u,u.finished||(u.finished=new Promise(((t,e)=>{u.onfinish=t,u.oncancel=e})));const y=n[n.length-1];return u.finished.then((()=>d(y))).catch(f),u}if(w&&n.every(Z)){if(b){const t=d;d=e=>t(b.toDefaultUnit(e))}return function(t,e=[0,1],n={}){return new X(t,e,n)}(d,n,r)}{const t=n[n.length-1];d(b&&"number"==typeof t?b.toDefaultUnit(t):t)}}const Z=t=>"number"==typeof t;function G(t,r,i,s,a,o){const c=e(r);n((()=>{const e={};if(new Set([...Object.keys(i),...Object.keys(c.current)]).forEach((t=>{let n=i[t];var r,s;(r=n,s=c.current[t],typeof r==typeof s&&(Array.isArray(r)&&Array.isArray(s)?function(t,e){const n=e.length;if(n!==t.length)return!1;for(let r=0;r<n;r++)if(e[r]!==t[r])return!1;return!0}(r,s):r===s))||(e[t]=n)})),Object.keys(e).length&&t.current){null==a||a(e);const n=[];for(const r in e){const i=Y(t.current,r,e[r],s);i&&n.push(i)}Promise.all(n.map((t=>t.finished))).then((()=>null==o?void 0:o(e))).catch(f)}c.current=i}))}function H(t,e,n={}){return t?"string"==typeof t?n[t]:t:e?n[e]:void 0}function J(t,e,n,i){const[s,a]=r(!1);return(s||n)&&Object.assign(t,H(e,n,i)),[s||Boolean(n),a]}var N=i(null);var Q=0,_=function(){return Q++},tt=function(){return t=_,null===(n=e(null)).current&&(n.current=t()),n.current;var t,n};function et(t,{exit:e,variants:r},{exit:i}){const[a,o]=function(){var t=s(N);if(null===t)return[!0,null];var e=t.isPresent,r=t.onExitComplete,i=t.register,a=tt();return n((function(){return i(a)}),[]),!e&&r?[!1,function(){return null==r?void 0:r(a)}]:[!0]}();if(n((()=>{e||null==o||o()}),[a]),e&&!a)return Object.assign(t,H(e,i,r)),o}const nt=i({});function rt(r){return a((function(i,a){const l=e(null),{options:u={},style:f,initial:h,hover:p,press:m,exit:d,inViewport:w,viewport:b,variants:O,onStart:A,onComplete:P,inherit:T=!0}=i,j=function(t,e){var n={};for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.indexOf(r)<0&&(n[r]=t[r]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(r=Object.getOwnPropertySymbols(t);i<r.length;i++)e.indexOf(r[i])<0&&Object.prototype.propertyIsEnumerable.call(t,r[i])&&(n[r[i]]=t[r[i]])}return n}(i,["options","style","initial","hover","press","exit","inViewport","viewport","variants","onStart","onComplete","inherit"]),M={initial:!0,style:!0};let k=s(nt);T||(k={});const V=H(f,k.style,O),E=H(h,k.initial,O),D=Object.assign(Object.assign({},V),E),$=Object.assign(Object.assign({},E),V),C=e(null);C.current||(C.current=function(t){const e={},n=[];for(let r in t){const i=t[r];x(r)&&(y[r]&&(r=y[r]),n.push(r),r=g(r));let s=Array.isArray(i)?i[0]:i;const a=v.get(r);a&&(s="number"==typeof i?a.toDefaultUnit(i):i),e[r]=s}return n.length&&(e.transform=S(n)),e}(D));const U=function(t,{hover:e,onPointerEnter:n,onPointerLeave:r,variants:i}={},{hover:s},a){const[o,c]=J(t,e,s,i);return a.hover=o,e?{onPointerEnter:t=>{null==n||n(t),c(!0)},onPointerLeave:t=>{null==r||r(t),c(!1)}}:{}}($,i,k,M),I=function(t,{press:e,onPointerDown:n,variants:r}={},{press:i},s){const[a,o]=J(t,e,i,r);if(s.press=a,!e)return{};const c=()=>{o(!1),window.removeEventListener("pointerup",c)};return{onPointerDown:t=>{null==n||n(t),o(!0),window.addEventListener("pointerup",c)}}}($,i,k,M);!function(t,e,{inViewport:r,variants:i,viewport:s={},onViewportEnter:a,onViewportLeave:o},{inViewport:c},l){const{root:u,margin:f,once:h,threshold:p}=s,[y,m]=J(e,r,c,i);l.inViewport=y;let d=!!r||!!a||!!o;h&&y&&(d=!1),n((()=>{if(!d||"undefined"==typeof IntersectionObserver)return;const e=new IntersectionObserver((([t])=>{m(t.isIntersecting);const e=t.isIntersecting?a:o;e&&e(t)}),{root:null==u?void 0:u.current,rootMargin:f,threshold:p});return e.observe(t.current),()=>e.disconnect()}),[r,a,o,u,f,p])}(l,$,i,k,M);const L=et($,i,k);G(l,D,$,u,A,(t=>{P&&P(t),L&&L()}));const R=o(r,Object.assign({},j,U,I,{style:C.current,ref:l})),z=it.reduce(((t,e)=>(t[e]=void 0,i[e]?"string"==typeof i[e]&&M[e]&&(t[e]=i[e]):k[e]&&(t[e]=k[e]),t)),{}),F=c((()=>z),Object.values(z));return t.createElement(nt.Provider,{value:F},R)}))}const it=["initial","style","hover","press","inViewport","exit"],st=new Map,at=new Proxy({},{get:(t,e)=>(st.has(e)||st.set(e,rt(e)),st.get(e))});export{at as animated}; | ||
| import*as t from"react";import{useRef as e,useEffect as n,useState as r,createContext as i,useContext as s,forwardRef as o,createElement as a,useMemo as c}from"react";const l=new WeakMap;function u(t){return l.has(t)||l.set(t,{activeTransforms:[],activeAnimations:{}}),l.get(t)}const f=()=>{},h=t=>t,p=["","X","Y","Z"],y={x:"translateX",y:"translateY",z:"translateZ"},m={syntax:"<angle>",initialValue:"0deg",toDefaultUnit:t=>t+"deg"},d={translate:{syntax:"<length-percentage>",initialValue:"0px",toDefaultUnit:t=>t+"px"},rotate:m,scale:{syntax:"<number>",initialValue:1,toDefaultUnit:h},skew:m},v=new Map,g=t=>`--motion-${t}`,w=["x","y","z"];["translate","scale","rotate","skew"].forEach((t=>{p.forEach((e=>{w.push(t+e),v.set(g(t+e),d[t])}))}));const b=(t,e)=>w.indexOf(t)-w.indexOf(e),O=new Set(w),x=t=>O.has(t),S=t=>t.sort(b).reduce(A,"").trim(),A=(t,e)=>`${t} ${e}(var(${g(e)}))`,P=t=>t.startsWith("--"),T=new Set;const j=t=>1e3*t;const M=t=>Array.isArray(t)&&"number"!=typeof t[0],k=t=>(t=>Array.isArray(t)&&"number"==typeof t[0])(t)?V(t):t,V=([t,e,n,r])=>`cubic-bezier(${t}, ${e}, ${n}, ${r})`,E=t=>document.createElement("div").animate(t,{duration:.001}),D={cssRegisterProperty:()=>"undefined"!=typeof CSS&&Object.hasOwnProperty.call(CSS,"registerProperty"),waapi:()=>Object.hasOwnProperty.call(Element.prototype,"animate"),partialKeyframes:()=>{try{E({opacity:[1]})}catch(t){return!1}return!0},finished:()=>Boolean(E({opacity:[0,1]}).finished)},$={},C=Object.keys(D).reduce(((t,e)=>(t[e]=()=>(void 0===$[e]&&($[e]=D[e]()),$[e]),t)),{}),U=(t,e,n)=>(((1-3*n+3*e)*t+(3*n-6*e))*t+3*e)*t;function I(t,e,n,r){if(t===e&&n===r)return h;const i=e=>function(t,e,n,r,i){let s,o,a=0;do{o=e+(n-e)/2,s=U(o,r,i)-t,s>0?n=o:e=o}while(Math.abs(s)>1e-7&&++a<12);return o}(e,0,1,t,n);return t=>0===t||1===t?t:U(i(t),e,r)}var L=function(t,e,n){var r=e-t;return 0===r?1:(n-t)/r},R=function(t,e,n){return-n*t+n*e+t},z=function(t,e){return void 0===e&&(e="end"),function(n){var r,i,s,o=(n="end"===e?Math.min(n,.999):Math.max(n,.001))*t,a="end"===e?Math.floor(o):Math.ceil(o);return r=0,i=1,s=a/t,Math.min(Math.max(s,r),i)}};const F={ease:I(.25,.1,.25,1),"ease-in":I(.42,0,1,1),"ease-in-out":I(.42,0,.58,1),"ease-out":I(0,0,.58,1)},W=/\((.*?)\)/;function q(t){if("function"==typeof t)return t;if(Array.isArray(t))return I(...t);if(F[t])return F[t];if(t.startsWith("steps")){const e=W.exec(t);if(e){const t=e[1].split(",");return z(parseFloat(t[0]),t[1].trim())}}return h}function B(t,e){const n=t[t.length-1];for(let r=1;r<=e;r++){const i=L(0,e,r);t.push(R(n,1,i))}}function K(t,e=function(t){const e=[0];return B(e,t-1),e}(t.length),n=h){const r=t.length,i=r-e.length;return i>0&&B(e,i),i=>{let s=0;for(;s<r-2&&!(i<e[s+1]);s++);let o=(a=L(e[s],e[s+1],i),Math.min(1,Math.max(a,0)));var a,c,l,u;if(Array.isArray(n)){const t=(c=0,l=n.length-1,((s-c)%(u=l-c)+u)%u+c);o=n[t](o)}else o=n(o);return R(t[s],t[s+1],o)}}class X{constructor(t,e,{easing:n="ease",duration:r=.3,delay:i=0,endDelay:s=0,offset:o,repeat:a=0,direction:c="normal"}){this.startTime=0,this.rate=1,this.t=0,this.cancelT=0,this.playState="idle",this.finished=new Promise(((t,e)=>{this.resolve=t,this.reject=e}));const l=r*(a+1),u=K(e,o,M(n)?n.map(q):q(n));this.tick=e=>{if("finished"===this.playState){const e=u(1);return t(e),void this.resolve(e)}let n=this.pauseTime?this.pauseTime:(e-this.startTime)*this.rate;this.t=n,n/=1e3,n=Math.max(n-i,0);const o=n/r;let a=Math.floor(o),f=o%1;!f&&o>=1&&(f=1),1===f&&a--;const h=a%2;("reverse"===c||"alternate"===c&&h||"alternate-reverse"===c&&!h)&&(f=1-f);const p=n>=l?1:Math.min(f,1),y=u(p);t(y);n>=l+s?(this.playState="finished",this.resolve(y)):"idle"!==this.playState&&requestAnimationFrame(this.tick)},this.play()}play(){const t=performance.now();this.playState="running",this.pauseTime?this.startTime=t-(this.pauseTime-this.startTime):this.startTime||(this.startTime=t),this.pauseTime=void 0,requestAnimationFrame(this.tick)}pause(){this.playState="paused",this.pauseTime=performance.now()}finish(){this.playState="finished",this.tick(0)}cancel(){this.playState="idle",this.tick(this.cancelT),this.reject(!1)}reverse(){this.rate*=-1}commitStyles(){this.cancelT=this.t}get currentTime(){return this.currentTime}set currentTime(t){this.pauseTime||0===this.rate?this.pauseTime=j(t):this.startTime=performance.now()-j(t)/this.rate}get playbackRate(){return this.rate}set playbackRate(t){this.rate=t}}function Y(t,e,n,r={}){let{duration:i=.3,delay:s=0,endDelay:o=0,repeat:a=0,easing:c="ease",direction:l,offset:h}=r;const p=u(t);let m=C.waapi(),d=f;const w=x(e);n=Array.isArray(n)?n:[n],w&&(y[e]&&(e=y[e]),((t,e)=>{const{activeTransforms:n}=u(t);var r,i;i=e,-1===(r=n).indexOf(i)&&r.push(i),t.style.transform=S(n)})(t,e),e=g(e)),function(t,e){t.activeAnimations[e]&&(!function(t){t.commitStyles();try{t.cancel()}catch(t){}}(t.activeAnimations[e]),t.activeAnimations[e]=void 0)}(p,e);const b=v.get(e);if(P(e)?(d=((t,e)=>n=>t.style.setProperty(e,n))(t,e),C.cssRegisterProperty()?function(t){if(!T.has(t)){T.add(t);try{const{syntax:e,initialValue:n}=v.has(t)?v.get(t):{};CSS.registerProperty({name:t,inherits:!1,syntax:e,initialValue:n})}catch(t){}}}(e):m=!1):d=((t,e)=>n=>t.style[e]=n)(t,e),m){if(b&&(n=n.map((t=>"number"==typeof t?b.toDefaultUnit(t):t))),!C.partialKeyframes()&&1===n.length){const r=P(e)?t.style.getPropertyValue(e):getComputedStyle(t)[e];n.unshift(r)}const r={delay:j(s),duration:j(i),endDelay:j(o),easing:M(c)?void 0:k(c),direction:l,iterations:a+1},u=t.animate({[e]:n,offset:h,easing:M(c)?c.map(k):void 0},r);p.activeAnimations[e]=u,u.finished||(u.finished=new Promise(((t,e)=>{u.onfinish=t,u.oncancel=e})));const y=n[n.length-1];return u.finished.then((()=>d(y))).catch(f),u}if(w&&n.every(Z)){if(b){const t=d;d=e=>t(b.toDefaultUnit(e))}return function(t,e=[0,1],n={}){return new X(t,e,n)}(d,n,r)}{const t=n[n.length-1];d(b&&"number"==typeof t?b.toDefaultUnit(t):t)}}const Z=t=>"number"==typeof t;const G=(t,e)=>t[e]?Object.assign(Object.assign({},t),t[e]):t;function H(t,r,i,s,o,a){const c=e(r);n((()=>{const e={};if(new Set([...Object.keys(i),...Object.keys(c.current)]).forEach((t=>{let n=i[t];var r,s;(r=n,s=c.current[t],typeof r==typeof s&&(Array.isArray(r)&&Array.isArray(s)?function(t,e){const n=e.length;if(n!==t.length)return!1;for(let r=0;r<n;r++)if(e[r]!==t[r])return!1;return!0}(r,s):r===s))||(e[t]=n)})),Object.keys(e).length&&t.current){null==o||o(e);const n=[];for(const r in e){const i=Y(t.current,r,e[r],G(s,r));i&&n.push(i)}Promise.all(n.map((t=>t.finished))).then((()=>null==a?void 0:a(e))).catch(f)}c.current=i}))}function J(t,e,n={}){return t?"string"==typeof t?n[t]:t:e?n[e]:void 0}function N(t,e,n){if(n)for(const r in n)"options"!==r&&(t[r]=n[r],n.options&&(e[r]=G(n.options,r)))}function Q(t,e,n,i,s){const[o,a]=r(!1);return(o||i)&&N(t,e,J(n,i,s)),[o||Boolean(i),a]}var _=i(null);var tt=0,et=function(){return tt++},nt=function(){return t=et,null===(n=e(null)).current&&(n.current=t()),n.current;var t,n};function rt(t,e,{exit:r,poses:i},{exit:o}){const[a,c]=function(){var t=s(_);if(null===t)return[!0,null];var e=t.isPresent,r=t.onExitComplete,i=t.register,o=nt();return n((function(){return i(o)}),[]),!e&&r?[!1,function(){return null==r?void 0:r(o)}]:[!0]}();if(n((()=>{r||null==c||c()}),[a]),r&&!a)return N(t,e,J(r,o,i)),c}const it=i({});function st(r){return o((function(i,o){const l=e(null),{options:u,style:f,initial:h,hover:p,press:m,exit:d,inViewport:w,viewport:b,poses:O,onStart:A,onComplete:P,inherit:T=!0}=i,j=function(t,e){var n={};for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.indexOf(r)<0&&(n[r]=t[r]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(r=Object.getOwnPropertySymbols(t);i<r.length;i++)e.indexOf(r[i])<0&&Object.prototype.propertyIsEnumerable.call(t,r[i])&&(n[r[i]]=t[r[i]])}return n}(i,["options","style","initial","hover","press","exit","inViewport","viewport","poses","onStart","onComplete","inherit"]),M={initial:!0,style:!0};let k=s(it);T||(k={});const V=J(f,k.style,O),E=J(h,k.initial,O),D=Object.assign(Object.assign({},V),E),$=Object.assign(Object.assign({},E),V),C=Object.assign(Object.assign({},u),null==V?void 0:V.options),U=e(null);U.current||(U.current=function(t){const e={},n=[];for(let r in t){const i=t[r];x(r)&&(y[r]&&(r=y[r]),n.push(r),r=g(r));let s=Array.isArray(i)?i[0]:i;const o=v.get(r);o&&(s="number"==typeof i?o.toDefaultUnit(i):i),e[r]=s}return n.length&&(e.transform=S(n)),e}(D));const I=function(t,e,{hover:n,onPointerEnter:r,onPointerLeave:i,poses:s}={},{hover:o},a){const[c,l]=Q(t,e,n,o,s);return a.hover=c,n?{onPointerEnter:t=>{null==r||r(t),l(!0)},onPointerLeave:t=>{null==i||i(t),l(!1)}}:{}}($,C,i,k,M),L=function(t,e,{press:n,onPointerDown:r,poses:i}={},{press:s},o){const[a,c]=Q(t,e,n,s,i);if(o.press=a,!n)return{};const l=()=>{c(!1),window.removeEventListener("pointerup",l)};return{onPointerDown:t=>{null==r||r(t),c(!0),window.addEventListener("pointerup",l)}}}($,C,i,k,M);!function(t,e,r,{inViewport:i,poses:s,viewport:o={},onViewportEnter:a,onViewportLeave:c},{inViewport:l},u){const{root:f,margin:h,once:p,threshold:y}=o,[m,d]=Q(e,r,i,l,s);u.inViewport=m;let v=!!i||!!a||!!c;p&&m&&(v=!1),n((()=>{if(!v||"undefined"==typeof IntersectionObserver)return;const e=new IntersectionObserver((([t])=>{d(t.isIntersecting);const e=t.isIntersecting?a:c;e&&e(t)}),{root:null==f?void 0:f.current,rootMargin:h,threshold:y});return e.observe(t.current),()=>e.disconnect()}),[i,a,c,f,h,y])}(l,$,C,i,k,M);const R=rt($,C,i,k);H(l,D,$,C,A,(t=>{P&&P(t),R&&R()}));const z=a(r,Object.assign({},j,I,L,{style:U.current,ref:l})),F=ot.reduce(((t,e)=>(t[e]=void 0,i[e]?"string"==typeof i[e]&&M[e]&&(t[e]=i[e]):k[e]&&(t[e]=k[e]),t)),{}),W=c((()=>F),Object.values(F));return t.createElement(it.Provider,{value:W},z)}))}const ot=["initial","style","hover","press","inViewport","exit"],at=new Map,ct=new Proxy({},{get:(t,e)=>(at.has(e)||at.set(e,st(e)),at.get(e))});export{ct as animated}; |
+5
-4
| { | ||
| "name": "motion", | ||
| "version": "6.0.1-alpha.29", | ||
| "version": "6.0.1-alpha.30", | ||
| "description": "The Motion library for the web", | ||
@@ -10,3 +10,3 @@ "author": "Matt Perry", | ||
| "license": "MIT", | ||
| "repository": "https://github.com/mattgperry/motion", | ||
| "repository": "https://github.com/motiondivision/motion", | ||
| "sideEffects": false, | ||
@@ -18,3 +18,4 @@ "keywords": [ | ||
| "cubic bezier", | ||
| "easing" | ||
| "easing", | ||
| "waapi" | ||
| ], | ||
@@ -135,5 +136,5 @@ "scripts": { | ||
| "path": "./dist/size-react.js", | ||
| "maxSize": "4.1 kB" | ||
| "maxSize": "4.2 kB" | ||
| } | ||
| ] | ||
| } |
+1
-5
| export { animate } from "./targets/dom/animate" | ||
| export { animateValue } from "./targets/dom/animate-value" | ||
| export { animateStyle } from "./targets/dom/animate-style" | ||
| export * from "./targets/dom/types" | ||
| // TODO Move to seperate motion/react entry point | ||
| export { animated } from "./targets/react/index" | ||
| export * from "./targets/react/types" |
@@ -8,3 +8,3 @@ import { | ||
| import { stopAnimation } from "./utils/stop-animation" | ||
| import { animateValue } from "./animate-value" | ||
| import { animateStyle } from "./animate-style" | ||
| import { getOptions } from "./utils/options" | ||
@@ -40,3 +40,3 @@ | ||
| const animation = animateValue( | ||
| const animation = animateStyle( | ||
| element, | ||
@@ -43,0 +43,0 @@ key, |
@@ -8,3 +8,6 @@ import { getOptions } from "../options" | ||
| ).toEqual({ duration: 1, easing: "ease", x: { easing: "ease" } }) | ||
| expect( | ||
| getOptions({ duration: 1, opacity: { duration: 0.0001 } }, "opacity") | ||
| ).toEqual({ duration: 0.0001, opacity: { duration: 0.0001 } }) | ||
| }) | ||
| }) |
@@ -75,2 +75,22 @@ import { | ||
| test("Style props can accept options override", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial={{ opacity: 0.4 }} | ||
| style={{ opacity: [0, 0.8], options: { duration } }} | ||
| onComplete={() => resolve(true)} | ||
| options={{ duration: 100 }} | ||
| /> | ||
| ) | ||
| const { rerender } = render(<Component />) | ||
| rerender(<Component />) | ||
| setTimeout(() => reject(false), 100) | ||
| }) | ||
| return expect(promise).resolves.toBe(true) | ||
| }) | ||
| test("Animation doesn't run on mount if initial and style define different values", async () => { | ||
@@ -155,2 +175,23 @@ const promise = new Promise((resolve, reject) => { | ||
| test("Hover accepts options", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const Component = () => ( | ||
| <animated.div | ||
| hover={{ opacity: 0.3, options: { duration } }} | ||
| options={{ duration: 100 }} | ||
| style={{ opacity: 0 }} | ||
| onComplete={(animation) => resolve(animation)} | ||
| /> | ||
| ) | ||
| const { container, rerender } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerEnter(container.firstChild as Element) | ||
| setTimeout(() => reject(), 100) | ||
| }) | ||
| return expect(promise).resolves.toEqual({ opacity: 0.3 }) | ||
| }) | ||
| test("Values animate back to style/initial when hover ends", async () => { | ||
@@ -201,2 +242,23 @@ const promise = new Promise((resolve, reject) => { | ||
| test("Press accepts options", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const Component = () => ( | ||
| <animated.div | ||
| press={{ opacity: [0.2, 0.3], options: { duration } }} | ||
| options={{ duration: 100 }} | ||
| style={{ opacity: [0, 0.2] }} | ||
| onComplete={(animation) => resolve(animation)} | ||
| /> | ||
| ) | ||
| const { container, rerender } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerDown(container.firstChild as Element) | ||
| setTimeout(() => reject(), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual({ opacity: [0.2, 0.3] }) | ||
| }) | ||
| test("Values animate back to style/initial/hover when press ends", async () => { | ||
@@ -203,0 +265,0 @@ const promise = new Promise((resolve, reject) => { |
@@ -60,3 +60,3 @@ import * as React from "react" | ||
| inherit={false} | ||
| variants={{}} | ||
| poses={{}} | ||
| viewport={{ margin: "100px" }} | ||
@@ -74,3 +74,3 @@ options={{ duration: 1 }} | ||
| test("Renders initial and style as variants", () => { | ||
| test("Renders initial and style as poses", () => { | ||
| const html = render( | ||
@@ -84,3 +84,3 @@ <animated.div | ||
| exit="litmus" | ||
| variants={{ | ||
| poses={{ | ||
| foo: { opacity: 1, background: "red" }, | ||
@@ -93,9 +93,9 @@ bar: { opacity: 0.5, width: "100px" }, | ||
| style={{ opacity: 1 }} | ||
| variants={{ foo: { opacity: 0.99 }, litmus: { background: "red" } }} | ||
| poses={{ foo: { opacity: 0.99 }, litmus: { background: "red" } }} | ||
| > | ||
| <animated.span variants={{ bar: { opacity: 0.25 } }}> | ||
| <animated.div variants={{ foo: { opacity: 0.2 } }}> | ||
| <animated.span poses={{ bar: { opacity: 0.25 } }}> | ||
| <animated.div poses={{ foo: { opacity: 0.2 } }}> | ||
| <animated.div | ||
| inherit={false} | ||
| variants={{ foo: { opacity: 0.3 } }} | ||
| poses={{ foo: { opacity: 0.3 } }} | ||
| ></animated.div> | ||
@@ -102,0 +102,0 @@ </animated.div> |
@@ -7,3 +7,3 @@ import * as React from "react" | ||
| MotionCSSProperties, | ||
| VariantActiveState, | ||
| PoseActiveState, | ||
| } from "./types" | ||
@@ -16,3 +16,3 @@ import { useAnimation } from "./hooks/use-animation" | ||
| import { convertKeyframesToStyles } from "./utils/keyframes" | ||
| import { resolveVariant } from "./utils/variants" | ||
| import { resolvePose } from "./utils/poses" | ||
| import { AnimationContext } from "./context" | ||
@@ -29,3 +29,3 @@ | ||
| const { | ||
| options = {}, | ||
| options: defaultOptions, | ||
| style, | ||
@@ -38,3 +38,3 @@ initial, | ||
| viewport, | ||
| variants, | ||
| poses, | ||
| onStart, | ||
@@ -47,9 +47,9 @@ onComplete, | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * Track throughout the render which poses are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| const isVariantActive: VariantActiveState = { initial: true, style: true } | ||
| const isPoseActive: PoseActiveState = { initial: true, style: true } | ||
| /** | ||
| * Inherit variants from the parent context, | ||
| * Inherit poses from the parent context, | ||
| */ | ||
@@ -59,7 +59,7 @@ let inherited = useContext(AnimationContext) | ||
| const resolvedStyle = resolveVariant(style, inherited.style, variants) | ||
| const resolvedInitial = resolveVariant( | ||
| const resolvedStyle = resolvePose(style, inherited.style, poses) | ||
| const resolvedInitial = resolvePose( | ||
| initial as any, | ||
| inherited.initial, | ||
| variants | ||
| poses | ||
| ) | ||
@@ -69,2 +69,4 @@ const initialTarget = { ...resolvedStyle, ...resolvedInitial } | ||
| const options = { ...defaultOptions, ...resolvedStyle?.options } | ||
| /** | ||
@@ -84,6 +86,6 @@ * If we haven't created a style prop for SSR yet (this is the initial render) | ||
| */ | ||
| const hoverProps = useHover(target, props, inherited, isVariantActive) | ||
| const pressProps = usePress(target, props, inherited, isVariantActive) | ||
| useViewport(ref, target, props, inherited, isVariantActive) | ||
| const onExitComplete = useExit(target, props, inherited) | ||
| const hoverProps = useHover(target, options, props, inherited, isPoseActive) | ||
| const pressProps = usePress(target, options, props, inherited, isPoseActive) | ||
| useViewport(ref, target, options, props, inherited, isPoseActive) | ||
| const onExitComplete = useExit(target, options, props, inherited) | ||
@@ -113,3 +115,3 @@ /** | ||
| if (props[key]) { | ||
| if (typeof props[key] === "string" && isVariantActive[key]) { | ||
| if (typeof props[key] === "string" && isPoseActive[key]) { | ||
| acc[key] = props[key] | ||
@@ -116,0 +118,0 @@ } |
@@ -1,7 +0,8 @@ | ||
| import { AnimationOptions, MotionKeyframes } from "../../dom/types" | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { AnimationCallback, MotionCSSProperties } from "../types" | ||
| import { RefObject, useEffect, useRef } from "react" | ||
| import { animateValue } from "../../dom/animate-value" | ||
| import { animateStyle } from "../../dom/animate-style" | ||
| import { noop } from "../../../utils/noop" | ||
| import { hasChanged } from "../utils/has-changed" | ||
| import { getOptions } from "../../dom/utils/options" | ||
@@ -12,3 +13,3 @@ export function useAnimation( | ||
| target: MotionKeyframes, | ||
| options?: AnimationOptions, | ||
| options: AnimationOptionsWithOverrides, | ||
| onStart?: AnimationCallback, | ||
@@ -42,7 +43,7 @@ onComplete?: AnimationCallback | ||
| for (const key in targetKeyframe) { | ||
| const animation = animateValue( | ||
| const animation = animateStyle( | ||
| ref.current, | ||
| key, | ||
| targetKeyframe[key]!, | ||
| options | ||
| getOptions(options, key) | ||
| ) | ||
@@ -49,0 +50,0 @@ animation && animations.push(animation) |
@@ -1,10 +0,12 @@ | ||
| import { MotionKeyframes } from "../../dom/types" | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { usePresence } from "framer-motion" | ||
| import { useEffect } from "react" | ||
| import { AnimatedProps, AnimationContextProps } from "../types" | ||
| import { resolveVariant } from "../utils/variants" | ||
| import { resolvePose } from "../utils/poses" | ||
| import { updateTargetAndOptions } from "../utils/update-target" | ||
| export function useExit( | ||
| target: MotionKeyframes, | ||
| { exit, variants }: AnimatedProps, | ||
| options: AnimationOptionsWithOverrides, | ||
| { exit, poses }: AnimatedProps, | ||
| { exit: inheritedExit }: AnimationContextProps | ||
@@ -24,5 +26,9 @@ ) { | ||
| if (exit && !isPresent) { | ||
| Object.assign(target, resolveVariant(exit, inheritedExit, variants)) | ||
| updateTargetAndOptions( | ||
| target, | ||
| options, | ||
| resolvePose(exit, inheritedExit, poses) | ||
| ) | ||
| return onExitComplete | ||
| } | ||
| } |
| import { Dispatch, SetStateAction, useState } from "react" | ||
| import { MotionKeyframes } from "../../dom/types" | ||
| import { Variants } from "../types" | ||
| import { resolveVariant } from "../utils/variants" | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { Poses } from "../types" | ||
| import { resolvePose } from "../utils/poses" | ||
| import { updateTargetAndOptions } from "../utils/update-target" | ||
| export function useGestureState( | ||
| target: MotionKeyframes, | ||
| options: AnimationOptionsWithOverrides, | ||
| stylesToApply?: MotionKeyframes | string, | ||
| inheritedVariant?: string, | ||
| variants?: Variants | ||
| inheritedPose?: string, | ||
| poses?: Poses | ||
| ): [boolean, Dispatch<SetStateAction<boolean>>] { | ||
| const [isGestureActive, setGestureState] = useState(false) | ||
| if (isGestureActive || inheritedVariant) { | ||
| Object.assign( | ||
| if (isGestureActive || inheritedPose) { | ||
| updateTargetAndOptions( | ||
| target, | ||
| resolveVariant(stylesToApply, inheritedVariant, variants) | ||
| options, | ||
| resolvePose(stylesToApply, inheritedPose, poses) | ||
| ) | ||
| } | ||
| return [isGestureActive || Boolean(inheritedVariant), setGestureState] | ||
| return [isGestureActive || Boolean(inheritedPose), setGestureState] | ||
| } |
| import { HTMLProps } from "react" | ||
| import { MotionKeyframes } from "../../dom/types" | ||
| import { | ||
| AnimatedProps, | ||
| AnimationContextProps, | ||
| VariantActiveState, | ||
| } from "../types" | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { AnimatedProps, AnimationContextProps, PoseActiveState } from "../types" | ||
| import { useGestureState } from "./use-gesture-state" | ||
@@ -12,2 +8,3 @@ | ||
| target: MotionKeyframes, | ||
| options: AnimationOptionsWithOverrides, | ||
| { | ||
@@ -17,15 +14,16 @@ hover, | ||
| onPointerLeave, | ||
| variants, | ||
| poses, | ||
| }: AnimatedProps & HTMLProps<any> = {}, | ||
| { hover: inheritedHover }: AnimationContextProps, | ||
| isVariantActive: VariantActiveState | ||
| isPoseActive: PoseActiveState | ||
| ): HTMLProps<any> { | ||
| const [isHoverActive, setHoverState] = useGestureState( | ||
| target, | ||
| options, | ||
| hover, | ||
| inheritedHover, | ||
| variants | ||
| poses | ||
| ) | ||
| isVariantActive.hover = isHoverActive | ||
| isPoseActive.hover = isHoverActive | ||
@@ -32,0 +30,0 @@ return hover |
| import { HTMLProps } from "react" | ||
| import { MotionKeyframes } from "../../dom/types" | ||
| import { | ||
| AnimatedProps, | ||
| AnimationContextProps, | ||
| VariantActiveState, | ||
| } from "../types" | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { AnimatedProps, AnimationContextProps, PoseActiveState } from "../types" | ||
| import { useGestureState } from "./use-gesture-state" | ||
@@ -12,13 +8,15 @@ | ||
| target: MotionKeyframes, | ||
| { press, onPointerDown, variants }: AnimatedProps & HTMLProps<any> = {}, | ||
| options: AnimationOptionsWithOverrides, | ||
| { press, onPointerDown, poses }: AnimatedProps & HTMLProps<any> = {}, | ||
| { press: inheritedPress }: AnimationContextProps, | ||
| isVariantActive: VariantActiveState | ||
| isPoseActive: PoseActiveState | ||
| ): HTMLProps<any> { | ||
| const [isPressActive, setPressState] = useGestureState( | ||
| target, | ||
| options, | ||
| press, | ||
| inheritedPress, | ||
| variants | ||
| poses | ||
| ) | ||
| isVariantActive.press = isPressActive | ||
| isPoseActive.press = isPressActive | ||
@@ -25,0 +23,0 @@ if (!press) return {} |
| import { RefObject, useEffect } from "react" | ||
| import { MotionKeyframes } from "../../dom/types" | ||
| import { | ||
| AnimatedProps, | ||
| AnimationContextProps, | ||
| VariantActiveState, | ||
| } from "../types" | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types" | ||
| import { AnimatedProps, AnimationContextProps, PoseActiveState } from "../types" | ||
| import { useGestureState } from "./use-gesture-state" | ||
@@ -13,5 +9,6 @@ | ||
| target: MotionKeyframes, | ||
| options: AnimationOptionsWithOverrides, | ||
| { | ||
| inViewport, | ||
| variants, | ||
| poses, | ||
| viewport = {}, | ||
@@ -22,3 +19,3 @@ onViewportEnter, | ||
| { inViewport: inheritedInViewport }: AnimationContextProps, | ||
| isVariantActive: VariantActiveState | ||
| isPoseActive: PoseActiveState | ||
| ) { | ||
@@ -29,7 +26,8 @@ const { root, margin: rootMargin, once, threshold } = viewport | ||
| target, | ||
| options, | ||
| inViewport, | ||
| inheritedInViewport, | ||
| variants | ||
| poses | ||
| ) | ||
| isVariantActive.inViewport = isInViewport | ||
| isPoseActive.inViewport = isInViewport | ||
@@ -36,0 +34,0 @@ let shouldObserve = !!inViewport || !!onViewportEnter || !!onViewportLeave |
@@ -12,4 +12,9 @@ import { | ||
| } from "react" | ||
| import { AnimationOptions, MotionKeyframes } from "../dom/types" | ||
| import { | ||
| AnimationOptions, | ||
| AnimationOptionsWithOverrides, | ||
| MotionKeyframes, | ||
| } from "../dom/types" | ||
| import { svgElements, htmlElements } from "./utils/supported-elements" | ||
| export type AnimationCallback = (target: MotionKeyframes) => void | ||
@@ -35,5 +40,9 @@ | ||
| export type MotionKeyframesWithOptions = MotionKeyframes & { | ||
| options?: AnimationOptionsWithOverrides | ||
| } | ||
| export type MotionCSSProperties = CSSPropertiesWithTransform & CSSVariables | ||
| export type Variants = { [key: string]: MotionKeyframes } | ||
| export type Poses = { [key: string]: MotionKeyframesWithOptions } | ||
@@ -49,9 +58,9 @@ export interface ViewportOptions { | ||
| initial?: MotionCSSProperties | string | ||
| style?: MotionKeyframes | string | ||
| hover?: MotionKeyframes | string | ||
| press?: MotionKeyframes | string | ||
| exit?: MotionKeyframes | string | ||
| inViewport?: MotionKeyframes | string | ||
| style?: MotionKeyframesWithOptions | string | ||
| hover?: MotionKeyframesWithOptions | string | ||
| press?: MotionKeyframesWithOptions | string | ||
| exit?: MotionKeyframesWithOptions | string | ||
| inViewport?: MotionKeyframesWithOptions | string | ||
| inherit?: boolean | ||
| variants?: Variants | ||
| poses?: Poses | ||
| viewport?: ViewportOptions | ||
@@ -65,3 +74,3 @@ options?: AnimationOptions | ||
| export type VariantProps = { | ||
| export type PoseProps = { | ||
| initial?: boolean | ||
@@ -76,7 +85,7 @@ style?: boolean | ||
| export type AnimationContextProps = { | ||
| [K in keyof VariantProps]?: string | ||
| [K in keyof PoseProps]?: string | ||
| } | ||
| export type VariantActiveState = { | ||
| [K in keyof VariantProps]?: boolean | ||
| export type PoseActiveState = { | ||
| [K in keyof PoseProps]?: boolean | ||
| } | ||
@@ -83,0 +92,0 @@ |
+1
-3
| export { animate } from "./targets/dom/animate"; | ||
| export { animateValue } from "./targets/dom/animate-value"; | ||
| export { animateStyle } from "./targets/dom/animate-style"; | ||
| export * from "./targets/dom/types"; | ||
| export { animated } from "./targets/react/index"; | ||
| export * from "./targets/react/types"; |
@@ -1,4 +0,4 @@ | ||
| import { AnimationOptions, MotionKeyframes } from "../../dom/types"; | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { AnimationCallback, MotionCSSProperties } from "../types"; | ||
| import { RefObject } from "react"; | ||
| export declare function useAnimation(ref: RefObject<HTMLElement>, initial: MotionKeyframes | MotionCSSProperties, target: MotionKeyframes, options?: AnimationOptions, onStart?: AnimationCallback, onComplete?: AnimationCallback): void; | ||
| export declare function useAnimation(ref: RefObject<HTMLElement>, initial: MotionKeyframes | MotionCSSProperties, target: MotionKeyframes, options: AnimationOptionsWithOverrides, onStart?: AnimationCallback, onComplete?: AnimationCallback): void; |
@@ -1,3 +0,3 @@ | ||
| import { MotionKeyframes } from "../../dom/types"; | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps } from "../types"; | ||
| export declare function useExit(target: MotionKeyframes, { exit, variants }: AnimatedProps, { exit: inheritedExit }: AnimationContextProps): import("framer-motion/types/components/AnimatePresence/use-presence").SafeToRemove | null | undefined; | ||
| export declare function useExit(target: MotionKeyframes, options: AnimationOptionsWithOverrides, { exit, poses }: AnimatedProps, { exit: inheritedExit }: AnimationContextProps): import("framer-motion/types/components/AnimatePresence/use-presence").SafeToRemove | null | undefined; |
| import { Dispatch, SetStateAction } from "react"; | ||
| import { MotionKeyframes } from "../../dom/types"; | ||
| import { Variants } from "../types"; | ||
| export declare function useGestureState(target: MotionKeyframes, stylesToApply?: MotionKeyframes | string, inheritedVariant?: string, variants?: Variants): [boolean, Dispatch<SetStateAction<boolean>>]; | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { Poses } from "../types"; | ||
| export declare function useGestureState(target: MotionKeyframes, options: AnimationOptionsWithOverrides, stylesToApply?: MotionKeyframes | string, inheritedPose?: string, poses?: Poses): [boolean, Dispatch<SetStateAction<boolean>>]; |
| import { HTMLProps } from "react"; | ||
| import { MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps, VariantActiveState } from "../types"; | ||
| export declare function useHover(target: MotionKeyframes, { hover, onPointerEnter, onPointerLeave, variants, }: (AnimatedProps & HTMLProps<any>) | undefined, { hover: inheritedHover }: AnimationContextProps, isVariantActive: VariantActiveState): HTMLProps<any>; | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps, PoseActiveState } from "../types"; | ||
| export declare function useHover(target: MotionKeyframes, options: AnimationOptionsWithOverrides, { hover, onPointerEnter, onPointerLeave, poses, }: (AnimatedProps & HTMLProps<any>) | undefined, { hover: inheritedHover }: AnimationContextProps, isPoseActive: PoseActiveState): HTMLProps<any>; |
| import { HTMLProps } from "react"; | ||
| import { MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps, VariantActiveState } from "../types"; | ||
| export declare function usePress(target: MotionKeyframes, { press, onPointerDown, variants }: (AnimatedProps & HTMLProps<any>) | undefined, { press: inheritedPress }: AnimationContextProps, isVariantActive: VariantActiveState): HTMLProps<any>; | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps, PoseActiveState } from "../types"; | ||
| export declare function usePress(target: MotionKeyframes, options: AnimationOptionsWithOverrides, { press, onPointerDown, poses }: (AnimatedProps & HTMLProps<any>) | undefined, { press: inheritedPress }: AnimationContextProps, isPoseActive: PoseActiveState): HTMLProps<any>; |
| import { RefObject } from "react"; | ||
| import { MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps, VariantActiveState } from "../types"; | ||
| export declare function useViewport(ref: RefObject<Element>, target: MotionKeyframes, { inViewport, variants, viewport, onViewportEnter, onViewportLeave, }: AnimatedProps, { inViewport: inheritedInViewport }: AnimationContextProps, isVariantActive: VariantActiveState): void; | ||
| import { AnimationOptionsWithOverrides, MotionKeyframes } from "../../dom/types"; | ||
| import { AnimatedProps, AnimationContextProps, PoseActiveState } from "../types"; | ||
| export declare function useViewport(ref: RefObject<Element>, target: MotionKeyframes, options: AnimationOptionsWithOverrides, { inViewport, poses, viewport, onViewportEnter, onViewportLeave, }: AnimatedProps, { inViewport: inheritedInViewport }: AnimationContextProps, isPoseActive: PoseActiveState): void; |
| import { CSSProperties, DetailedHTMLFactory, ForwardRefExoticComponent, HTMLAttributes, PropsWithoutRef, ReactHTML, RefAttributes, RefObject, SVGAttributes } from "react"; | ||
| import { AnimationOptions, MotionKeyframes } from "../dom/types"; | ||
| import { AnimationOptions, AnimationOptionsWithOverrides, MotionKeyframes } from "../dom/types"; | ||
| import { svgElements, htmlElements } from "./utils/supported-elements"; | ||
@@ -21,5 +21,8 @@ export declare type AnimationCallback = (target: MotionKeyframes) => void; | ||
| }; | ||
| export declare type MotionKeyframesWithOptions = MotionKeyframes & { | ||
| options?: AnimationOptionsWithOverrides; | ||
| }; | ||
| export declare type MotionCSSProperties = CSSPropertiesWithTransform & CSSVariables; | ||
| export declare type Variants = { | ||
| [key: string]: MotionKeyframes; | ||
| export declare type Poses = { | ||
| [key: string]: MotionKeyframesWithOptions; | ||
| }; | ||
@@ -34,9 +37,9 @@ export interface ViewportOptions { | ||
| initial?: MotionCSSProperties | string; | ||
| style?: MotionKeyframes | string; | ||
| hover?: MotionKeyframes | string; | ||
| press?: MotionKeyframes | string; | ||
| exit?: MotionKeyframes | string; | ||
| inViewport?: MotionKeyframes | string; | ||
| style?: MotionKeyframesWithOptions | string; | ||
| hover?: MotionKeyframesWithOptions | string; | ||
| press?: MotionKeyframesWithOptions | string; | ||
| exit?: MotionKeyframesWithOptions | string; | ||
| inViewport?: MotionKeyframesWithOptions | string; | ||
| inherit?: boolean; | ||
| variants?: Variants; | ||
| poses?: Poses; | ||
| viewport?: ViewportOptions; | ||
@@ -49,3 +52,3 @@ options?: AnimationOptions; | ||
| } | ||
| export declare type VariantProps = { | ||
| export declare type PoseProps = { | ||
| initial?: boolean; | ||
@@ -59,6 +62,6 @@ style?: boolean; | ||
| export declare type AnimationContextProps = { | ||
| [K in keyof VariantProps]?: string; | ||
| [K in keyof PoseProps]?: string; | ||
| }; | ||
| export declare type VariantActiveState = { | ||
| [K in keyof VariantProps]?: boolean; | ||
| export declare type PoseActiveState = { | ||
| [K in keyof PoseProps]?: boolean; | ||
| }; | ||
@@ -65,0 +68,0 @@ declare type UnionStringArray<T extends Readonly<string[]>> = T[number]; |
| import { getAnimationData } from './data.js'; | ||
| import { isCssVar, registerCssVariable } from './utils/css-var.js'; | ||
| import { noop } from '../../utils/noop.js'; | ||
| import { ms } from './utils/time.js'; | ||
| import { isTransform, transformAlias, addTransformToElement, asTransformCssVar, transformPropertyDefinitions } from './utils/transforms.js'; | ||
| import { stopAnimation } from './utils/stop-animation.js'; | ||
| import { isEasingList, convertEasing } from './utils/easing.js'; | ||
| import { supports } from './utils/feature-detection.js'; | ||
| import { createCssVariableRenderer, createStyleRenderer } from './utils/apply.js'; | ||
| import { animateNumber } from '../js/animate-number.js'; | ||
| function animateValue(element, name, keyframes, options = {}) { | ||
| let { duration = 0.3, delay = 0, endDelay = 0, repeat = 0, easing = "ease", direction, offset, } = options; | ||
| const data = getAnimationData(element); | ||
| let canAnimateNatively = supports.waapi(); | ||
| let render = noop; | ||
| const valueIsTransform = isTransform(name); | ||
| keyframes = Array.isArray(keyframes) ? keyframes : [keyframes]; | ||
| /** | ||
| * If this is an individual transform, we need to map its | ||
| * key to a CSS variable and update the element's transform style | ||
| */ | ||
| if (valueIsTransform) { | ||
| if (transformAlias[name]) | ||
| name = transformAlias[name]; | ||
| addTransformToElement(element, name); | ||
| name = asTransformCssVar(name); | ||
| } | ||
| stopCurrentAnimation(data, name); | ||
| /** | ||
| * Check if this is an animation pregenerator and generate keyframes | ||
| * if so. | ||
| */ | ||
| // if (isAnimationGenerator(easing)) { | ||
| // const generatedAnimation = easing.generate(keyframes) | ||
| // easing = "linear" | ||
| // if (generatedAnimation !== false) { | ||
| // keyframes = generatedAnimation.keyframes | ||
| // duration = generatedAnimation.duration | ||
| // } | ||
| // } | ||
| /** | ||
| * Get definition of value, this will be used to convert numerical | ||
| * keyframes into the default value type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(name); | ||
| /** | ||
| * If this is a CSS variable we need to register it with the browser | ||
| * before it can be animated natively. We also set it with setProperty | ||
| * rather than directly onto the element.style object. | ||
| */ | ||
| if (isCssVar(name)) { | ||
| render = createCssVariableRenderer(element, name); | ||
| if (supports.cssRegisterProperty()) { | ||
| registerCssVariable(name); | ||
| } | ||
| else { | ||
| canAnimateNatively = false; | ||
| } | ||
| } | ||
| else { | ||
| render = createStyleRenderer(element, name); | ||
| } | ||
| /** | ||
| * If we can animate this value with WAAPI, do so. Currently this only | ||
| * feature detects CSS.registerProperty but could check WAAPI too. | ||
| */ | ||
| if (canAnimateNatively) { | ||
| /** | ||
| * Convert numbers to default value types. Currently this only supports | ||
| * transforms but it could also support other value types. | ||
| */ | ||
| if (definition) { | ||
| keyframes = keyframes.map((value) => typeof value === "number" ? definition.toDefaultUnit(value) : value); | ||
| } | ||
| if (!supports.partialKeyframes() && keyframes.length === 1) { | ||
| const initialKeyframe = isCssVar(name) | ||
| ? element.style.getPropertyValue(name) | ||
| : getComputedStyle(element)[name]; | ||
| keyframes.unshift(initialKeyframe); | ||
| } | ||
| const animationOptions = { | ||
| delay: ms(delay), | ||
| duration: ms(duration), | ||
| endDelay: ms(endDelay), | ||
| easing: !isEasingList(easing) ? convertEasing(easing) : undefined, | ||
| direction, | ||
| iterations: repeat + 1, | ||
| }; | ||
| const animation = element.animate({ | ||
| [name]: keyframes, | ||
| offset, | ||
| easing: isEasingList(easing) ? easing.map(convertEasing) : undefined, | ||
| }, animationOptions); | ||
| data.activeAnimations[name] = animation; | ||
| /** | ||
| * Polyfill finished Promise in browsers that don't support it | ||
| */ | ||
| if (!animation.finished) { | ||
| animation.finished = new Promise((resolve, reject) => { | ||
| animation.onfinish = resolve; | ||
| animation.oncancel = reject; | ||
| }); | ||
| } | ||
| const target = keyframes[keyframes.length - 1]; | ||
| animation.finished.then(() => render(target)).catch(noop); | ||
| return animation; | ||
| } | ||
| else if (valueIsTransform && keyframes.every(isNumber)) { | ||
| if (definition) { | ||
| const applyStyle = render; | ||
| render = (v) => applyStyle(definition.toDefaultUnit(v)); | ||
| } | ||
| return animateNumber(render, keyframes, options); | ||
| } | ||
| else { | ||
| const target = keyframes[keyframes.length - 1]; | ||
| render(definition && typeof target === "number" | ||
| ? definition.toDefaultUnit(target) | ||
| : target); | ||
| } | ||
| } | ||
| function stopCurrentAnimation(data, name) { | ||
| if (data.activeAnimations[name]) { | ||
| stopAnimation(data.activeAnimations[name]); | ||
| data.activeAnimations[name] = undefined; | ||
| } | ||
| } | ||
| const isNumber = (value) => typeof value === "number"; | ||
| export { animateValue }; |
| import { __rest } from 'tslib'; | ||
| import * as React from 'react'; | ||
| import { forwardRef, useRef, useContext, createElement, useMemo } from 'react'; | ||
| import { useAnimation } from './hooks/use-animation.js'; | ||
| import { useHover } from './hooks/use-hover.js'; | ||
| import { usePress } from './hooks/use-press.js'; | ||
| import { useExit } from './hooks/use-exit.js'; | ||
| import { useViewport } from './hooks/use-viewport.js'; | ||
| import { convertKeyframesToStyles } from './utils/keyframes.js'; | ||
| import { resolveVariant } from './utils/variants.js'; | ||
| import { AnimationContext } from './context.js'; | ||
| function createAnimatedComponent(Component) { | ||
| function Animated(props, _externalRef) { | ||
| // TODO: Support externalRef if provided | ||
| const ref = useRef(null); | ||
| const { options = {}, style, initial, hover, press, exit, inViewport, viewport, variants, onStart, onComplete, inherit = true } = props, forwardProps = __rest(props | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| , ["options", "style", "initial", "hover", "press", "exit", "inViewport", "viewport", "variants", "onStart", "onComplete", "inherit"]); | ||
| /** | ||
| * Track throughout the render which variants are considered active and should | ||
| * be passed to children. | ||
| */ | ||
| const isVariantActive = { initial: true, style: true }; | ||
| /** | ||
| * Inherit variants from the parent context, | ||
| */ | ||
| let inherited = useContext(AnimationContext); | ||
| if (!inherit) | ||
| inherited = {}; | ||
| const resolvedStyle = resolveVariant(style, inherited.style, variants); | ||
| const resolvedInitial = resolveVariant(initial, inherited.initial, variants); | ||
| const initialTarget = Object.assign(Object.assign({}, resolvedStyle), resolvedInitial); | ||
| const target = Object.assign(Object.assign({}, resolvedInitial), resolvedStyle); | ||
| /** | ||
| * If we haven't created a style prop for SSR yet (this is the initial render) | ||
| * make one. We provide this to React every render as beyond that with manage style | ||
| * via animations. | ||
| */ | ||
| const styleProp = useRef(null); | ||
| styleProp.current || (styleProp.current = convertKeyframesToStyles(initialTarget)); | ||
| /** | ||
| * Attach animation event handlers (gestures/exit/viewport appearance). | ||
| * This are called in reverse order of which styles should take priority when | ||
| * active, for example if there's a hover and press gesture active the press | ||
| * gesture will take precedence. | ||
| */ | ||
| const hoverProps = useHover(target, props, inherited, isVariantActive); | ||
| const pressProps = usePress(target, props, inherited, isVariantActive); | ||
| useViewport(ref, target, props, inherited, isVariantActive); | ||
| const onExitComplete = useExit(target, props, inherited); | ||
| /** | ||
| * Compare our final calculated style target with the one from the previous render | ||
| * and trigger any necessary animations. | ||
| */ | ||
| useAnimation(ref, initialTarget, target, options, onStart, (animation) => { | ||
| onComplete && onComplete(animation); | ||
| onExitComplete && onExitComplete(); | ||
| }); | ||
| const element = createElement(Component, Object.assign({}, forwardProps, hoverProps, pressProps, { | ||
| style: styleProp.current, | ||
| ref, | ||
| })); | ||
| /** | ||
| * Create a variant context to pass forward to child components. | ||
| */ | ||
| const context = variantProps.reduce((acc, key) => { | ||
| acc[key] = undefined; | ||
| if (props[key]) { | ||
| if (typeof props[key] === "string" && isVariantActive[key]) { | ||
| acc[key] = props[key]; | ||
| } | ||
| } | ||
| else if (inherited[key]) { | ||
| acc[key] = inherited[key]; | ||
| } | ||
| return acc; | ||
| }, {}); | ||
| /** | ||
| * Memoize the context so we only trigger a re-render in children if the values | ||
| * within it change. | ||
| */ | ||
| const memoizedContext = useMemo(() => context, Object.values(context)); | ||
| return (React.createElement(AnimationContext.Provider, { value: memoizedContext }, element)); | ||
| } | ||
| return forwardRef(Animated); | ||
| } | ||
| const variantProps = [ | ||
| "initial", | ||
| "style", | ||
| "hover", | ||
| "press", | ||
| "inViewport", | ||
| "exit", | ||
| ]; | ||
| export { createAnimatedComponent }; |
| import { createContext } from 'react'; | ||
| const AnimationContext = createContext({}); | ||
| export { AnimationContext }; |
| import { useRef, useEffect } from 'react'; | ||
| import { animateValue } from '../../dom/animate-value.js'; | ||
| import { noop } from '../../../utils/noop.js'; | ||
| import { hasChanged } from '../utils/has-changed.js'; | ||
| function useAnimation(ref, initial, target, options, onStart, onComplete) { | ||
| const prevTarget = useRef(initial); | ||
| useEffect(() => { | ||
| const targetKeyframe = {}; | ||
| const allKeys = new Set([ | ||
| ...Object.keys(target), | ||
| ...Object.keys(prevTarget.current), | ||
| ]); | ||
| allKeys.forEach((key) => { | ||
| let next = target[key]; | ||
| if (!hasChanged(next, prevTarget.current[key])) | ||
| return; | ||
| /** | ||
| * TODO: If next is undefined, throw error or record a "base value" | ||
| * to animate back down to | ||
| */ | ||
| targetKeyframe[key] = next; | ||
| }); | ||
| if (Object.keys(targetKeyframe).length && ref.current) { | ||
| onStart === null || onStart === void 0 ? void 0 : onStart(targetKeyframe); | ||
| const animations = []; | ||
| for (const key in targetKeyframe) { | ||
| const animation = animateValue(ref.current, key, targetKeyframe[key], options); | ||
| animation && animations.push(animation); | ||
| } | ||
| Promise.all(animations.map((animation) => animation.finished)) | ||
| .then(() => onComplete === null || onComplete === void 0 ? void 0 : onComplete(targetKeyframe)) | ||
| .catch(noop); | ||
| } | ||
| prevTarget.current = target; | ||
| }); | ||
| } | ||
| export { useAnimation }; |
| import { usePresence } from 'framer-motion'; | ||
| import { useEffect } from 'react'; | ||
| import { resolveVariant } from '../utils/variants.js'; | ||
| function useExit(target, { exit, variants }, { exit: inheritedExit }) { | ||
| const [isPresent, onExitComplete] = usePresence(); | ||
| /** | ||
| * In case we don't have an exit animation defined we still need to | ||
| * call onExitComplete if it exits so AnimatePresence knows it | ||
| * can remove this component. | ||
| */ | ||
| useEffect(() => { | ||
| if (!exit) | ||
| onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete(); | ||
| }, [isPresent]); | ||
| if (exit && !isPresent) { | ||
| Object.assign(target, resolveVariant(exit, inheritedExit, variants)); | ||
| return onExitComplete; | ||
| } | ||
| } | ||
| export { useExit }; |
| import { useState } from 'react'; | ||
| import { resolveVariant } from '../utils/variants.js'; | ||
| function useGestureState(target, stylesToApply, inheritedVariant, variants) { | ||
| const [isGestureActive, setGestureState] = useState(false); | ||
| if (isGestureActive || inheritedVariant) { | ||
| Object.assign(target, resolveVariant(stylesToApply, inheritedVariant, variants)); | ||
| } | ||
| return [isGestureActive || Boolean(inheritedVariant), setGestureState]; | ||
| } | ||
| export { useGestureState }; |
| import { useGestureState } from './use-gesture-state.js'; | ||
| function useHover(target, { hover, onPointerEnter, onPointerLeave, variants, } = {}, { hover: inheritedHover }, isVariantActive) { | ||
| const [isHoverActive, setHoverState] = useGestureState(target, hover, inheritedHover, variants); | ||
| isVariantActive.hover = isHoverActive; | ||
| return hover | ||
| ? { | ||
| onPointerEnter: (e) => { | ||
| onPointerEnter === null || onPointerEnter === void 0 ? void 0 : onPointerEnter(e); | ||
| setHoverState(true); | ||
| }, | ||
| onPointerLeave: (e) => { | ||
| onPointerLeave === null || onPointerLeave === void 0 ? void 0 : onPointerLeave(e); | ||
| setHoverState(false); | ||
| }, | ||
| } | ||
| : {}; | ||
| } | ||
| export { useHover }; |
| import { useGestureState } from './use-gesture-state.js'; | ||
| function usePress(target, { press, onPointerDown, variants } = {}, { press: inheritedPress }, isVariantActive) { | ||
| const [isPressActive, setPressState] = useGestureState(target, press, inheritedPress, variants); | ||
| isVariantActive.press = isPressActive; | ||
| if (!press) | ||
| return {}; | ||
| const onPointerUp = () => { | ||
| setPressState(false); | ||
| window.removeEventListener("pointerup", onPointerUp); | ||
| }; | ||
| return { | ||
| onPointerDown: (e) => { | ||
| onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(e); | ||
| setPressState(true); | ||
| window.addEventListener("pointerup", onPointerUp); | ||
| }, | ||
| }; | ||
| } | ||
| export { usePress }; |
| import { useEffect } from 'react'; | ||
| import { useGestureState } from './use-gesture-state.js'; | ||
| function useViewport(ref, target, { inViewport, variants, viewport = {}, onViewportEnter, onViewportLeave, }, { inViewport: inheritedInViewport }, isVariantActive) { | ||
| const { root, margin: rootMargin, once, threshold } = viewport; | ||
| const [isInViewport, setViewportState] = useGestureState(target, inViewport, inheritedInViewport, variants); | ||
| isVariantActive.inViewport = isInViewport; | ||
| let shouldObserve = !!inViewport || !!onViewportEnter || !!onViewportLeave; | ||
| if (once && isInViewport) | ||
| shouldObserve = false; | ||
| useEffect(() => { | ||
| if (!shouldObserve || typeof IntersectionObserver === "undefined") | ||
| return; | ||
| const observer = new IntersectionObserver(([entry]) => { | ||
| setViewportState(entry.isIntersecting); | ||
| const callback = entry.isIntersecting | ||
| ? onViewportEnter | ||
| : onViewportLeave; | ||
| callback && callback(entry); | ||
| }, { root: root === null || root === void 0 ? void 0 : root.current, rootMargin, threshold }); | ||
| observer.observe(ref.current); | ||
| return () => observer.disconnect(); | ||
| }, [ | ||
| inViewport, | ||
| onViewportEnter, | ||
| onViewportLeave, | ||
| root, | ||
| rootMargin, | ||
| threshold, | ||
| ]); | ||
| } | ||
| export { useViewport }; |
| import { createAnimatedComponent } from './animated.js'; | ||
| const components = new Map(); | ||
| const animated = new Proxy({}, { | ||
| get: (_, key) => { | ||
| if (!components.has(key)) { | ||
| components.set(key, createAnimatedComponent(key)); | ||
| } | ||
| return components.get(key); | ||
| }, | ||
| }); | ||
| export { animated }; |
| function hasChanged(a, b) { | ||
| if (typeof a !== typeof b) | ||
| return true; | ||
| if (Array.isArray(a) && Array.isArray(b)) | ||
| return !shallowCompare(a, b); | ||
| return a !== b; | ||
| } | ||
| function shallowCompare(next, prev) { | ||
| const prevLength = prev.length; | ||
| if (prevLength !== next.length) | ||
| return false; | ||
| for (let i = 0; i < prevLength; i++) { | ||
| if (prev[i] !== next[i]) | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| export { hasChanged, shallowCompare }; |
| import { isTransform, transformAlias, asTransformCssVar, transformPropertyDefinitions, buildTransformTemplate } from '../../dom/utils/transforms.js'; | ||
| function convertKeyframesToStyles(keyframes) { | ||
| const initialKeyframes = {}; | ||
| const transformKeys = []; | ||
| for (let key in keyframes) { | ||
| const value = keyframes[key]; | ||
| if (isTransform(key)) { | ||
| if (transformAlias[key]) | ||
| key = transformAlias[key]; | ||
| transformKeys.push(key); | ||
| key = asTransformCssVar(key); | ||
| } | ||
| let initialKeyframe = Array.isArray(value) ? value[0] : value; | ||
| /** | ||
| * If this is a number and we have a default value type, convert the number | ||
| * to this type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(key); | ||
| if (definition) { | ||
| initialKeyframe = | ||
| typeof value === "number" ? definition.toDefaultUnit(value) : value; | ||
| } | ||
| initialKeyframes[key] = initialKeyframe; | ||
| } | ||
| if (transformKeys.length) { | ||
| initialKeyframes.transform = buildTransformTemplate(transformKeys); | ||
| } | ||
| return initialKeyframes; | ||
| } | ||
| export { convertKeyframesToStyles }; |
| function resolveVariant(definition, inheritedDefinition, variants = {}) { | ||
| if (definition) { | ||
| return typeof definition === "string" ? variants[definition] : definition; | ||
| } | ||
| else if (inheritedDefinition) { | ||
| return variants[inheritedDefinition]; | ||
| } | ||
| } | ||
| export { resolveVariant }; |
| import { AnimationData, getAnimationData } from "./data" | ||
| import { AnimationOptions, AnimationWithCommitStyles } from "./types" | ||
| import { isCssVar, registerCssVariable } from "./utils/css-var" | ||
| import { noop } from "../../utils/noop" | ||
| import { ms } from "./utils/time" | ||
| import { | ||
| addTransformToElement, | ||
| asTransformCssVar, | ||
| isTransform, | ||
| transformAlias, | ||
| transformPropertyDefinitions, | ||
| } from "./utils/transforms" | ||
| import { stopAnimation } from "./utils/stop-animation" | ||
| import { convertEasing, isEasingList } from "./utils/easing" | ||
| import { supports } from "./utils/feature-detection" | ||
| import { createCssVariableRenderer, createStyleRenderer } from "./utils/apply" | ||
| import { animateNumber } from "../js/animate-number" | ||
| export function animateValue( | ||
| element: Element, | ||
| name: string, | ||
| keyframes: string | number | Array<string | number>, | ||
| options: AnimationOptions = {} | ||
| ) { | ||
| let { | ||
| duration = 0.3, | ||
| delay = 0, | ||
| endDelay = 0, | ||
| repeat = 0, | ||
| easing = "ease", | ||
| direction, | ||
| offset, | ||
| } = options | ||
| const data = getAnimationData(element) | ||
| let canAnimateNatively = supports.waapi() | ||
| let render: (v: any) => void = noop | ||
| const valueIsTransform = isTransform(name) | ||
| keyframes = Array.isArray(keyframes) ? keyframes : [keyframes] | ||
| /** | ||
| * If this is an individual transform, we need to map its | ||
| * key to a CSS variable and update the element's transform style | ||
| */ | ||
| if (valueIsTransform) { | ||
| if (transformAlias[name]) name = transformAlias[name] | ||
| addTransformToElement(element as HTMLElement, name) | ||
| name = asTransformCssVar(name) | ||
| } | ||
| stopCurrentAnimation(data, name) | ||
| /** | ||
| * Check if this is an animation pregenerator and generate keyframes | ||
| * if so. | ||
| */ | ||
| // if (isAnimationGenerator(easing)) { | ||
| // const generatedAnimation = easing.generate(keyframes) | ||
| // easing = "linear" | ||
| // if (generatedAnimation !== false) { | ||
| // keyframes = generatedAnimation.keyframes | ||
| // duration = generatedAnimation.duration | ||
| // } | ||
| // } | ||
| /** | ||
| * Get definition of value, this will be used to convert numerical | ||
| * keyframes into the default value type. | ||
| */ | ||
| const definition = transformPropertyDefinitions.get(name) | ||
| /** | ||
| * If this is a CSS variable we need to register it with the browser | ||
| * before it can be animated natively. We also set it with setProperty | ||
| * rather than directly onto the element.style object. | ||
| */ | ||
| if (isCssVar(name)) { | ||
| render = createCssVariableRenderer(element, name) | ||
| if (supports.cssRegisterProperty()) { | ||
| registerCssVariable(name) | ||
| } else { | ||
| canAnimateNatively = false | ||
| } | ||
| } else { | ||
| render = createStyleRenderer(element, name) | ||
| } | ||
| /** | ||
| * If we can animate this value with WAAPI, do so. Currently this only | ||
| * feature detects CSS.registerProperty but could check WAAPI too. | ||
| */ | ||
| if (canAnimateNatively) { | ||
| /** | ||
| * Convert numbers to default value types. Currently this only supports | ||
| * transforms but it could also support other value types. | ||
| */ | ||
| if (definition) { | ||
| keyframes = keyframes.map((value) => | ||
| typeof value === "number" ? definition.toDefaultUnit!(value) : value | ||
| ) | ||
| } | ||
| if (!supports.partialKeyframes() && keyframes.length === 1) { | ||
| const initialKeyframe = isCssVar(name) | ||
| ? (element as HTMLElement).style.getPropertyValue(name) | ||
| : getComputedStyle(element)[name] | ||
| keyframes.unshift(initialKeyframe) | ||
| } | ||
| const animationOptions = { | ||
| delay: ms(delay), | ||
| duration: ms(duration), | ||
| endDelay: ms(endDelay), | ||
| easing: !isEasingList(easing) ? convertEasing(easing) : undefined, | ||
| direction, | ||
| iterations: repeat + 1, | ||
| } | ||
| const animation = element.animate( | ||
| { | ||
| [name]: keyframes, | ||
| offset, | ||
| easing: isEasingList(easing) ? easing.map(convertEasing) : undefined, | ||
| } as PropertyIndexedKeyframes, | ||
| animationOptions | ||
| ) as AnimationWithCommitStyles | ||
| data.activeAnimations[name] = animation | ||
| /** | ||
| * Polyfill finished Promise in browsers that don't support it | ||
| */ | ||
| if (!animation.finished) { | ||
| ;(animation as any).finished = new Promise((resolve, reject) => { | ||
| animation.onfinish = resolve | ||
| animation.oncancel = reject | ||
| }) | ||
| } | ||
| const target = keyframes[keyframes.length - 1] | ||
| animation.finished.then(() => render(target)).catch(noop) | ||
| return animation | ||
| } else if (valueIsTransform && keyframes.every(isNumber)) { | ||
| if (definition) { | ||
| const applyStyle = render | ||
| render = (v: number) => applyStyle(definition.toDefaultUnit(v)) | ||
| } | ||
| return animateNumber(render, keyframes, options) | ||
| } else { | ||
| const target = keyframes[keyframes.length - 1] | ||
| render( | ||
| definition && typeof target === "number" | ||
| ? definition.toDefaultUnit(target) | ||
| : target | ||
| ) | ||
| } | ||
| } | ||
| function stopCurrentAnimation(data: AnimationData, name: string) { | ||
| if (data.activeAnimations[name]) { | ||
| stopAnimation(data.activeAnimations[name]!) | ||
| data.activeAnimations[name] = undefined | ||
| } | ||
| } | ||
| const isNumber = (value: string | number): value is number => | ||
| typeof value === "number" |
| import { | ||
| pointerDown, | ||
| pointerUp, | ||
| pointerEnter, | ||
| pointerLeave, | ||
| render, | ||
| } from "../../../../jest.setup" | ||
| import "../../dom/__tests__/web-animations.min-edited" | ||
| import * as React from "react" | ||
| import { animated } from "../index" | ||
| console.error = jest.fn() | ||
| const duration = 0.001 | ||
| describe("Variants", () => { | ||
| test("Components will animate from initial -> style on mount", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("child")).toHaveStyle("transform: scale(2)") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="hidden" | ||
| style="visible" | ||
| variants={{ | ||
| hidden: { opacity: 0 }, | ||
| visible: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| hidden: { transform: "none" }, | ||
| visible: { transform: "scale(2)" }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| hidden: { transform: "none" }, | ||
| visible: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate when the contents of the style variant changes", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("opacity: 1") | ||
| resolve(true) | ||
| } | ||
| const Component = ({ opacity }: { opacity: number }) => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| variants={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| a: { opacity: 0.75 }, | ||
| b: { opacity }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component opacity={0.5} />) | ||
| rerender(<Component opacity={1} />) | ||
| rerender(<Component opacity={1} />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate when the name of the style variant changes", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 0.5") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = ({ style }: { style: string }) => ( | ||
| <animated.div | ||
| initial="a" | ||
| style={style} | ||
| variants={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component style="b" />) | ||
| rerender(<Component style="c" />) | ||
| rerender(<Component style="c" />) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate to hover variant when hover starts", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 0.5") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| hover="c" | ||
| variants={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerEnter(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate from hover variant when hover end", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle( | ||
| "opacity: 1; transform: scale(1)" | ||
| ) | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 0.75") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: none") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| hover="c" | ||
| variants={{ | ||
| a: { opacity: 0, transform: "scale(1)" }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5, transform: "scale(2)" }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerEnter(getByTestId("parent") as Element) | ||
| pointerLeave(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 100) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate to press variant when press starts", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle("opacity: 0.5") | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 1") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: scale(0.5)") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| press="c" | ||
| variants={{ | ||
| a: { opacity: 0 }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5 }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerDown(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| test("Components will animate from press variant when press end", async () => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const onComplete = () => { | ||
| expect(getByTestId("parent")).toHaveStyle( | ||
| "opacity: 1; transform: scale(1)" | ||
| ) | ||
| expect(getByTestId("child")).toHaveStyle("opacity: 0.75") | ||
| expect(getByTestId("grandchild")).toHaveStyle("transform: none") | ||
| resolve(true) | ||
| } | ||
| const Component = () => ( | ||
| <animated.div | ||
| initial="a" | ||
| style="b" | ||
| press="c" | ||
| variants={{ | ||
| a: { opacity: 0, transform: "scale(1)" }, | ||
| b: { opacity: 1 }, | ||
| c: { opacity: 0.5, transform: "scale(2)" }, | ||
| }} | ||
| options={{ duration }} | ||
| onComplete={() => onComplete()} | ||
| data-testid="parent" | ||
| > | ||
| <animated.div | ||
| variants={{ | ||
| a: { opacity: 0.5 }, | ||
| b: { opacity: 0.75 }, | ||
| c: { opacity: 1 }, | ||
| }} | ||
| options={{ duration }} | ||
| data-testid="child" | ||
| > | ||
| <animated.div | ||
| data-testid="grandchild" | ||
| variants={{ | ||
| b: { transform: "none" }, | ||
| c: { transform: "scale(0.5)" }, | ||
| }} | ||
| options={{ duration }} | ||
| /> | ||
| </animated.div> | ||
| </animated.div> | ||
| ) | ||
| const { rerender, getByTestId } = render(<Component />) | ||
| rerender(<Component />) | ||
| pointerDown(getByTestId("parent") as Element) | ||
| pointerUp(getByTestId("parent") as Element) | ||
| setTimeout(() => reject(false), 50) | ||
| }) | ||
| return expect(promise).resolves.toEqual(true) | ||
| }) | ||
| }) |
| import { MotionKeyframes } from "../../dom/types" | ||
| import { Variants } from "../types" | ||
| export function resolveVariant( | ||
| definition?: MotionKeyframes | string, | ||
| inheritedDefinition?: string, | ||
| variants: Variants = {} | ||
| ): MotionKeyframes | undefined { | ||
| if (definition) { | ||
| return typeof definition === "string" ? variants[definition] : definition | ||
| } else if (inheritedDefinition) { | ||
| return variants[inheritedDefinition] | ||
| } | ||
| } |
| import { AnimationOptions, AnimationWithCommitStyles } from "./types"; | ||
| export declare function animateValue(element: Element, name: string, keyframes: string | number | Array<string | number>, options?: AnimationOptions): AnimationWithCommitStyles | import("../js/animate-number").Animation | undefined; |
| import { MotionKeyframes } from "../../dom/types"; | ||
| import { Variants } from "../types"; | ||
| export declare function resolveVariant(definition?: MotionKeyframes | string, inheritedDefinition?: string, variants?: Variants): MotionKeyframes | undefined; |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
12
-7.69%325361
-10.41%132
-7.04%8802
-8.54%