From 8dafa2902bf4eab5faabd247b1a8a82c3a0825c1 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 28 Jan 2026 13:56:17 +0100 Subject: [PATCH 1/7] Fix shared element animations when animate() called before animateLayout() When animate() is called on an element before animateLayout(), the VisualElement gets mounted but the projection does not. This causes registerSharedNode() to never be called, breaking shared element animations. The fix explicitly mounts the projection when the VisualElement is already mounted but the projection isn't. Co-Authored-By: Claude Opus 4.5 --- .../modal-open-after-animate.html | 243 ++++++++++++++++++ .../fixtures/animate-layout-tests.json | 2 +- .../src/layout/LayoutAnimationBuilder.ts | 4 + tests/animate-layout/animate-layout.spec.ts | 31 +++ 4 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 dev/html/public/animate-layout/modal-open-after-animate.html create mode 100644 tests/animate-layout/animate-layout.spec.ts diff --git a/dev/html/public/animate-layout/modal-open-after-animate.html b/dev/html/public/animate-layout/modal-open-after-animate.html new file mode 100644 index 0000000000..ce99e5f8ff --- /dev/null +++ b/dev/html/public/animate-layout/modal-open-after-animate.html @@ -0,0 +1,243 @@ + + + + + + + + + + + + diff --git a/packages/framer-motion/cypress/fixtures/animate-layout-tests.json b/packages/framer-motion/cypress/fixtures/animate-layout-tests.json index b7090502f4..35a130ed29 100644 --- a/packages/framer-motion/cypress/fixtures/animate-layout-tests.json +++ b/packages/framer-motion/cypress/fixtures/animate-layout-tests.json @@ -1 +1 @@ -["app-store-a-b-a.html","basic-position-change.html","interrupt-animation.html","modal-open-close-interrupt.html","modal-open-close-open-interrupt.html","modal-open-close-open.html","modal-open-close.html","modal-open-opacity.html","modal-open.html","repeat-animation.html","scale-correction.html","scope-with-data-layout.html","shared-element-a-ab-a.html","shared-element-a-b-a-replace.html","shared-element-a-b-a-reuse.html","shared-element-basic.html","shared-element-configured.html","shared-element-crossfade.html","shared-element-nested-children-bottom.html","shared-element-nested-children.html","shared-element-no-crossfade.html","shared-multiple-elements.html"] \ No newline at end of file +["app-store-a-b-a.html","basic-position-change.html","interrupt-animation.html","modal-open-after-animate.html","modal-open-close-interrupt.html","modal-open-close-open-interrupt.html","modal-open-close-open.html","modal-open-close.html","modal-open-opacity.html","modal-open.html","repeat-animation.html","scale-correction.html","scope-with-data-layout.html","shared-element-a-ab-a.html","shared-element-a-b-a-replace.html","shared-element-a-b-a-reuse.html","shared-element-basic.html","shared-element-configured.html","shared-element-crossfade.html","shared-element-nested-children-bottom.html","shared-element-nested-children.html","shared-element-no-crossfade.html","shared-multiple-elements.html"] \ No newline at end of file diff --git a/packages/motion-dom/src/layout/LayoutAnimationBuilder.ts b/packages/motion-dom/src/layout/LayoutAnimationBuilder.ts index 3a802fd021..929c16f9dc 100644 --- a/packages/motion-dom/src/layout/LayoutAnimationBuilder.ts +++ b/packages/motion-dom/src/layout/LayoutAnimationBuilder.ts @@ -330,6 +330,10 @@ function getOrCreateRecord( if (!visualElement.current) { visualElement.mount(element as HTMLElement) + } else if (!visualElement.projection.instance) { + // Mount projection if VisualElement is already mounted but projection isn't + // This happens when animate() was called before animateLayout() + visualElement.projection.mount(element as HTMLElement) } if (!existing) { diff --git a/tests/animate-layout/animate-layout.spec.ts b/tests/animate-layout/animate-layout.spec.ts new file mode 100644 index 0000000000..29ea2c02fa --- /dev/null +++ b/tests/animate-layout/animate-layout.spec.ts @@ -0,0 +1,31 @@ +import { expect, test } from "@playwright/test" + +test.describe("animateLayout()", () => { + test("shared element animation works when animate() is called before animateLayout()", async ({ + page, + }) => { + await page.goto("animate-layout/modal-open-after-animate.html") + + // Wait for the test script to run + await page.waitForTimeout(500) + + // Check that no elements have data-layout-correct="false" (which would indicate test failure) + const failedElements = await page + .locator('[data-layout-correct="false"]') + .count() + expect(failedElements).toBe(0) + }) + + test("original modal-open test still works", async ({ page }) => { + await page.goto("animate-layout/modal-open.html") + + // Wait for the test script to run + await page.waitForTimeout(500) + + // Check that no elements have data-layout-correct="false" + const failedElements = await page + .locator('[data-layout-correct="false"]') + .count() + expect(failedElements).toBe(0) + }) +}) From 3dffb405794e614ccb59680eddd5f17c3832ee1b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Feb 2026 07:04:39 +0000 Subject: [PATCH 2/7] feat(MotionConfig): add skipAnimations prop for E2E and visual regression testing This adds the ability to skip all animations within a component tree by wrapping it with . This is useful for E2E tests and visual regression testing where animations should complete instantly. The implementation mirrors the existing reducedMotion pattern: - Added skipAnimations to MotionConfigContext interface - Added skipAnimations to VisualElementOptions - Added shouldSkipAnimations property to VisualElement - Updated animateMotionValue to check element?.shouldSkipAnimations This provides a React-friendly alternative to the global MotionGlobalConfig.skipAnimations, allowing tree-scoped animation skipping. Closes #3514 https://claude.ai/code/session_01A87hrNZPSrAajiuoEkGu86 --- .../MotionConfig/__tests__/index.test.tsx | 104 ++++++++++++++++++ .../src/components/MotionConfig/index.tsx | 1 + .../src/context/MotionConfigContext.tsx | 8 ++ .../src/motion/utils/use-visual-element.ts | 5 +- packages/framer-motion/src/render/types.ts | 5 + .../src/animation/interfaces/motion-value.ts | 3 +- .../motion-dom/src/render/VisualElement.ts | 18 +++ packages/motion-dom/src/render/types.ts | 13 +++ 8 files changed, 155 insertions(+), 2 deletions(-) diff --git a/packages/framer-motion/src/components/MotionConfig/__tests__/index.test.tsx b/packages/framer-motion/src/components/MotionConfig/__tests__/index.test.tsx index 0e0fc24dad..34e549285c 100644 --- a/packages/framer-motion/src/components/MotionConfig/__tests__/index.test.tsx +++ b/packages/framer-motion/src/components/MotionConfig/__tests__/index.test.tsx @@ -75,3 +75,107 @@ describe("reducedMotion", () => { expect(result[1]).not.toEqual(1) }) }) + +describe("skipAnimations", () => { + test("skipAnimations makes all animations complete instantly", async () => { + const result = await new Promise<[number, number]>(async (resolve) => { + const x = motionValue(0) + const opacity = motionValue(0) + const Component = () => { + return ( + + + + ) + } + + const { rerender } = render() + rerender() + + await nextFrame() + + resolve([x.get(), opacity.get()]) + }) + + // Both transform and non-transform values should complete instantly + expect(result[0]).toEqual(100) + expect(result[1]).toEqual(1) + }) + + test("skipAnimations=false does not skip animations", async () => { + const result = await new Promise<[number, number]>(async (resolve) => { + const x = motionValue(0) + const opacity = motionValue(0) + const Component = () => { + return ( + + + + ) + } + + const { rerender } = render() + rerender() + + await nextFrame() + + resolve([x.get(), opacity.get()]) + }) + + // Values should still be animating (not yet at final value) + expect(result[0]).not.toEqual(100) + expect(result[1]).not.toEqual(1) + }) + + test("skipAnimations is scoped to component tree", async () => { + const result = await new Promise<[number, number, number, number]>( + async (resolve) => { + const x1 = motionValue(0) + const opacity1 = motionValue(0) + const x2 = motionValue(0) + const opacity2 = motionValue(0) + + const Component = () => { + return ( + <> + + + + + + ) + } + + const { rerender } = render() + rerender() + + await nextFrame() + + resolve([x1.get(), opacity1.get(), x2.get(), opacity2.get()]) + } + ) + + // Inside MotionConfig with skipAnimations - should be instant + expect(result[0]).toEqual(100) + expect(result[1]).toEqual(1) + // Outside MotionConfig - should still be animating + expect(result[2]).not.toEqual(100) + expect(result[3]).not.toEqual(1) + }) +}) diff --git a/packages/framer-motion/src/components/MotionConfig/index.tsx b/packages/framer-motion/src/components/MotionConfig/index.tsx index d669225c3b..ead6133680 100644 --- a/packages/framer-motion/src/components/MotionConfig/index.tsx +++ b/packages/framer-motion/src/components/MotionConfig/index.tsx @@ -59,6 +59,7 @@ export function MotionConfig({ JSON.stringify(config.transition), config.transformPagePoint, config.reducedMotion, + config.skipAnimations, ] ) diff --git a/packages/framer-motion/src/context/MotionConfigContext.tsx b/packages/framer-motion/src/context/MotionConfigContext.tsx index d8b7b37f25..a527e48f72 100644 --- a/packages/framer-motion/src/context/MotionConfigContext.tsx +++ b/packages/framer-motion/src/context/MotionConfigContext.tsx @@ -44,6 +44,14 @@ export interface MotionConfigContext { * @public */ nonce?: string + + /** + * If true, all animations will be skipped and values will be set instantly. + * Useful for E2E tests and visual regression testing. + * + * @public + */ + skipAnimations?: boolean } /** diff --git a/packages/framer-motion/src/motion/utils/use-visual-element.ts b/packages/framer-motion/src/motion/utils/use-visual-element.ts index cd5f081516..5fe5e3a2a1 100644 --- a/packages/framer-motion/src/motion/utils/use-visual-element.ts +++ b/packages/framer-motion/src/motion/utils/use-visual-element.ts @@ -40,7 +40,9 @@ export function useVisualElement< const { visualElement: parent } = useContext(MotionContext) const lazyContext = useContext(LazyContext) const presenceContext = useContext(PresenceContext) - const reducedMotionConfig = useContext(MotionConfigContext).reducedMotion + const motionConfig = useContext(MotionConfigContext) + const reducedMotionConfig = motionConfig.reducedMotion + const skipAnimations = motionConfig.skipAnimations const visualElementRef = useRef { props: MotionProps blockInitialAnimation?: boolean reducedMotionConfig?: ReducedMotionConfig + /** + * If true, all animations will be skipped and values will be set instantly. + * Useful for E2E tests and visual regression testing. + */ + skipAnimations?: boolean /** * Explicit override for SVG detection. When true, uses SVG rendering; * when false, uses HTML rendering. If undefined, auto-detects. diff --git a/packages/motion-dom/src/animation/interfaces/motion-value.ts b/packages/motion-dom/src/animation/interfaces/motion-value.ts index 319c2713cb..db9a80f670 100644 --- a/packages/motion-dom/src/animation/interfaces/motion-value.ts +++ b/packages/motion-dom/src/animation/interfaces/motion-value.ts @@ -99,7 +99,8 @@ export const animateMotionValue = if ( MotionGlobalConfig.instantAnimations || - MotionGlobalConfig.skipAnimations + MotionGlobalConfig.skipAnimations || + element?.shouldSkipAnimations ) { shouldSkip = true makeAnimationInstant(options) diff --git a/packages/motion-dom/src/render/VisualElement.ts b/packages/motion-dom/src/render/VisualElement.ts index 2106ec7741..deb8877ff8 100644 --- a/packages/motion-dom/src/render/VisualElement.ts +++ b/packages/motion-dom/src/render/VisualElement.ts @@ -252,6 +252,12 @@ export abstract class VisualElement< */ shouldReduceMotion: boolean | null = null + /** + * Decides whether animations should be skipped for this VisualElement. + * Useful for E2E tests and visual regression testing. + */ + shouldSkipAnimations: boolean = false + /** * Normally, if a component is controlled by a parent's variants, it can * rely on that ancestor to trigger animations further down the tree. @@ -320,6 +326,11 @@ export abstract class VisualElement< */ private reducedMotionConfig: ReducedMotionConfig | undefined + /** + * A reference to the skipAnimations config passed to the VisualElement's host React component. + */ + private skipAnimationsConfig: boolean | undefined + /** * On mount, this will be hydrated with a callback to disconnect * this visual element from its parent on unmount. @@ -366,6 +377,7 @@ export abstract class VisualElement< props, presenceContext, reducedMotionConfig, + skipAnimations, blockInitialAnimation, visualState, }: VisualElementOptions, @@ -381,6 +393,7 @@ export abstract class VisualElement< this.presenceContext = presenceContext this.depth = parent ? parent.depth + 1 : 0 this.reducedMotionConfig = reducedMotionConfig + this.skipAnimationsConfig = skipAnimations this.options = options this.blockInitialAnimation = Boolean(blockInitialAnimation) @@ -453,6 +466,11 @@ export abstract class VisualElement< ) } + /** + * Set whether animations should be skipped based on the config. + */ + this.shouldSkipAnimations = this.skipAnimationsConfig ?? false + this.parent?.addChild(this) this.update(this.props, this.presenceContext) diff --git a/packages/motion-dom/src/render/types.ts b/packages/motion-dom/src/render/types.ts index 23e091391f..137de259f3 100644 --- a/packages/motion-dom/src/render/types.ts +++ b/packages/motion-dom/src/render/types.ts @@ -66,6 +66,14 @@ export interface MotionConfigContextProps { * @public */ nonce?: string + + /** + * If true, all animations will be skipped and values will be set instantly. + * Useful for E2E tests and visual regression testing. + * + * @public + */ + skipAnimations?: boolean } export interface VisualState<_Instance, RenderState> { @@ -81,6 +89,11 @@ export interface VisualElementOptions { props: MotionNodeOptions blockInitialAnimation?: boolean reducedMotionConfig?: ReducedMotionConfig + /** + * If true, all animations will be skipped and values will be set instantly. + * Useful for E2E tests and visual regression testing. + */ + skipAnimations?: boolean /** * Explicit override for SVG detection. When true, uses SVG rendering; * when false, uses HTML rendering. If undefined, auto-detects. From c84f4cf43ef42b54836862844ac377c2551f8eeb Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Jan 2026 06:07:34 +0000 Subject: [PATCH 3/7] Fix animateMini crash when element removed from DOM during scroll cancellation Check if element is still connected to the DOM before calling commitStyles() in NativeAnimation. This prevents the WAAPI commitStyles() method from throwing when the animation is stopped after the element has been removed from the DOM (e.g., in disconnectedCallback). Added Playwright E2E test to verify the fix. Fixes #3509 https://claude.ai/code/session_01Cp6uaRWywEQbL3zyMCNkfN --- dev/html/public/playwright/animate/mini.html | 30 +++++++++++++++++++ .../src/animation/NativeAnimation.ts | 3 +- tests/animate/mini.spec.ts | 7 +++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/dev/html/public/playwright/animate/mini.html b/dev/html/public/playwright/animate/mini.html index 25fd202fdb..272e0e306c 100644 --- a/dev/html/public/playwright/animate/mini.html +++ b/dev/html/public/playwright/animate/mini.html @@ -35,6 +35,7 @@
autoplay
time
custom easing
+
stop after remove
diff --git a/packages/motion-dom/src/animation/NativeAnimation.ts b/packages/motion-dom/src/animation/NativeAnimation.ts index 8ee336901a..8a78aacec2 100644 --- a/packages/motion-dom/src/animation/NativeAnimation.ts +++ b/packages/motion-dom/src/animation/NativeAnimation.ts @@ -178,7 +178,8 @@ export class NativeAnimation * while deferring the commit until the next animation frame. */ protected commitStyles() { - if (!this.isPseudoElement) { + const element = this.options?.element + if (!this.isPseudoElement && element?.isConnected) { this.animation.commitStyles?.() } } diff --git a/tests/animate/mini.spec.ts b/tests/animate/mini.spec.ts index a7a20deb64..1735a9ab62 100644 --- a/tests/animate/mini.spec.ts +++ b/tests/animate/mini.spec.ts @@ -62,4 +62,11 @@ test.describe("animateMini", () => { const element = page.locator("#custom-easing") await expect(element).toHaveCSS("opacity", "0.25") }) + + test("stop() does not crash when element is removed from DOM", async ({ + page, + }) => { + const element = page.locator("#stop-after-remove-result") + await expect(element).toHaveText("complete") + }) }) From 8b4558554aa8bc99b61ac0c7aa1199757b057afb Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Mon, 2 Feb 2026 12:52:45 +0100 Subject: [PATCH 4/7] Updating changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b03018ba15..e4a02985a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Motion adheres to [Semantic Versioning](http://semver.org/). Undocumented APIs should be considered internal and may change without warning. +## [12.29.4] 2026-02-02 + +### Fixed + +- `animate`: Prevent error when calling `stop()` on removed elements. + ## [12.29.3] 2026-02-02 ### Fixed From 5f6c358a2493c907a0844ae8b7f97c0c26e9dc7d Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Mon, 2 Feb 2026 12:56:02 +0100 Subject: [PATCH 5/7] Updating changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a02985a9..d697b28104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,16 @@ Motion adheres to [Semantic Versioning](http://semver.org/). Undocumented APIs should be considered internal and may change without warning. -## [12.29.4] 2026-02-02 +## [12.30.0] 2026-02-02 + +### Added + +- `MotionConfig`: Add `skipAnimations` option. ### Fixed - `animate`: Prevent error when calling `stop()` on removed elements. +- `animateLayout`: Fixing shared element animations when `animate` called before `animateLayout`. ## [12.29.3] 2026-02-02 From f3ebcdb1435781963dfa06f4d00afca9e0475881 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Mon, 2 Feb 2026 12:56:23 +0100 Subject: [PATCH 6/7] v12.30.0 --- dev/html/package.json | 8 ++++---- dev/next/package.json | 4 ++-- dev/react-19/package.json | 4 ++-- dev/react/package.json | 4 ++-- lerna.json | 2 +- packages/framer-motion/package.json | 4 ++-- packages/motion-dom/package.json | 2 +- packages/motion/package.json | 4 ++-- yarn.lock | 22 +++++++++++----------- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/dev/html/package.json b/dev/html/package.json index 4ce792b5d4..d58ab3e796 100644 --- a/dev/html/package.json +++ b/dev/html/package.json @@ -1,7 +1,7 @@ { "name": "html-env", "private": true, - "version": "12.29.3", + "version": "12.30.0", "type": "module", "scripts": { "dev": "vite", @@ -10,9 +10,9 @@ "preview": "vite preview" }, "dependencies": { - "framer-motion": "^12.29.3", - "motion": "^12.29.3", - "motion-dom": "^12.29.2", + "framer-motion": "^12.30.0", + "motion": "^12.30.0", + "motion-dom": "^12.30.0", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/dev/next/package.json b/dev/next/package.json index d54351379c..215b096d23 100644 --- a/dev/next/package.json +++ b/dev/next/package.json @@ -1,7 +1,7 @@ { "name": "next-env", "private": true, - "version": "12.29.3", + "version": "12.30.0", "type": "module", "scripts": { "dev": "next dev", @@ -10,7 +10,7 @@ "build": "next build" }, "dependencies": { - "motion": "^12.29.3", + "motion": "^12.30.0", "next": "15.4.10", "react": "19.0.0", "react-dom": "19.0.0" diff --git a/dev/react-19/package.json b/dev/react-19/package.json index d45f0e04f9..c2c1bbff12 100644 --- a/dev/react-19/package.json +++ b/dev/react-19/package.json @@ -1,7 +1,7 @@ { "name": "react-19-env", "private": true, - "version": "12.29.3", + "version": "12.30.0", "type": "module", "scripts": { "dev": "vite", @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "motion": "^12.29.3", + "motion": "^12.30.0", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/dev/react/package.json b/dev/react/package.json index 91461b767f..7b7e188e8b 100644 --- a/dev/react/package.json +++ b/dev/react/package.json @@ -1,7 +1,7 @@ { "name": "react-env", "private": true, - "version": "12.29.3", + "version": "12.30.0", "type": "module", "scripts": { "dev": "yarn vite", @@ -11,7 +11,7 @@ "preview": "yarn vite preview" }, "dependencies": { - "framer-motion": "^12.29.3", + "framer-motion": "^12.30.0", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/lerna.json b/lerna.json index c36eefb19a..8342924aa4 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "12.29.3", + "version": "12.30.0", "packages": [ "packages/*", "dev/*" diff --git a/packages/framer-motion/package.json b/packages/framer-motion/package.json index 4b1d17b012..a73f08dde4 100644 --- a/packages/framer-motion/package.json +++ b/packages/framer-motion/package.json @@ -1,6 +1,6 @@ { "name": "framer-motion", - "version": "12.29.3", + "version": "12.30.0", "description": "A simple and powerful JavaScript animation library", "main": "dist/cjs/index.js", "module": "dist/es/index.mjs", @@ -88,7 +88,7 @@ "measure": "rollup -c ./rollup.size.config.mjs" }, "dependencies": { - "motion-dom": "^12.29.2", + "motion-dom": "^12.30.0", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, diff --git a/packages/motion-dom/package.json b/packages/motion-dom/package.json index a68da94d35..00e2bbfbc0 100644 --- a/packages/motion-dom/package.json +++ b/packages/motion-dom/package.json @@ -1,6 +1,6 @@ { "name": "motion-dom", - "version": "12.29.2", + "version": "12.30.0", "author": "Matt Perry", "license": "MIT", "repository": "https://github.com/motiondivision/motion", diff --git a/packages/motion/package.json b/packages/motion/package.json index fda38ed78c..d3d990aba0 100644 --- a/packages/motion/package.json +++ b/packages/motion/package.json @@ -1,6 +1,6 @@ { "name": "motion", - "version": "12.29.3", + "version": "12.30.0", "description": "An animation library for JavaScript and React.", "main": "dist/cjs/index.js", "module": "dist/es/index.mjs", @@ -76,7 +76,7 @@ "postpublish": "git push --tags" }, "dependencies": { - "framer-motion": "^12.29.3", + "framer-motion": "^12.30.0", "tslib": "^2.4.0" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index e08f109223..1a3f3495c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7420,14 +7420,14 @@ __metadata: languageName: node linkType: hard -"framer-motion@^12.29.3, framer-motion@workspace:packages/framer-motion": +"framer-motion@^12.30.0, framer-motion@workspace:packages/framer-motion": version: 0.0.0-use.local resolution: "framer-motion@workspace:packages/framer-motion" dependencies: "@radix-ui/react-dialog": ^1.1.15 "@thednp/dommatrix": ^2.0.11 "@types/three": 0.137.0 - motion-dom: ^12.29.2 + motion-dom: ^12.30.0 motion-utils: ^12.29.2 three: 0.137.0 tslib: ^2.4.0 @@ -8192,9 +8192,9 @@ __metadata: version: 0.0.0-use.local resolution: "html-env@workspace:dev/html" dependencies: - framer-motion: ^12.29.3 - motion: ^12.29.3 - motion-dom: ^12.29.2 + framer-motion: ^12.30.0 + motion: ^12.30.0 + motion-dom: ^12.30.0 react: ^18.3.1 react-dom: ^18.3.1 vite: ^5.2.0 @@ -10936,7 +10936,7 @@ __metadata: languageName: node linkType: hard -"motion-dom@^12.29.2, motion-dom@workspace:packages/motion-dom": +"motion-dom@^12.30.0, motion-dom@workspace:packages/motion-dom": version: 0.0.0-use.local resolution: "motion-dom@workspace:packages/motion-dom" dependencies: @@ -11013,11 +11013,11 @@ __metadata: languageName: unknown linkType: soft -"motion@^12.29.3, motion@workspace:packages/motion": +"motion@^12.30.0, motion@workspace:packages/motion": version: 0.0.0-use.local resolution: "motion@workspace:packages/motion" dependencies: - framer-motion: ^12.29.3 + framer-motion: ^12.30.0 tslib: ^2.4.0 peerDependencies: "@emotion/is-prop-valid": "*" @@ -11134,7 +11134,7 @@ __metadata: version: 0.0.0-use.local resolution: "next-env@workspace:dev/next" dependencies: - motion: ^12.29.3 + motion: ^12.30.0 next: 15.4.10 react: 19.0.0 react-dom: 19.0.0 @@ -12599,7 +12599,7 @@ __metadata: "@typescript-eslint/parser": ^7.2.0 "@vitejs/plugin-react-swc": ^3.5.0 eslint-plugin-react-refresh: ^0.4.6 - motion: ^12.29.3 + motion: ^12.30.0 react: ^19.0.0 react-dom: ^19.0.0 vite: ^5.2.0 @@ -12683,7 +12683,7 @@ __metadata: "@typescript-eslint/parser": ^7.2.0 "@vitejs/plugin-react-swc": ^3.5.0 eslint-plugin-react-refresh: ^0.4.6 - framer-motion: ^12.29.3 + framer-motion: ^12.30.0 react: ^18.3.1 react-dom: ^18.3.1 vite: ^5.2.0 From d60c6921309f3a35d0a102289a3b0cb150808316 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Mon, 2 Feb 2026 14:51:43 +0100 Subject: [PATCH 7/7] Fixing test --- dev/html/src/imports/animate-layout.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/html/src/imports/animate-layout.js b/dev/html/src/imports/animate-layout.js index 484c5f71f0..700c820a18 100644 --- a/dev/html/src/imports/animate-layout.js +++ b/dev/html/src/imports/animate-layout.js @@ -2,6 +2,7 @@ import { LayoutAnimationBuilder, frame, parseAnimateLayoutArgs, + animate, } from "framer-motion/dom" export function unstable_animateLayout( @@ -22,4 +23,5 @@ window.AnimateLayout = { animateLayout: unstable_animateLayout, LayoutAnimationBuilder, frame, + animate, }