La revisión de hoy (`REVIEW-theming-2026-08-23.md`, punto P4) destapó que
NINGUNO de los commits de tokenización de la mañana del 23 hizo los pasos 8 y 9
del protocolo: `git show --stat` de los diecisiete sólo tocaba CSS, base.ts, el
ledger y las fichas. Veintidós componentes tokenizados sin la tabla de tokens en
su README y veintiuno sin la pestaña que la enseña viva.
QUÉ ENTRA
- **README «Talla y tema»** en 22 (los 21 con demo + `surface`, que no tiene
ruta). La tabla NO está escrita a mano: se DERIVA de `lib/recipes/base.ts` y
de `theming-sentinel-exceptions.ts`, así que lo que el lector ve es lo que el
contrato dice. Hasta 30 claves va la tabla completa clave → valor por defecto;
por encima, agrupada por parte (con la paleta en su propio grupo, que si no se
come la tabla: button tiene 70 claves de tono de 106). Debajo, lo que el guard
da por silencioso con su razón medida, y la excepción POR PATRÓN cuando la
razón es la cascada de paleta.
- **Pestaña `Tokens`** en los 21 con demo, con el conteo real de claves.
VERIFICADO EN EL NAVEGADOR, LOS 21
Cada pestaña abre y lista exactamente sus claves: menubar 35 · field 68 ·
onion-menu 19 · button 106 · callout 34 · empty-state 26 · dropdown-menu 28 ·
context-menu 28 · checkbox 47 · image 23 · anchor-nav 12 · banner 53 ·
date-range-field 7 · time-range-field 7 · tooltip 23 · section 4 · sticky 1 ·
button-group 1 · qr-code 10 · toggle-group 1 · split-button 1.
⚠ Y el verificador mintió DOS veces antes de acertar: primero buscaba el rótulo
de la cabecera del panel en `innerText` (no lo encontraba aunque la tabla estaba
ahí), y después clicaba con `element.click()` tras `waitUntil: 'load'` — la
página aún NO ha hidratado, así que el `onclick` de Svelte no está enganchado y
el clic no hace nada. Con `networkidle` + el clic de Playwright (que espera a
que el nodo sea accionable), los 21 en verde. Es la ley de siempre: el
instrumento miente primero.
`audio-player` queda fuera: no tiene README propio — hueco aparte, anotado.
Verificación: `npm run check` sin errores nuevos en las 21 demos (los 72
globales son ajenos y preexistentes) · `docs:check` 0 · cada README conserva su
estructura de encabezados y **ninguno gana un hunk de prettier** (mi sección se
formateó dentro de su propio recorte, sin tocar lo ajeno).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cierra el eje de direccion abierto en 013ceac57.
1) LAS 49 DEMOS. Todas hacian `let dir = $state('ltr')` y se lo pasaban
explicito al componente, asi que el interruptor del topbar no movia
ninguna: la prop gana a prefs, que es el contrato. Pasan al patron de tres
estados `auto | ltr | rtl` con `auto` por defecto, que es lo que recibe un
consumidor real — sin prop, resolviendo por prefs. Elegir ltr/rtl sigue
demostrando que la prop pisa. El arnes compartido SystemAxes va al mismo
patron, y las 22 demos que lo bindean pasan a bindear el modo.
El tooltip ya tenia tres estados con '' como "inherit" — mismo concepto,
otro nombre; normalizado a `auto`.
2) LA PROSA. `<main data-uix-canvas dir="ltr" lang="en">`. La copia de la
documentacion esta escrita en ingles, asi que se DECLARA inglesa. Sin eso,
al voltear la shell a RTL el algoritmo bidi mueve la puntuacion neutra
final al extremo visual izquierdo y "What is morfo?" se lee "?What is
morfo" — bidi correcto sobre una declaracion falsa. `dir="ltr"` lo arregla
y ademas AISLA la tirada en un solo atributo: la hoja de estilos de agente
del WHATWG da `[dir=ltr i] { unicode-bidi: isolate }`, verificado en la
fuente. NO `dir="auto"`: la spec llama a su heuristica de primer-caracter
"very crude" y aqui ya sabemos la respuesta.
LO QUE ESTO NO ARREGLA, y es correcto que no lo haga: el texto ingles
DENTRO de un componente que declara rtl sigue mostrando el artefacto. El
componente hace bien en estar en rtl —es lo que pidio el usuario— y el
contenedor de arriba no entra en el. Eso solo se cierra traduciendo el
contenido de la demo o marcandolo; es la parte que las cinco librerias de
referencia dejan explicitamente al consumidor.
Verificado: check 74 = linea base exacta. smoke: las 49 rutas tocadas
PASAN; los 3 fallos de la pasada (/demos/motion, /temas,
/uix/components/card) son inestables — ninguno esta en el diff, y la
pasada sin mis cambios fallo en dos rutas DISTINTAS (/demos/cristal,
/demos/heroscrolling). En Chrome: elegir arabe voltea calendar, tabs y
slider por derivacion mientras la prosa se queda legible en ltr.
NOTA DE METODO: un `prettier --write` sobre todas las demos genero 165
ficheros y +31k lineas de ruido, y rompio dos atributos normalizando
`data-perm-mode='type="X"'` a comillas dobles. Revertido y reaplicado solo
el cambio de direccion: 49 ficheros, +357/-161.
QUEDA: `html lang` no sigue al idioma (el dir si); perm:check sin ejecutar
—el topbar ya lleva data-perm-step, lo que hace que toda ruta tenga paso.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Widens `avoidCollisions` from `boolean` to `boolean | 'flip'` on the 6 overlays
that expose it (combobox, context-menu, dropdown-menu, link-preview, select,
tooltip) — the FloatingContent engine already decoupled flip from shift, so
'flip' (flip-only, no slide) works everywhere and lets an arrowless, non-shift
overlay take the native CSS-anchor path. Additive: `boolean` is unchanged.
- Public prop types + provider opts widened (types.ts + *-provider). JSDoc on
the 3 descriptive ones (combobox/select/tooltip) documents the 3 modes; the
terse `@default true` menu types keep their inline style (the type shows 'flip').
- Demos: the 4 that had an avoidCollisions checkbox (dropdown-menu, context-menu,
link-preview, tooltip) now expose a 3-way full/flip/off control.
Verified in a real foreground browser (Claude-in-Chrome):
- dropdown-menu + avoidCollisions='flip' + no arrow → routes to NATIVE
(data-floating-native, position-anchor link to trigger, zero JS transform,
placed correctly).
- context-menu correctly STAYS on JS with 'flip' — it anchors to the cursor
(a Measurable), which the dispatcher's virtualAnchor gate forces to JS. The
discriminator works as designed.
- tooltip / link-preview 3-way controls render.
0 new check errors; 41 overlay + floating tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two items from src/uix/PENDIENTES.md:
- Tooltip D-4.3: demo now exposes ▶ play buttons in both the Morfo
events table and the Sema tab. Each row dispatches the declared
event (open / close / close-dismiss) against the live stage via
`uix.events.emit({ name, family, target })`. Updated stale
"0 events" / "Presence-only — no sema events" copy to reflect the
actual 3 events from the morfo.
- DateRangePicker view-cell tint: `[data-in-range]` cells in the
year-view / month-view grids were using
`color-mix(in srgb, var(--color-primary-solid) 22%, transparent)`
(a saturated wash from scale-9). Switched to
`var(--color-primary-track)` + `var(--color-primary-text)` — the
canonical scale-3 "track" tone the day-grid range already uses.
Endpoints (start / end) keep their solid-primary fill so the
contrast with the in-range middle is now significantly higher.
Test result unchanged: 2391/2397 passing. No regressions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>