Repository navigation
fix(core): resolve percentage translate transforms against element size - #11481
aleclarson wants to merge 2 commits into
Conversation
translate() arguments in `transform` declarations were parsed with parseFloat, so `translate(-50%, -50%)` silently became -50dip instead of -50% of the element's own size. translateX/translateY longhands had the same problem via FixedLength.parse. Translate values are now parsed and stored as PercentLengthType and resolved against the view's own width/height when the native transform is applied and on every subsequent layout, matching CSS semantics. Duplicate translate functions in a transform list are merged per-axis so percentage units survive where they don't mix with other units on the same axis. Fixes NativeScript#11457
|
View your CI Pipeline Execution ↗ for commit 85d5f5b
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at |
commit: |
|
|
||
| const TRANSFORM_SPLITTER = new RegExp(/\s*(.+?)\((.*?)\)/g); | ||
| const TRANSFORMATIONS = Object.freeze<TransformationType[]>(['rotate', 'rotateX', 'rotateY', 'rotate3d', 'translate', 'translate3d', 'translateX', 'translateY', 'scale', 'scale3d', 'scaleX', 'scaleY']); | ||
| const TRANSLATE_TRANSFORMATIONS = Object.freeze<TransformationType[]>(['translate', 'translate3d', 'translateX', 'translateY']); |
There was a problem hiding this comment.
We could have translate array defined on top and concatenate/merge it with the other prop array to avoid keep track of props twice.
| * against the element's own size. | ||
| */ | ||
| export function isPercentTranslate(value: CoreTypes.PercentLengthType): boolean { | ||
| return typeof value === 'object' && value !== null && value.unit === '%'; |
There was a problem hiding this comment.
return value?.unit === '%'; should be enough
| * @param value The translate axis value as a PercentLengthType. | ||
| * @param basis The element's size in dips along the translated axis. | ||
| */ | ||
| export function resolveTranslate(value: CoreTypes.PercentLengthType, basis: number): CoreTypes.dip { |
There was a problem hiding this comment.
wouldnt it be better to define PercentLength.toDpi or something?
|
Thanks @aleclarson, percent translates are a feature we want. We're targeting 9.2 rather than the 9.1.3 patch because this changes public API and existing behavior. Here's what we found reviewing it against current Breaking changes
Correctness
For 9.2
|
PR Checklist
What is the current behavior?
Percentage arguments to
translate()/translateX()/translateY()/translate3d()in atransformdeclaration are parsed withparseFloat, which silently drops the%and applies the number as dips.transform: translate(-50%, -50%)moves a view by -50dip instead of -50% of its own size. ThetranslateX/translateYlonghand properties mis-parse the same way viaFixedLength.parse, and keyframetransformdeclarations hit the same path.What is the new behavior?
CoreTypes.PercentLengthType(the same mechanismwidth/height/marginalready use) viaPercentLength.parse, so%,dip,px, and plain numbers are all represented in the style value.resolveTranslate(value, basis)incss-transform.tsis used by iOSupdateNativeTransform()and AndroidtranslateX/YProperty.setNative/ layout (layoutNativeView). Resolution re-runs on every size change (_onSizeChangedon iOS, every native layout on Android), sotranslate(-50%, -50%)stays centered across resizes.translatefunctions in onetransform(e.g.translateX(-50%) translateY(-50%), which both map toproperty: 'translate') are merged per-axis instead of going through the affine-matrix path. Percent units are preserved when an axis has a single contribution or same-unit contributions; unrepresentable mixed-unit sums (e.g.translate(10) translateX(-50%)) degrade to the previous numeric coercion rather than producing NaN, so nothing regressively breaks in the matrix path.transform:inside@keyframesandview.animate({ translate })normalize translate throughPercentLength.parse, and the platform animators resolve percentages against the target's bounds — so@keyframes { transform: translate(0, -100%) }slide-in animations work.view.translateX/translateYare typedCoreTypes.PercentLengthType(numbers still accepted);translateX: 10px, which previously produced NaN on Android, now resolves correctly.Fixes #11457
Note on existing quirks kept intact: scale/rotate parsing is unchanged, and the matrix-composition path (multiple
scale/rotatefunctions) keeps its prior semantics — percentage translates hitting it degrade to the old numeric behavior rather than erroring.Test plan
ui/styling/css-transform.spec.tscovers percent/dip/px translate parsing,translateX/translateYfunctions, duplicate-translate merging, mixed-unit degradation, thetranslateX/Yproperty converters, andresolveTranslatebasis resolutionnpx nx run core:test— 515 tests passnpx nx run apps-automated:ios/:android— native transform application on device/simulator (not runnable in this environment; percentage re-resolution on resize happens inlayoutNativeView(Android) /_onSizeChanged(iOS))