From 7d304f8109e7d24044aee2b76b9c7c36a8bdfb63 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Fri, 17 Mar 2023 16:41:06 +0100 Subject: [PATCH] `.stop()` applies permanently (#2030) * Stopping animations permanenently * Fix * Updating --- .../animators/js/__tests__/animate.test.ts | 24 +++++++++++++++++++ .../src/animation/animators/js/index.ts | 4 ++++ .../waapi/create-accelerated-animation.ts | 7 +++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/framer-motion/src/animation/animators/js/__tests__/animate.test.ts b/packages/framer-motion/src/animation/animators/js/__tests__/animate.test.ts index 44e84923fb..ddc5ef8290 100644 --- a/packages/framer-motion/src/animation/animators/js/__tests__/animate.test.ts +++ b/packages/framer-motion/src/animation/animators/js/__tests__/animate.test.ts @@ -1002,6 +1002,30 @@ describe("animate", () => { expect(output).toEqual([0, 20, 40, 60, 80, 100, 0, 20, 40, 60, 80, 100]) }) + test(".play() doesn't start the animation if it has been manually stopped", async () => { + const driver = syncDriver(20) + const output: number[] = [] + const animation = animateValue({ + keyframes: [0, 100], + duration: 100, + ease: "linear", + onUpdate: (v) => { + output.push(Math.round(v)) + + if (output.length === 5) animation.stop() + }, + driver, + }) + + await nextFrame() + + animation.play() + + await nextFrame() + + expect(output).toEqual([0, 20, 40, 60, 80]) + }) + test(".then() can be chained", async () => { return new Promise(async (resolve) => { const animation = animateValue({ diff --git a/packages/framer-motion/src/animation/animators/js/index.ts b/packages/framer-motion/src/animation/animators/js/index.ts index 80a26f51c2..3489cbffb4 100644 --- a/packages/framer-motion/src/animation/animators/js/index.ts +++ b/packages/framer-motion/src/animation/animators/js/index.ts @@ -70,6 +70,7 @@ export function animateValue({ }: AnimationOptions): MainThreadAnimationControls { let speed = 1 + let hasStopped = false let resolveFinishedPromise: VoidFunction let currentFinishedPromise: Promise @@ -271,6 +272,8 @@ export function animateValue({ } const play = () => { + if (hasStopped) return + if (!animationDriver) animationDriver = driver(tick) const now = animationDriver.now() @@ -331,6 +334,7 @@ export function animateValue({ holdTime = time }, stop: () => { + hasStopped = true if (playState === "idle") return playState = "idle" onStop && onStop() diff --git a/packages/framer-motion/src/animation/animators/waapi/create-accelerated-animation.ts b/packages/framer-motion/src/animation/animators/waapi/create-accelerated-animation.ts index 4b95e5eed5..d8d5c88ad9 100644 --- a/packages/framer-motion/src/animation/animators/waapi/create-accelerated-animation.ts +++ b/packages/framer-motion/src/animation/animators/waapi/create-accelerated-animation.ts @@ -63,6 +63,7 @@ export function createAcceleratedAnimation( /** * TODO: Unify with js/index */ + let hasStopped = false let resolveFinishedPromise: VoidFunction let currentFinishedPromise: Promise @@ -168,9 +169,13 @@ export function createAcceleratedAnimation( set speed(newSpeed: number) { animation.playbackRate = newSpeed }, - play: () => animation.play(), + play: () => { + if (hasStopped) return + animation.play() + }, pause: () => animation.pause(), stop: () => { + hasStopped = true if (animation.playState === "idle") return /**