From 4e809795222459d877fb1297334afcc7eaf53cb2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Jan 2026 14:09:45 +0000 Subject: [PATCH 01/11] Fix string scale values of zero being treated as default When passing scale: "0" or similar string values, the buildTransform function was incorrectly treating these as default values because it only checked if parseFloat(value) === 0 for string values. For scale properties, the default is 1, not 0. This fix makes the string branch mirror the number branch logic, checking against 1 for scale properties and 0 for others. Fixes #3465 --- .../render/html/utils/__tests__/build-transform.test.ts | 7 +++++++ .../motion-dom/src/render/html/utils/build-transform.ts | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/framer-motion/src/render/html/utils/__tests__/build-transform.test.ts b/packages/framer-motion/src/render/html/utils/__tests__/build-transform.test.ts index 29f9d9b4a0..07e691cdb4 100644 --- a/packages/framer-motion/src/render/html/utils/__tests__/build-transform.test.ts +++ b/packages/framer-motion/src/render/html/utils/__tests__/build-transform.test.ts @@ -101,4 +101,11 @@ describe("buildTransform", () => { "translateX(1px) translateY(10px) scale(2) rotate(90deg) rotateZ(190deg)" ) }) + + it("Correctly handles string scale values of zero", () => { + // scale: "0" should produce scale(0), not be treated as default + expect(buildTransform({ scale: "0" }, {})).toBe("scale(0)") + expect(buildTransform({ scaleX: "0" }, {})).toBe("scaleX(0)") + expect(buildTransform({ scaleY: "0" }, {})).toBe("scaleY(0)") + }) }) diff --git a/packages/motion-dom/src/render/html/utils/build-transform.ts b/packages/motion-dom/src/render/html/utils/build-transform.ts index 17e52bdc2c..caceb10c31 100644 --- a/packages/motion-dom/src/render/html/utils/build-transform.ts +++ b/packages/motion-dom/src/render/html/utils/build-transform.ts @@ -43,7 +43,8 @@ export function buildTransform( if (typeof value === "number") { valueIsDefault = value === (key.startsWith("scale") ? 1 : 0) } else { - valueIsDefault = parseFloat(value) === 0 + const parsed = parseFloat(value) + valueIsDefault = key.startsWith("scale") ? parsed === 1 : parsed === 0 } if (!valueIsDefault || transformTemplate) { From 54ed4afda386876fc04e6b308ebc3fd1eef4c0bd Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Jan 2026 14:30:19 +0000 Subject: [PATCH 02/11] Fix string scale values in styleEffect buildTransform Apply the same fix to the duplicate buildTransform function in effects/style/transform.ts. This ensures string scale values of "0" are correctly handled in the styleEffect code path as well. Fixes #3465 --- .../effects/__tests__/style-effect.test.ts | 31 +++++++++++++++++++ .../motion-dom/src/effects/style/transform.ts | 3 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/motion-dom/src/effects/__tests__/style-effect.test.ts b/packages/motion-dom/src/effects/__tests__/style-effect.test.ts index dae2067a46..310e4bd182 100644 --- a/packages/motion-dom/src/effects/__tests__/style-effect.test.ts +++ b/packages/motion-dom/src/effects/__tests__/style-effect.test.ts @@ -477,4 +477,35 @@ describe("styleEffect", () => { // Verify mixed values are handled correctly expect(element.style.transformOrigin).toBe("50% 100% 0px") }) + + it("correctly handles string scale values of zero", async () => { + const element = document.createElement("div") + + // Create motion values with string scale of zero + const scale = motionValue("0") + const scaleX = motionValue("0") + const scaleY = motionValue("0") + + // Apply style effect + styleEffect(element, { + scale, + scaleX, + scaleY, + }) + + await nextFrame() + + // scale: "0" should produce scale(0), not be treated as default + expect(element.style.transform).toBe("scale(0) scaleX(0) scaleY(0)") + + // Change to non-zero values + scale.set("1") + scaleX.set("1") + scaleY.set("1") + + await nextFrame() + + // All values are now default (1), so transform should be "none" + expect(element.style.transform).toBe("none") + }) }) diff --git a/packages/motion-dom/src/effects/style/transform.ts b/packages/motion-dom/src/effects/style/transform.ts index f8b506a033..ab60a4595f 100644 --- a/packages/motion-dom/src/effects/style/transform.ts +++ b/packages/motion-dom/src/effects/style/transform.ts @@ -26,7 +26,8 @@ export function buildTransform(state: MotionValueState) { if (typeof value === "number") { valueIsDefault = value === (key.startsWith("scale") ? 1 : 0) } else { - valueIsDefault = parseFloat(value) === 0 + const parsed = parseFloat(value) + valueIsDefault = key.startsWith("scale") ? parsed === 1 : parsed === 0 } if (!valueIsDefault) { From 53e2b4e4c68ba7e7ade793b7f03c437f79328c8a Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 13:50:22 +0100 Subject: [PATCH 03/11] Updating changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c686561f7c..35bed4975e 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.28.1] 2026-01-21 + +### Fixed + +- Ensure `scale: "0%"` isn't treated as default value. + ## [12.28.0] 2026-01-20 ### Added From abbe8f2fa7a8028009856d4a2099f56556cd2974 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 13:51:16 +0100 Subject: [PATCH 04/11] v12.28.1 --- 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 c563403b50..619ebeadd9 100644 --- a/dev/html/package.json +++ b/dev/html/package.json @@ -1,7 +1,7 @@ { "name": "html-env", "private": true, - "version": "12.28.0", + "version": "12.28.1", "type": "module", "scripts": { "dev": "vite", @@ -10,9 +10,9 @@ "preview": "vite preview" }, "dependencies": { - "framer-motion": "^12.28.0", - "motion": "^12.28.0", - "motion-dom": "^12.28.0", + "framer-motion": "^12.28.1", + "motion": "^12.28.1", + "motion-dom": "^12.28.1", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/dev/next/package.json b/dev/next/package.json index 56ecd07628..0ba78a61df 100644 --- a/dev/next/package.json +++ b/dev/next/package.json @@ -1,7 +1,7 @@ { "name": "next-env", "private": true, - "version": "12.28.0", + "version": "12.28.1", "type": "module", "scripts": { "dev": "next dev", @@ -10,7 +10,7 @@ "build": "next build" }, "dependencies": { - "motion": "^12.28.0", + "motion": "^12.28.1", "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 48bed74ebf..d58180fe6d 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.28.0", + "version": "12.28.1", "type": "module", "scripts": { "dev": "vite", @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "motion": "^12.28.0", + "motion": "^12.28.1", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/dev/react/package.json b/dev/react/package.json index 2b4ce9f0bb..ca1ce9eb60 100644 --- a/dev/react/package.json +++ b/dev/react/package.json @@ -1,7 +1,7 @@ { "name": "react-env", "private": true, - "version": "12.28.0", + "version": "12.28.1", "type": "module", "scripts": { "dev": "yarn vite", @@ -11,7 +11,7 @@ "preview": "yarn vite preview" }, "dependencies": { - "framer-motion": "^12.28.0", + "framer-motion": "^12.28.1", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/lerna.json b/lerna.json index a4f79db0b5..bf9918737c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "12.28.0", + "version": "12.28.1", "packages": [ "packages/*", "dev/*" diff --git a/packages/framer-motion/package.json b/packages/framer-motion/package.json index 63b0909fd1..343edcc78c 100644 --- a/packages/framer-motion/package.json +++ b/packages/framer-motion/package.json @@ -1,6 +1,6 @@ { "name": "framer-motion", - "version": "12.28.0", + "version": "12.28.1", "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.28.0", + "motion-dom": "^12.28.1", "motion-utils": "^12.27.2", "tslib": "^2.4.0" }, diff --git a/packages/motion-dom/package.json b/packages/motion-dom/package.json index d60b2c5cc0..45bac23916 100644 --- a/packages/motion-dom/package.json +++ b/packages/motion-dom/package.json @@ -1,6 +1,6 @@ { "name": "motion-dom", - "version": "12.28.0", + "version": "12.28.1", "author": "Matt Perry", "license": "MIT", "repository": "https://github.com/motiondivision/motion", diff --git a/packages/motion/package.json b/packages/motion/package.json index e5e753bcf7..df86aecea6 100644 --- a/packages/motion/package.json +++ b/packages/motion/package.json @@ -1,6 +1,6 @@ { "name": "motion", - "version": "12.28.0", + "version": "12.28.1", "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.28.0", + "framer-motion": "^12.28.1", "tslib": "^2.4.0" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 12b92a3b74..856cb28114 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7420,14 +7420,14 @@ __metadata: languageName: node linkType: hard -"framer-motion@^12.28.0, framer-motion@workspace:packages/framer-motion": +"framer-motion@^12.28.1, 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.28.0 + motion-dom: ^12.28.1 motion-utils: ^12.27.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.28.0 - motion: ^12.28.0 - motion-dom: ^12.28.0 + framer-motion: ^12.28.1 + motion: ^12.28.1 + motion-dom: ^12.28.1 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.28.0, motion-dom@workspace:packages/motion-dom": +"motion-dom@^12.28.1, 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.28.0, motion@workspace:packages/motion": +"motion@^12.28.1, motion@workspace:packages/motion": version: 0.0.0-use.local resolution: "motion@workspace:packages/motion" dependencies: - framer-motion: ^12.28.0 + framer-motion: ^12.28.1 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.28.0 + motion: ^12.28.1 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.28.0 + motion: ^12.28.1 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.28.0 + framer-motion: ^12.28.1 react: ^18.3.1 react-dom: ^18.3.1 vite: ^5.2.0 From c5a8e5cd92299b8d202e536a0c7295d3dd6accaf Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 14:28:55 +0100 Subject: [PATCH 05/11] Updating fix slash command --- .claude/commands/fix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/commands/fix.md b/.claude/commands/fix.md index 7c18d2e6b1..4d9bd79cdc 100644 --- a/.claude/commands/fix.md +++ b/.claude/commands/fix.md @@ -20,5 +20,5 @@ git worktree add ../${REPO_NAME}-$ARGUMENTS -b $ARGUMENTS Then tell me to close Claude and reopen with: ```bash -cd ../-$ARGUMENTS && claude +cd ../-$ARGUMENTS && claude --dangerously-skip-permissions ``` From 51191665a86935f4c46f99f17a571b36e32ff8e0 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Jan 2026 13:47:42 +0000 Subject: [PATCH 06/11] Add fontSize to default px types list This allows numeric fontSize values to automatically have "px" units appended, matching the behavior of width, height, and other dimension properties. Fixes #2749 --- .../src/render/html/utils/__tests__/build-styles.test.ts | 8 ++++++++ .../motion-dom/src/animation/waapi/utils/px-values.ts | 2 ++ packages/motion-dom/src/value/types/maps/number.ts | 3 +++ 3 files changed, 13 insertions(+) diff --git a/packages/framer-motion/src/render/html/utils/__tests__/build-styles.test.ts b/packages/framer-motion/src/render/html/utils/__tests__/build-styles.test.ts index 06de8441c1..643e91767a 100644 --- a/packages/framer-motion/src/render/html/utils/__tests__/build-styles.test.ts +++ b/packages/framer-motion/src/render/html/utils/__tests__/build-styles.test.ts @@ -12,6 +12,14 @@ describe("buildHTMLStyles", () => { expect(style).toEqual({ width: "100px" }) }) + test("Builds fontSize with px unit", () => { + const latest = { fontSize: 16 } + const style = {} + build(latest, { style }) + + expect(style).toEqual({ fontSize: "16px" }) + }) + test("Builds vars", () => { const latest = { "--width": 100 } const vars = {} diff --git a/packages/motion-dom/src/animation/waapi/utils/px-values.ts b/packages/motion-dom/src/animation/waapi/utils/px-values.ts index ce04cc35d9..f48adcb218 100644 --- a/packages/motion-dom/src/animation/waapi/utils/px-values.ts +++ b/packages/motion-dom/src/animation/waapi/utils/px-values.ts @@ -50,6 +50,8 @@ export const pxValues = new Set([ "marginInline", "marginInlineStart", "marginInlineEnd", + // Typography + "fontSize", // Misc "backgroundPositionX", "backgroundPositionY", diff --git a/packages/motion-dom/src/value/types/maps/number.ts b/packages/motion-dom/src/value/types/maps/number.ts index be7c6ce678..97c8ef1e7b 100644 --- a/packages/motion-dom/src/value/types/maps/number.ts +++ b/packages/motion-dom/src/value/types/maps/number.ts @@ -59,6 +59,9 @@ export const numberValueTypes: ValueTypeMap = { marginInlineStart: px, marginInlineEnd: px, + // Typography + fontSize: px, + // Misc backgroundPositionX: px, backgroundPositionY: px, From d8b7f5f2eb33f66f9aca6cb85b13c2aec4af97bf Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 15:16:26 +0100 Subject: [PATCH 07/11] Fix LazyMotion animation not firing when state changes before features load When using LazyMotion with async feature loading, state changes that occur before features load (~5ms after mount) would cause the element to snap to its final value instead of animating. This happened because the VisualElement wasn't created until features loaded, so there was no AnimationState to track the state changes. The fix tracks whether the component has already been through React's commit phase before the VisualElement is created. If so, we set manuallyAnimateOnMount to true, which forces the initial animation to run rather than being blocked. Fixes #2759 Co-Authored-By: Claude Opus 4.5 --- .../src/tests/lazy-motion-fast-state.tsx | 58 +++++++++++++++++++ .../integration/lazy-motion-fast-state.ts | 13 +++++ .../src/motion/utils/use-visual-element.ts | 22 +++++++ 3 files changed, 93 insertions(+) create mode 100644 dev/react/src/tests/lazy-motion-fast-state.tsx create mode 100644 packages/framer-motion/cypress/integration/lazy-motion-fast-state.ts diff --git a/dev/react/src/tests/lazy-motion-fast-state.tsx b/dev/react/src/tests/lazy-motion-fast-state.tsx new file mode 100644 index 0000000000..3e22176dd9 --- /dev/null +++ b/dev/react/src/tests/lazy-motion-fast-state.tsx @@ -0,0 +1,58 @@ +import { m, LazyMotion, domAnimation } from "framer-motion" +import { useState, useEffect, useRef } from "react" + +/** + * Test for GitHub issue #2759 + * When LazyMotion features load asynchronously and state changes occur before + * features load, the enter animation should still fire (not snap to final value). + */ + +const variants = { + hidden: { opacity: 0 }, + visible: { opacity: 1 }, +} + +export const App = () => { + const [isVisible, setIsVisible] = useState(false) + const boxRef = useRef(null) + + // Simulate state change that occurs before features load + useEffect(() => { + const timer = setTimeout(() => { + setIsVisible(true) + }, 5) // State changes after 5ms + return () => clearTimeout(timer) + }, []) + + return ( + + new Promise((resolve) => { + // Features load after 50ms (longer than the 5ms state change) + setTimeout(() => { + resolve(domAnimation) + }, 50) + }) + } + > + { + if (boxRef.current) { + boxRef.current.dataset.animationComplete = "true" + } + }} + style={{ + width: 100, + height: 100, + background: "red", + }} + /> + + ) +} diff --git a/packages/framer-motion/cypress/integration/lazy-motion-fast-state.ts b/packages/framer-motion/cypress/integration/lazy-motion-fast-state.ts new file mode 100644 index 0000000000..073aa1b4c8 --- /dev/null +++ b/packages/framer-motion/cypress/integration/lazy-motion-fast-state.ts @@ -0,0 +1,13 @@ +describe("LazyMotion with fast state changes", () => { + it("animates when state changes before features load", () => { + cy.visit("?test=lazy-motion-fast-state") + .wait(300) // Wait for features to load and animation to complete + .get("#box") + .should(([$element]: any) => { + // Verify the animation completed + expect($element.dataset.animationComplete).to.equal("true") + // Verify the element is visible (opacity: 1) + expect(getComputedStyle($element).opacity).to.equal("1") + }) + }) +}) 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 a76fe01dd5..cd5f081516 100644 --- a/packages/framer-motion/src/motion/utils/use-visual-element.ts +++ b/packages/framer-motion/src/motion/utils/use-visual-element.ts @@ -46,6 +46,12 @@ export function useVisualElement< HTMLElement | SVGElement > | null>(null) + /** + * Track whether the component has been through React's commit phase. + * Used to detect when LazyMotion features load after the component has mounted. + */ + const hasMountedOnce = useRef(false) + /** * If we haven't preloaded a renderer, check to see if we have one lazy-loaded */ @@ -65,6 +71,16 @@ export function useVisualElement< reducedMotionConfig, isSVG, }) + + /** + * If the component has already mounted before features loaded (e.g. via + * LazyMotion with async feature loading), we need to force the initial + * animation to run. Otherwise state changes that occurred before features + * loaded will be lost and the element will snap to its final state. + */ + if (hasMountedOnce.current && visualElementRef.current) { + visualElementRef.current.manuallyAnimateOnMount = true + } } const visualElement = visualElementRef.current @@ -113,6 +129,12 @@ export function useVisualElement< ) useIsomorphicLayoutEffect(() => { + /** + * Track that this component has mounted. This is used to detect when + * LazyMotion features load after the component has already committed. + */ + hasMountedOnce.current = true + if (!visualElement) return isMounted.current = true From c03e834039fe2832c71949b161a240cb376d55ed Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Jan 2026 14:17:27 +0000 Subject: [PATCH 08/11] Remove radius from px default unit mappings The SVG feMorphology filter primitive requires radius to be a unitless number. The radius property was incorrectly mapped to px units, which caused animated radius values to become invalid (e.g., "4px" instead of "4"). Fixes #2779 --- .../src/animation/waapi/utils/px-values.ts | 1 - .../src/effects/__tests__/svg-effect.test.ts | 21 +++++++++++++++++++ .../motion-dom/src/value/types/maps/number.ts | 1 - 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/motion-dom/src/animation/waapi/utils/px-values.ts b/packages/motion-dom/src/animation/waapi/utils/px-values.ts index ce04cc35d9..4b3d5ee1c6 100644 --- a/packages/motion-dom/src/animation/waapi/utils/px-values.ts +++ b/packages/motion-dom/src/animation/waapi/utils/px-values.ts @@ -6,7 +6,6 @@ export const pxValues = new Set([ "borderBottomWidth", "borderLeftWidth", "borderRadius", - "radius", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomRightRadius", diff --git a/packages/motion-dom/src/effects/__tests__/svg-effect.test.ts b/packages/motion-dom/src/effects/__tests__/svg-effect.test.ts index 35b75f1268..88652559e8 100644 --- a/packages/motion-dom/src/effects/__tests__/svg-effect.test.ts +++ b/packages/motion-dom/src/effects/__tests__/svg-effect.test.ts @@ -9,6 +9,27 @@ async function nextFrame() { } describe("svgEffect", () => { + it("sets feMorphology radius as unitless number (issue #2779)", async () => { + const element = document.createElementNS( + "http://www.w3.org/2000/svg", + "feMorphology" + ) + + // Create motion value for radius + const radius = motionValue(4) + + // Apply svg effect + svgEffect(element, { + radius, + }) + + await nextFrame() + + // Verify radius is set as unitless number, not with "px" suffix + // This was the bug - radius was being set as "4px" instead of "4" + expect(element.getAttribute("radius")).toBe("4") + }) + it("sets SVG attributes and styles after svgEffect is applied", async () => { const element = document.createElementNS( "http://www.w3.org/2000/svg", diff --git a/packages/motion-dom/src/value/types/maps/number.ts b/packages/motion-dom/src/value/types/maps/number.ts index be7c6ce678..48e405b2e0 100644 --- a/packages/motion-dom/src/value/types/maps/number.ts +++ b/packages/motion-dom/src/value/types/maps/number.ts @@ -12,7 +12,6 @@ export const numberValueTypes: ValueTypeMap = { borderBottomWidth: px, borderLeftWidth: px, borderRadius: px, - radius: px, borderTopLeftRadius: px, borderTopRightRadius: px, borderBottomRightRadius: px, From 8c44b8da94016d1724db62a3095e1e853f04f9e9 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 15:30:29 +0100 Subject: [PATCH 09/11] Updating changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35bed4975e..0bf32aaa1a 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.28.2] 2026-01-21 + +### Fixed + +- Removed default value type from `radius`. + ## [12.28.1] 2026-01-21 ### Fixed From d9054dc6a2b9fa10c8ed4741029744614249712f Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 15:41:48 +0100 Subject: [PATCH 10/11] Updating changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bf32aaa1a..597a32ed74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,14 @@ Undocumented APIs should be considered internal and may change without warning. ## [12.28.2] 2026-01-21 +### Added + +- Add default value type `px` for `fontSize`. + ### Fixed - Removed default value type from `radius`. +- Ensure `LazyMotion` animates initial state even when state has changed before Motion is loaded. ## [12.28.1] 2026-01-21 From d8dd8a816137387135c152f31e587f9bfd5bbefb Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 21 Jan 2026 15:42:22 +0100 Subject: [PATCH 11/11] v12.28.2 --- 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 619ebeadd9..0616625fcc 100644 --- a/dev/html/package.json +++ b/dev/html/package.json @@ -1,7 +1,7 @@ { "name": "html-env", "private": true, - "version": "12.28.1", + "version": "12.28.2", "type": "module", "scripts": { "dev": "vite", @@ -10,9 +10,9 @@ "preview": "vite preview" }, "dependencies": { - "framer-motion": "^12.28.1", - "motion": "^12.28.1", - "motion-dom": "^12.28.1", + "framer-motion": "^12.28.2", + "motion": "^12.28.2", + "motion-dom": "^12.28.2", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/dev/next/package.json b/dev/next/package.json index 0ba78a61df..2daed67612 100644 --- a/dev/next/package.json +++ b/dev/next/package.json @@ -1,7 +1,7 @@ { "name": "next-env", "private": true, - "version": "12.28.1", + "version": "12.28.2", "type": "module", "scripts": { "dev": "next dev", @@ -10,7 +10,7 @@ "build": "next build" }, "dependencies": { - "motion": "^12.28.1", + "motion": "^12.28.2", "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 d58180fe6d..7c48473384 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.28.1", + "version": "12.28.2", "type": "module", "scripts": { "dev": "vite", @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "motion": "^12.28.1", + "motion": "^12.28.2", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/dev/react/package.json b/dev/react/package.json index ca1ce9eb60..af179b7d02 100644 --- a/dev/react/package.json +++ b/dev/react/package.json @@ -1,7 +1,7 @@ { "name": "react-env", "private": true, - "version": "12.28.1", + "version": "12.28.2", "type": "module", "scripts": { "dev": "yarn vite", @@ -11,7 +11,7 @@ "preview": "yarn vite preview" }, "dependencies": { - "framer-motion": "^12.28.1", + "framer-motion": "^12.28.2", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/lerna.json b/lerna.json index bf9918737c..41bb16df26 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "12.28.1", + "version": "12.28.2", "packages": [ "packages/*", "dev/*" diff --git a/packages/framer-motion/package.json b/packages/framer-motion/package.json index 343edcc78c..983b4fd1eb 100644 --- a/packages/framer-motion/package.json +++ b/packages/framer-motion/package.json @@ -1,6 +1,6 @@ { "name": "framer-motion", - "version": "12.28.1", + "version": "12.28.2", "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.28.1", + "motion-dom": "^12.28.2", "motion-utils": "^12.27.2", "tslib": "^2.4.0" }, diff --git a/packages/motion-dom/package.json b/packages/motion-dom/package.json index 45bac23916..0e8c7e3882 100644 --- a/packages/motion-dom/package.json +++ b/packages/motion-dom/package.json @@ -1,6 +1,6 @@ { "name": "motion-dom", - "version": "12.28.1", + "version": "12.28.2", "author": "Matt Perry", "license": "MIT", "repository": "https://github.com/motiondivision/motion", diff --git a/packages/motion/package.json b/packages/motion/package.json index df86aecea6..4d77e446af 100644 --- a/packages/motion/package.json +++ b/packages/motion/package.json @@ -1,6 +1,6 @@ { "name": "motion", - "version": "12.28.1", + "version": "12.28.2", "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.28.1", + "framer-motion": "^12.28.2", "tslib": "^2.4.0" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 856cb28114..d896350aca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7420,14 +7420,14 @@ __metadata: languageName: node linkType: hard -"framer-motion@^12.28.1, framer-motion@workspace:packages/framer-motion": +"framer-motion@^12.28.2, 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.28.1 + motion-dom: ^12.28.2 motion-utils: ^12.27.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.28.1 - motion: ^12.28.1 - motion-dom: ^12.28.1 + framer-motion: ^12.28.2 + motion: ^12.28.2 + motion-dom: ^12.28.2 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.28.1, motion-dom@workspace:packages/motion-dom": +"motion-dom@^12.28.2, 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.28.1, motion@workspace:packages/motion": +"motion@^12.28.2, motion@workspace:packages/motion": version: 0.0.0-use.local resolution: "motion@workspace:packages/motion" dependencies: - framer-motion: ^12.28.1 + framer-motion: ^12.28.2 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.28.1 + motion: ^12.28.2 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.28.1 + motion: ^12.28.2 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.28.1 + framer-motion: ^12.28.2 react: ^18.3.1 react-dom: ^18.3.1 vite: ^5.2.0