fix(motion): las barras horizontales crecian desde su punta en RTL

`grow-x` clavaba `transform-origin: 0% 50%` — el borde fisico izquierdo. En
RTL la barra se dispone contra el borde DERECHO, asi que la entrada la hacia
crecer desde su punta de vuelta a su base, despegandose de su ancla. Medido
en los dos consumidores, con la direccion movida por el toggle del topbar:

  bar-segment  borde izq. clavado en 296, el derecho avanza 108 -> 0
  bar-list     borde izq. clavado en 239, y el de ANCLAJE se aleja 65 -> 3

`transform-origin` no tiene forma logica en CSS, asi que el preset lee ahora
`--motion-origin-inline-start`, que `render-css.ts` emite por `:dir()` — el
mismo patron que `scale-fade` ya usa con `--floating-transform-origin`. La
var HEREDA (al reves que el indice de stagger, que es `inherits: false`):
es lo que permite que un `:dir()` de un ancestro alcance al nodo animado. Se
declaran las DOS direcciones para que un subarbol que redeclare la suya
tambien acierte — la misma razon por la que `[dir='rtl']` esta prohibido.

Tras el arreglo el borde de anclaje queda CLAVADO en 0 y la punta avanza, en
ambas direcciones. LTR intacto (`origin: 0px`, ancla en 0). Verificado a ojo
congelando la animacion al 45%: las cinco barras del bar-list nacen pegadas a
su ancla —derecha en RTL, izquierda en LTR— con el stagger escalonado.

RTL-1 no podia verlo: es `transform-origin` en un preset de TypeScript, ni
siquiera CSS estatico.

`metrics-progress` NO usa `grow-x`; los afectados eran solo esos dos.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alpha-0.1-dir-prefs
dev 2 months ago
parent 3812cd196e
commit 3c3d8e1ac8

@ -5712,6 +5712,14 @@
inherits: false;
}
:dir(ltr) {
--motion-origin-inline-start: 0%;
}
:dir(rtl) {
--motion-origin-inline-start: 100%;
}
@property --motion-stagger-index {
syntax: '<integer>';
inherits: false;
@ -6902,14 +6910,14 @@
[data-animation-style='grow-x'][data-motion-state='open'] {
animation: grow-right var(--motion-duration-enter, var(--duration-moderate)) var(--motion-ease-enter, var(--ease-out)) backwards;
animation-delay: calc(var(--motion-stagger-index, 0) * var(--motion-stagger-each, 0ms));
transform-origin: 0% 50%;
transform-origin: var(--motion-origin-inline-start, 0%) 50%;
}
[data-animation-style='grow-x'][data-state='closed'],
[data-stagger][data-state='closed'] > [data-animation-style='grow-x'] {
animation: shrink-left var(--motion-duration-exit, var(--duration-fast)) var(--motion-ease-exit, var(--ease-in)) forwards;
animation-delay: calc(var(--motion-stagger-index-rev, 0) * var(--motion-stagger-each, 0ms));
transform-origin: 0% 50%;
transform-origin: var(--motion-origin-inline-start, 0%) 50%;
}
[data-motion='reduce'] [data-animation-style='grow-x'][data-state='open'],

@ -50,10 +50,12 @@ export const BUILTIN_KEYFRAMES: Readonly<Record<string, KeyframeStops>> = {
to: { 'stroke-dasharray': '1', 'stroke-dashoffset': '1' }
},
// Grow from the left edge (horizontal bars · progress fills). Horizontal-only
// `scale` (`0 1` → `1 1`); pair with `transform-origin: 0% 50%` (the `grow-x`
// preset sets it). HTML default `transform-box: border-box` already scopes the
// origin to the element — no `fill-box` needed for a `<div>`.
// Grow from the inline-start edge (horizontal bars · progress fills).
// Horizontal-only `scale` (`0 1` → `1 1`); pair with a `transform-origin` on
// that edge (the `grow-x` preset sets it, direction-aware). HTML default
// `transform-box: border-box` already scopes the origin to the element — no
// `fill-box` needed for a `<div>`. The names are the LTR reading of the
// effect; in RTL the same keyframes grow towards the left.
'grow-right': { from: { scale: '0 1' }, to: { scale: '1 1' } },
'shrink-left': { from: { scale: '1 1' }, to: { scale: '0 1' } },
@ -533,18 +535,26 @@ export const BUILTIN_CSS_PRESETS: Readonly<Record<string, CssStatePreset>> = {
reduce: 'instant'
},
// Grow from the left edge — horizontal bars (bar-list / bar-segment), progress
// fills. Scales on `scale` (X only) with the origin at the left; under reduce it
// snaps to full width.
// Grow from the inline-start edge — horizontal bars (bar-list / bar-segment),
// progress fills. Scales on `scale` (X only) with the origin on the edge the
// bar is anchored to; under reduce it snaps to full width. The origin comes
// from `--motion-origin-inline-start` (rendered per `:dir()`, render-css.ts)
// because `transform-origin` has no logical form: hard-coding `0%` made every
// RTL bar grow from its tip back to its base.
'grow-x': {
driver: 'css',
enter: {
keyframes: 'grow-right',
duration: 'moderate',
ease: 'out',
transformOrigin: '0% 50%'
transformOrigin: 'var(--motion-origin-inline-start, 0%) 50%'
},
exit: {
keyframes: 'shrink-left',
duration: 'fast',
ease: 'in',
transformOrigin: 'var(--motion-origin-inline-start, 0%) 50%'
},
exit: { keyframes: 'shrink-left', duration: 'fast', ease: 'in', transformOrigin: '0% 50%' },
reduce: 'instant'
},

@ -896,6 +896,19 @@ function renderMotionBlocks(motion: MotionConfig): string {
blocks.push(`@property --motion-duration-${phase} {\n\tsyntax: '*';\n\tinherits: false;\n}`)
blocks.push(`@property --motion-ease-${phase} {\n\tsyntax: '*';\n\tinherits: false;\n}`)
}
// `transform-origin` has NO logical form in CSS, so a preset that anchors to
// the inline-start edge (`grow-x` — horizontal bars, progress fills) grows
// from the physical left in both directions: in RTL the bar is laid out
// against the right edge, so it would grow from its TIP back to its base.
// This var carries the inline-start edge as a percentage; presets read it
// instead of hard-coding `0%`. It INHERITS (unlike the stagger index) —
// that is how a `:dir()` match on an ancestor reaches the animated node.
// Both directions are declared so a subtree that re-declares its own
// direction gets the right value, which is exactly why `[dir='rtl']` is
// forbidden catalogue-wide.
blocks.push(':dir(ltr) {\n\t--motion-origin-inline-start: 0%;\n}')
blocks.push(':dir(rtl) {\n\t--motion-origin-inline-start: 100%;\n}')
// Stagger index is per-item — `inherits: false` stops it leaking into nested
// groups; the rhythm (`--motion-stagger-each`) inherits from the container.
blocks.push(

Loading…
Cancel
Save

Powered by TurnKey Linux.