docs(direction): cierre del barrido de graficas, la regla de RTL en SVG, y la cola para manana

LAS 11 GRAFICAS DEL CATALOGO, REVISADAS. Ninguna de las siete que quedaban
necesitaba cambios, y por razones distintas que conviene dejar escritas:
bar-list ya lo resuelve con CSS logico; sparkline y bubble-chart heredan el
frame de <Chart> arreglado en 55070c688; y gauge, pie-chart, polar-area y
smith-chart son RADIALES — sus posiciones son angulos, no tienen eje de lectura
y es correcto que no espejen.

LA REGLA, ahora en la fila "RTL · SVG" del contrato de construccion y
desarrollada en eidos/components/chart/README.md §Direction. Son DOS decisiones
y no son la misma:

 1) ¿espeja la composicion? solo si hay EJE DE LECTURA. Se invierte el rango de
    pixeles de la escala, o se refleja la x. Los valores de Y no se espejan
    nunca — un grafico es una secuencia leida como lee el lector, no un espejo.
 2) `text-anchor` es LOGICO: si la composicion espeja se deja tal cual (voltear
    ademas lo cancela); si no espeja se fuerza el fisico.

TRAMPAS DE MEDICION que me engañaron durante toda la sesion, en §7.3: el bbox de
un path espejado es identico al del original —mi "fingerprint" declaro sparkline
sin espejar cuando si lo hacia—; un test de "se sale del SVG" no ve una invasion
hacia DENTRO; el hueco del eje Y hay que medirlo contra el TICK y no contra la
linea; verificar en LTR no revela NADA de un defecto de RTL; y la pagina
"heatmap" tiene dos modos tras un control, asi que capturar el primer svg solo
enseñaba uno.

HANDOFF. La cabecera apunta a la §8 nueva, que es la cola priorizada: scroll-area
(dos señales, sin medir, y le falta una demo con eje horizontal), los agujeros de
OBSERVABILIDAD que impiden verificar drawer y float-panel, las verificaciones
pendientes, y la deuda ajena por gravedad —encabezada por los 91 ficheros de test
que falsifican Soma.require()—. Y una §8.5 con lo que NO hay que rehacer, para
que nadie repita el trabajo medido.

check 74 = linea base exacta.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alpha-0.1-dir-prefs
dev 2 months ago
parent 01b891b645
commit 40db0b9816

@ -35,6 +35,7 @@ defends it today.
| **Touch hit-area** | §37: `--touch-target` (44px) under `pointer: coarse` only — AREA ≠ VISUAL (`::before` slop for bare markers) | targets <44 on touch without slop; growing the visual | archetypes.css coarse rules |
| **Portal typography** | anchor `font-family`+`line-height`+`color` on the portaled content root | inheriting (falls to serif in the portal) | rule (LIVE) |
| **RTL** | **logical** properties (`inline/block`, `inset-inline`) for flow; physical `left/right` ONLY as floating *placement* APIs (EID-3 exception) or where the geometry itself is physical (compass handles, polar arcs, a JS-measured offset); branch on direction with **`:dir(rtl)`** | physical `padding-left`/… in content flow; a logical anchor paired with a physical `translateX` — the anchor flips, the transform does not; `[dir='rtl'] …`, which misses the common no-attribute case and ignores any nearer re-declaration | RTL-1 · `npm run rtl:check` |
| **RTL · SVG** | a graphic with a READING axis mirrors (invert the scale's pixel range); a RADIAL one does not. `text-anchor` is LOGICAL: leave it alone when the composition mirrors, force the physical one when it does not — see `eidos/components/chart/README.md` §Direction | mirroring *and* flipping the anchor (they cancel); flipping the anchor on a gutter that never moves (the label walks across the graphic); mirroring y values | eye, in RTL — RTL-1 reads CSS text and cannot see SVG attrs or JS-written inline geometry |
| **i18n** | `eidos.langs.ts('#?key\|fallback')` + key in the catalog | hardcoded strings / `aria-label`s | rule (LIVE) |
| **Color (values)** | role tokens `--color-*` / recipe tokens | raw hex/rgb/hsl/oklch | R-2.1/2.6 · R-4.6 |
| **Density / spacing** | `--space-*` · `--control-height-*` | fixed px (bypasses density/scaling) | R-2.x |

@ -1,8 +1,9 @@
# CONTINUE — el eje de dirección (RTL/LTR)
> **Kickoff**: _"Lee `docs/process/CONTINUE-direction.md` y empieza por §2.1."_
> **Fecha**: 2026-08-02 · Rama `alpha-0.1-dir-prefs` (sale de `alpha-0.1-sec-dom`).
> **§1 es lo que ya está cerrado — no lo rehagas.** Lo abierto empieza en §2.
> **Kickoff**: _"Lee `docs/process/CONTINUE-direction.md` y sigue por §8."_
> **Fecha**: 2026-08-03 · Rama `alpha-0.1-dir-prefs` (sale de `alpha-0.1-sec-dom`).
> **§1, §6 y §7 son lo cerrado — no lo rehagas.** Lo abierto está en §2 (lo que
> sobrevive), §3 (ajeno al eje) y **§8, que es la cola priorizada para hoy**.
>
> Hermano de este documento: [`CONTINUE-player-rtl.md`](./CONTINUE-player-rtl.md),
> cuyo §1 cerró este hilo. Sus §2–§5 (disposición de botones del player, iconos de
@ -18,7 +19,8 @@
| `013ceac57` | La raíz: `getDir()` reactivo · estampado condicional · `activeDir()` único · 99 ficheros |
| `5469e05df` | 49 demos + arnés `SystemAxes` a `auto·ltr·rtl` · prosa declarada inglesa · 51 ficheros |
| `538f4932b` | El handoff anterior decía que esto seguía roto |
| **sin commitear** | **§2.1 cerrada**: el guard RTL-1 + los 23 hallazgos + los 12 `[dir='rtl']` + el pin del `<main>` (§6) |
| `ec533845d`…`714a1ddb5` | **§2.1 + §2.2 cerradas** (§6): guard RTL-1 · 23 hallazgos · los 12 `[dir='rtl']` → `:dir()` · el pin del `<main>` · tabs · virtualizadores · float-panel · rating-group · splitter · carousel |
| `8086f21d6`…`01b891b64` | **Las gráficas** (§7): 6 defectos de RTL en el chart + funnel, calendar-heatmap, heatmap matriz, radar, y los bloques de código |
Empezó como «el slider no responde al RTL» y eran **dos defectos independientes**:
@ -622,3 +624,133 @@ cerrar, es trabajo de la shell (hacer visible el estado), no del eje.
verificado con stash. Es del hilo del sonido, no de este eje.
- Los 9 CSS tocados ya fallaban `prettier --check` ANTES de tocarlos. No los
formatees: son ficheros enteros de ruido (§5).
---
## 7. Las gráficas — barrido completo del catálogo (2026-08-03)
El usuario abrió este frente con «los chart calculan mal» y una captura. **Me
costó cuatro avisos suyos dar con lo que señalaba**, y la causa de las tres
primeras equivocaciones fue siempre la misma: verificar en LTR, con números, y
sobre un recorte que yo elegía. La regla que sale de aquí está en la fila
**RTL · SVG** del contrato y desarrollada en
`src/uix/eidos/components/chart/README.md` §Direction.
### 7.1 · Las dos decisiones, que NO son la misma
1. **¿Espeja la composición?** Sólo si el gráfico tiene EJE DE LECTURA. Lo
tienen `chart` (escala x), `calendar-heatmap`, la matriz de `heatmap`, el
canalón del `funnel` y `bar-list`. NO lo tienen los radiales (`gauge`,
`pie-chart`, `polar-area`, `radar-chart`, `smith-chart`): sus posiciones son
ángulos. Se espeja invirtiendo el RANGO de píxeles de la escala, o
reflejando la x (`mx()`). **Los valores de Y no se espejan nunca.**
2. **`text-anchor` es LÓGICO.** Si la composición espeja, se deja lógico —
voltearlo además lo cancela. Si NO espeja (canalón del eje Y, radar), se
fuerza el físico con `rtl.anchor()`.
Confundirlas es silencioso y se ve como las etiquetas caminando sobre el
gráfico.
### 7.2 · Estado del catálogo — TODAS revisadas
| | Estado |
| --- | --- |
| `chart` + presets (line/area/bar/bubble/scatter) | Arreglado: eje X espeja · tooltip hereda `formatY` · canalón adaptativo · etiquetas a 9.4px del tick · anchor físico |
| `funnel` | Arreglado: composición espejada (embudo derecha, etiquetas izquierda) |
| `calendar-heatmap` | Arreglado: semanas y canalón de días espejados |
| `heatmap` (matriz) | Arreglado: columnas y canalón de filas espejados |
| `radar-chart` | Arreglado: anchor físico, sin espejar (es radial) |
| `bar-list` | Correcto sin tocar — CSS lógico |
| `sparkline`, `bubble-chart` | Correctos sin tocar — heredan el frame de `chart` |
| `gauge`, `pie-chart`, `polar-area`, `smith-chart` | Correctos sin tocar — radiales |
Y los bloques de código de las demos (`pre/code/kbd/samp`) se declaran `ltr`:
el bidi los volvía ilegibles (`<script lang='ts'>` → `<'script lang='ts>`). Es
la versión ESTRECHA del pin que llevaba `<main data-uix-canvas>`.
### 7.3 · Trampas de medición — me engañaron tres veces
- **El bbox de un path espejado es idéntico al del original.** Mi «fingerprint»
por `getBoundingClientRect` declaró `sparkline` sin espejar cuando sí lo
hacía. Para un espejado hay que mirar la PRIMERA coordenada (`M0,…` vs
`M186,…`), no la caja.
- **Un desborde hacia DENTRO no sale en un test de «se sale del SVG».** El
barrido que escribí buscaba texto fuera del svg y dio 0 en todo mientras las
etiquetas invadían el área de trazado.
- **Medir contra el elemento equivocado.** El hueco del eje Y lo medí contra la
LÍNEA del eje (7px, aceptable) cuando lo que toca es medir contra el TICK, que
sale 4px hacia la etiqueta: quedaban 3.4px y se leía pegado.
- **Verificar en LTR un defecto de RTL.** Tres veces. El `text-anchor` lógico no
se manifiesta en LTR en absoluto.
- **La página completa, no el primer SVG.** La ruta `heatmap` tiene DOS modos
(`matrix` / `calendar`) tras un control; capturando el primer svg sólo veía uno.
### 7.4 · QUEDA en las gráficas
- `radar-chart`: «Economy» empieza en **x=-6**, o sea se sale unos píxeles del
SVG **también en LTR**. Preexistente, no tocado.
- No hay NINGÚN test de chart en el repo. Todo lo de esta sesión está verificado
a ojo y con medidas puntuales, no fijado por tests.
- Sin revisar en RTL: `metrics`, `bar-segment`, `chart-legend` como piezas
sueltas.
---
## 8. La cola para mañana — por orden de valor
### 8.1 · `scroll-area` (lo único del eje con defecto sospechado y sin medir)
Dos señales, ninguna verificada:
- Su `resolvedDir` aparece **una sola vez** en todo el componente — la
declaración. Es código muerto.
- Usa `scrollLeft` en cuatro sitios (`isAtLeft = scrollLeft <= 0`, el ratio del
thumb, el salto por click, el arrastre) sin tratar que **en RTL los
navegadores lo devuelven NEGATIVO**: `isAtLeft` sería siempre cierto y el
ratio del thumb saldría negativo.
⚠️ No está medido porque **el scroll-area de la demo no tiene eje horizontal**
(`maxScroll: 0`). Primero hace falta un ejemplo con scroll horizontal; sin eso
no es observable. El usuario ya confirmó que el componente «funciona» en lo
demás, y medido: con el toggle en `auto`, ES→ltr y AR→rtl llegan bien.
### 8.2 · Agujeros de OBSERVABILIDAD (bloquean verificar, no rompen nada)
- **`drawer`**: su demo sólo expone `top/right/bottom/left`. La mitad LÓGICA
(`start`/`end`), que es la única que ejercita RTL, no se puede ver. El
componente está bien por lectura (`resolveDirection()` es el ejemplo a imitar)
y verificado sólo en su mitad física.
- **`float-panel`**: su demo no ancla ningún panel, así que la semilla anclada
—lo que se arregló en `caf3cfd88`— no es observable. Cubierto por
`anchored-seed.test.ts`.
- **§2.3**: cablear `secondaryValue` en la demo del slider.
### 8.3 · Verificaciones que quedaron sin hacer
- `archetypes` y `proof-of-human`: sus reglas viven en `@media (pointer: coarse)`
y se verificaron con `Emulation.setEmulatedMedia`; el resto de esa media query
no se ha mirado.
- **El swipe del `carousel` con un ratón de verdad.** El arreglo de `714a1ddb5`
está medido (el rail sigue al dedo, Δ+100 en ambas direcciones) pero conviene
el gesto real.
- `metrics`, `bar-segment`, `chart-legend` como piezas sueltas en RTL.
### 8.4 · Deuda ajena al eje, por gravedad
1. **91 ficheros de test falsifican `Soma.require()`** con
`vi.spyOn(Soma, 'require').mockReturnValue({ prefs: { getDir: () => dir } })`.
Incumple una Regla Crítica de CLAUDE.md: esa parte de la batería **no
ejercita el código real**. Es un proyecto entero y es lo más grave del
documento.
2. **No hay NINGÚN test de chart** en el repo. Todo lo de §7 está verificado a
ojo, no fijado.
3. `html lang` no sigue al idioma · componentes estampando `dir=""` vacío
(`sidebar`, `tree-view`).
4. **`smoke` y `perm:check` sin ejecutar** en toda la sesión.
### 8.5 · Lo que NO hay que rehacer
- Las 5 de §2.2 (slider, number-field, css-field, dropdown-menu, carousel) están
**medidas y sanas**; el único defecto era el pintado del swipe, ya arreglado.
- El motor `soma/layers/floating` está verificado y cubre sus 9 consumidores.
- `toast` es correcto: su vocabulario es físico y coherente consigo mismo.
- Las 11 gráficas del catálogo están revisadas (§7.2).

@ -103,6 +103,39 @@ Line/Bar/Area/Scatter/Pie/Sparkline cover the dashboard baseline. Heavy types
component; `g · rect · circle · line · figure · figcaption` were added to the
element union + schema (additive).
### Direction (RTL) — the rule for every chart in the family
Two decisions per chart, and they are **not** the same decision:
1. **Does the composition mirror?** Only if the graphic has a READING axis. A
time or category series does (`chart`'s x scale, `calendar-heatmap`,
`heatmap`'s columns, `funnel`'s label gutter, `bar-list`): under RTL the
first datum sits on the right. Radial graphics do NOT (`gauge`, `pie-chart`,
`polar-area`, `radar-chart`, `smith-chart`) — their positions are angles.
Mirroring is done by inverting the pixel RANGE of the x scale, or by
reflecting x coordinates (`mx()`); every mark reads from the same source, so
they all move together. **Y values are never mirrored** — a chart is a
sequence read the reader's way, not a mirror image.
2. **`text-anchor` is LOGICAL.** Under `direction: rtl`, `end` means the LEFT
side. So:
- composition **mirrors** → leave the anchor logical, it already lands right.
Flipping it too cancels the mirroring out.
- composition does **not** mirror (a y-axis gutter, radar labels) → force the
physical anchor with `rtl.anchor()` from `rtl.svelte.ts`.
Getting this backwards is silent and looks like the labels walking across the
graphic. Measured examples: a y-axis label ran to x=59.9 with the axis at 46;
the funnel dropped its whole label column onto the funnel body.
`rtl.svelte.ts` holds both pieces — `physicalAnchor()` and `createChartRtl()`,
which reads the RESOLVED direction off the element (standalone charts have no
`<Chart>` context, and `prefs.getDir()` is not always wired in the tree).
**Verify by LOOKING, in RTL.** Numbers mislead here: the bounding box of a
mirrored path is identical to the unmirrored one, and a label 3.4px from its
tick measures as "no overlap" while reading as contact.
## Gaps
| Item | Disposition |

Loading…
Cancel
Save

Powered by TurnKey Linux.