Keep rotateZ on elements with a layout animation
The projection pipeline handled rotate, rotateX and rotateY but not rotateZ, so a layout or shared layout animation silently dropped it from the generated transform and never mixed it between lead and follow.
This commit is contained in:
1 parent
1ba1c99cc1
commit
2e01f31175
7 files changed
+83
No files matched your search
@@ -10,6 +10,10 @@ Undocumented APIs should be considered internal and may change without warning.
|
|||||||
|
|
||||||
- `springValue`/`useSpring`: Improved performance when retargeting spring.
|
- `springValue`/`useSpring`: Improved performance when retargeting spring.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `rotateZ` is no longer dropped from elements with a layout or shared layout animation.
|
||||||
|
|
||||||
## [13.2.0] 2026-09-03
|
## [13.2.0] 2026-09-03
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -97,4 +97,20 @@ describe("mixValues", () => {
|
|||||||
|
|
||||||
expect(output).toEqual({ borderTopLeftRadius: "10px" })
|
expect(output).toEqual({ borderTopLeftRadius: "10px" })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("mixes rotate", () => {
|
||||||
|
const output = {}
|
||||||
|
|
||||||
|
mixValues(output, { rotate: 0 }, { rotate: 90 }, 0.5, false, false)
|
||||||
|
|
||||||
|
expect(output).toEqual({ rotate: 45 })
|
||||||
|
})
|
||||||
|
|
||||||
|
test("mixes rotateZ", () => {
|
||||||
|
const output = {}
|
||||||
|
|
||||||
|
mixValues(output, { rotateZ: 0 }, { rotateZ: 90 }, 0.5, false, false)
|
||||||
|
|
||||||
|
expect(output).toEqual({ rotateZ: 45 })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -91,6 +91,15 @@ export function mixValues(
|
|||||||
progress
|
progress
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `rotateZ` is a synonym of `rotate` but arrives as its own value.
|
||||||
|
if (follow.rotateZ || lead.rotateZ) {
|
||||||
|
target.rotateZ = mixNumber(
|
||||||
|
(follow.rotateZ as number) || 0,
|
||||||
|
(lead.rotateZ as number) || 0,
|
||||||
|
progress
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRadius(values: ResolvedValues, radiusName: string) {
|
function getRadius(values: ResolvedValues, radiusName: string) {
|
||||||
|
|||||||
@@ -102,4 +102,35 @@ describe("buildProjectionTransform", () => {
|
|||||||
buildProjectionTransform(delta, { x: 1, y: 1 }, { rotate: 10 })
|
buildProjectionTransform(delta, { x: 1, y: 1 }, { rotate: 10 })
|
||||||
).toEqual("translate3d(100px, 100px, 0px) rotate(10deg) scale(2, 4)")
|
).toEqual("translate3d(100px, 100px, 0px) rotate(10deg) scale(2, 4)")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("Applies rotateZ", () => {
|
||||||
|
const delta = {
|
||||||
|
x: {
|
||||||
|
translate: 100,
|
||||||
|
scale: 2,
|
||||||
|
origin: 0.5,
|
||||||
|
originPoint: 100,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
translate: 100,
|
||||||
|
scale: 4,
|
||||||
|
origin: 0.5,
|
||||||
|
originPoint: 100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildProjectionTransform(delta, { x: 1, y: 1 }, { rotateZ: 10 })
|
||||||
|
).toEqual("translate3d(100px, 100px, 0px) rotateZ(10deg) scale(2, 4)")
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildProjectionTransform(
|
||||||
|
delta,
|
||||||
|
{ x: 1, y: 1 },
|
||||||
|
{ rotate: 45, rotateX: 20, rotateY: 30, rotateZ: 10 }
|
||||||
|
)
|
||||||
|
).toEqual(
|
||||||
|
"translate3d(100px, 100px, 0px) rotate(45deg) rotateX(20deg) rotateY(30deg) rotateZ(10deg) scale(2, 4)"
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -36,6 +36,7 @@ export function buildProjectionTransform(
|
|||||||
pathRotation,
|
pathRotation,
|
||||||
rotateX,
|
rotateX,
|
||||||
rotateY,
|
rotateY,
|
||||||
|
rotateZ,
|
||||||
skewX,
|
skewX,
|
||||||
skewY,
|
skewY,
|
||||||
} = latestTransform
|
} = latestTransform
|
||||||
@@ -46,6 +47,7 @@ export function buildProjectionTransform(
|
|||||||
if (pathRotation) transform += `rotate(${pathRotation}deg) `
|
if (pathRotation) transform += `rotate(${pathRotation}deg) `
|
||||||
if (rotateX) transform += `rotateX(${rotateX}deg) `
|
if (rotateX) transform += `rotateX(${rotateX}deg) `
|
||||||
if (rotateY) transform += `rotateY(${rotateY}deg) `
|
if (rotateY) transform += `rotateY(${rotateY}deg) `
|
||||||
|
if (rotateZ) transform += `rotateZ(${rotateZ}deg) `
|
||||||
if (skewX) transform += `skewX(${skewX}deg) `
|
if (skewX) transform += `skewX(${skewX}deg) `
|
||||||
if (skewY) transform += `skewY(${skewY}deg) `
|
if (skewY) transform += `skewY(${skewY}deg) `
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { hasTransform } from "../has-transform"
|
||||||
|
|
||||||
|
describe("hasTransform", () => {
|
||||||
|
test("returns false when no transform is set", () => {
|
||||||
|
expect(hasTransform({})).toBeFalsy()
|
||||||
|
expect(hasTransform({ scale: 1, scaleX: 1, scaleY: 1 })).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("detects every distorting transform", () => {
|
||||||
|
expect(hasTransform({ scale: 2 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ x: 100 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ z: 100 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ rotate: 45 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ rotateX: 45 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ rotateY: 45 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ rotateZ: 45 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ skewX: 45 })).toBeTruthy()
|
||||||
|
expect(hasTransform({ skewY: 45 })).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -21,6 +21,7 @@ export function hasTransform(values: ResolvedValues) {
|
|||||||
values.rotate ||
|
values.rotate ||
|
||||||
values.rotateX ||
|
values.rotateX ||
|
||||||
values.rotateY ||
|
values.rotateY ||
|
||||||
|
values.rotateZ ||
|
||||||
values.skewX ||
|
values.skewX ||
|
||||||
values.skewY
|
values.skewY
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user