docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
/**
|
|
|
|
|
* __theming-probe — the before/after computed-style probe of PLAN-theming §7.2/§7.4.
|
|
|
|
|
*
|
|
|
|
|
* node scripts/__theming-probe.ts <component> <out.json> [url]
|
|
|
|
|
*
|
|
|
|
|
* Temporary instrument (the `__` prefix keeps it out of the tracked surface).
|
|
|
|
|
* Walks the component demo, and for every node matching `[data-{c}…]` records
|
|
|
|
|
* the knob computed values at rest, per size, hovered and focused. The size is
|
|
|
|
|
* forced by WRITING `data-size` on the nodes that already carry it — the recipe
|
|
|
|
|
* selects on that attribute, so the computed result is the same one the real
|
|
|
|
|
* interaction produces, without depending on each demo's chips.
|
|
|
|
|
*
|
|
|
|
|
* Run it with plain `node`, NOT with tsx: the tsx loader injects helpers that
|
|
|
|
|
* are not defined inside `page.evaluate`, and every probe throws.
|
|
|
|
|
*
|
|
|
|
|
* Must run from the repo ROOT (playwright does not resolve from the scratchpad)
|
|
|
|
|
* and against a live dev server; a hidden screen freezes rAF, so headless is the
|
|
|
|
|
* reliable surface.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { writeFileSync } from 'node:fs';
|
|
|
|
|
import { chromium } from 'playwright';
|
|
|
|
|
|
|
|
|
|
const PROPS = [
|
|
|
|
|
'backgroundColor',
|
|
|
|
|
'backgroundImage',
|
|
|
|
|
'color',
|
|
|
|
|
'borderTopColor',
|
|
|
|
|
'borderTopWidth',
|
|
|
|
|
'borderTopLeftRadius',
|
|
|
|
|
'borderBottomRightRadius',
|
|
|
|
|
'paddingTop',
|
|
|
|
|
'paddingRight',
|
|
|
|
|
'paddingBottom',
|
|
|
|
|
'paddingLeft',
|
|
|
|
|
'rowGap',
|
|
|
|
|
'columnGap',
|
|
|
|
|
'fontSize',
|
|
|
|
|
'fontWeight',
|
|
|
|
|
'fontFamily',
|
|
|
|
|
'lineHeight',
|
|
|
|
|
'letterSpacing',
|
|
|
|
|
'blockSize',
|
|
|
|
|
'inlineSize',
|
|
|
|
|
'minBlockSize',
|
|
|
|
|
'minInlineSize',
|
|
|
|
|
'boxShadow',
|
|
|
|
|
'opacity',
|
|
|
|
|
'fill',
|
|
|
|
|
'stroke',
|
|
|
|
|
'outlineColor',
|
|
|
|
|
'outlineWidth',
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
'filter',
|
|
|
|
|
'backdropFilter'
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const SIZES = ['xs', 'sm', 'md', 'lg', 'xl'];
|
|
|
|
|
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
/**
|
|
|
|
|
* Demo controls that must be ON before measuring: a part the demo does not
|
|
|
|
|
* mount is a part the diff never compares, and a probe over two nodes passes
|
|
|
|
|
* in false (the F2-B lesson — count the nodes before believing a green gate).
|
|
|
|
|
* text-gradient boots with `showBorder=false`, so its whole frame — three of
|
|
|
|
|
* its seven tokens — is absent from the default stage.
|
|
|
|
|
*/
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
/**
|
|
|
|
|
* Components whose PARTS are not tagged `data-{c}-*`: prose styles bare HTML
|
|
|
|
|
* (h1, code, table…) through `:where([data-prose] el)`, so the attribute filter
|
|
|
|
|
* below sees exactly ONE node and the gate proves nothing. The selector's
|
|
|
|
|
* matches join the measured set.
|
|
|
|
|
*/
|
|
|
|
|
const EXTRA_NODES: Record<string, string> = {
|
|
|
|
|
prose: '[data-prose] *'
|
|
|
|
|
};
|
|
|
|
|
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const DEMO_VARIANTS: Record<string, string[]> = {
|
|
|
|
|
'text-gradient': [
|
|
|
|
|
'[data-uix-control]:has([data-uix-control-label]:text-is("showBorder")) [data-uix-chip]:text-is("true")'
|
|
|
|
|
]
|
|
|
|
|
};
|
|
|
|
|
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
async function main() {
|
|
|
|
|
const [component, out, urlArg] = process.argv.slice(2);
|
|
|
|
|
if (!component || !out) throw new Error('usage: <component> <out.json> [url]');
|
|
|
|
|
const url = urlArg ?? `http://localhost:5173/uix/components/${component}`;
|
|
|
|
|
|
|
|
|
|
const browser = await chromium.launch();
|
|
|
|
|
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
|
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
// A demo that is still LOADING measures a different instant on every run:
|
|
|
|
|
// feed's auto load-more keeps [data-busy] for ~3s and its commit-settle
|
|
|
|
|
// firma animates box-shadow on the very node under measurement (5 phantom
|
|
|
|
|
// diffs between two runs of the same code, 2026-08-21). Wait for the busy
|
|
|
|
|
// window to close before every snapshot.
|
|
|
|
|
const settle = () =>
|
|
|
|
|
page
|
|
|
|
|
.waitForFunction(() => !document.querySelector('[data-busy]'), null, { timeout: 15000 })
|
|
|
|
|
.catch(() => {});
|
|
|
|
|
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
// Every load resets the demo's controls, so the variant chips are re-clicked
|
|
|
|
|
// after each one — the probe reloads once per size, plus open and hover.
|
|
|
|
|
const variants = async () => {
|
|
|
|
|
for (const sel of DEMO_VARIANTS[component] ?? []) {
|
|
|
|
|
const el = page.locator(sel).first();
|
|
|
|
|
if (!(await el.count())) throw new Error(`variant selector matches nothing: ${sel}`);
|
|
|
|
|
await el.click({ timeout: 2000 });
|
|
|
|
|
await page.waitForTimeout(200);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const prepare = async () => {
|
|
|
|
|
await settle();
|
|
|
|
|
await variants();
|
|
|
|
|
};
|
|
|
|
|
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
await page.goto(url, { waitUntil: 'networkidle' });
|
|
|
|
|
await page.waitForTimeout(600);
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
await prepare();
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
const measure = (c: string, props: string[], size: string | null) =>
|
|
|
|
|
page.evaluate(
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
([kebab, keys, forced, extra]) => {
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const root = document.querySelector('[data-uix-stage]') ?? document.body;
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const nodes = [...root.querySelectorAll<HTMLElement>('*')].filter(
|
|
|
|
|
(n) =>
|
|
|
|
|
[...n.attributes].some((a) => a.name.startsWith(`data-${kebab}`)) ||
|
|
|
|
|
(extra ? n.matches(extra as string) : false)
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
);
|
|
|
|
|
if (forced)
|
|
|
|
|
for (const n of nodes)
|
|
|
|
|
if (n.hasAttribute('data-size')) n.setAttribute('data-size', forced);
|
|
|
|
|
const key = (n: HTMLElement) => {
|
|
|
|
|
const attrs = [...n.attributes]
|
|
|
|
|
.filter((a) => a.name.startsWith('data-') && !a.name.startsWith('data-event'))
|
|
|
|
|
.map((a) => (a.value ? `${a.name}=${a.value}` : a.name))
|
|
|
|
|
.sort()
|
|
|
|
|
.join('|');
|
|
|
|
|
return `${n.tagName.toLowerCase()}[${attrs}]`;
|
|
|
|
|
};
|
|
|
|
|
const seen = new Map<string, number>();
|
|
|
|
|
const rows: Record<string, Record<string, string>> = {};
|
|
|
|
|
for (const n of nodes) {
|
|
|
|
|
const base = key(n);
|
|
|
|
|
const i = (seen.get(base) ?? 0) + 1;
|
|
|
|
|
seen.set(base, i);
|
|
|
|
|
const cs = getComputedStyle(n);
|
|
|
|
|
const row: Record<string, string> = {};
|
|
|
|
|
for (const k of keys as string[]) row[k] = cs[k as keyof CSSStyleDeclaration] as string;
|
|
|
|
|
rows[`${base}#${i}`] = row;
|
|
|
|
|
}
|
|
|
|
|
return rows;
|
|
|
|
|
},
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
[c, props, size, EXTRA_NODES[c] ?? null] as const
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const result: Record<string, unknown> = {};
|
|
|
|
|
result.rest = await measure(component, PROPS, null);
|
|
|
|
|
for (const size of SIZES) {
|
|
|
|
|
await page.reload({ waitUntil: 'networkidle' });
|
|
|
|
|
await page.waitForTimeout(400);
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
await prepare();
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
result[`size:${size}`] = await measure(component, PROPS, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open state: a portaled panel lives OUTSIDE the stage, so measure from the
|
|
|
|
|
// document once the trigger has opened it (§7.2 — probe the popup open).
|
|
|
|
|
await page.reload({ waitUntil: 'networkidle' });
|
|
|
|
|
await page.waitForTimeout(400);
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
await prepare();
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const trigger = page.locator(`[data-${component}-trigger], [data-${component}-input]`).first();
|
|
|
|
|
if (await trigger.count()) {
|
|
|
|
|
try {
|
|
|
|
|
await trigger.click({ timeout: 2000 });
|
|
|
|
|
await page.waitForTimeout(500);
|
|
|
|
|
result.open = await page.evaluate(
|
|
|
|
|
([kebab, keys]) => {
|
|
|
|
|
const nodes = [...document.querySelectorAll<HTMLElement>('*')].filter((n) =>
|
|
|
|
|
[...n.attributes].some((a) => a.name.startsWith(`data-${kebab}`))
|
|
|
|
|
);
|
|
|
|
|
const seen = new Map<string, number>();
|
|
|
|
|
const rows: Record<string, Record<string, string>> = {};
|
|
|
|
|
for (const n of nodes) {
|
|
|
|
|
const attrs = [...n.attributes]
|
|
|
|
|
.filter((a) => a.name.startsWith('data-') && !a.name.startsWith('data-event'))
|
|
|
|
|
.map((a) => (a.value ? `${a.name}=${a.value}` : a.name))
|
|
|
|
|
.sort()
|
|
|
|
|
.join('|');
|
|
|
|
|
const base = `${n.tagName.toLowerCase()}[${attrs}]`;
|
|
|
|
|
const i = (seen.get(base) ?? 0) + 1;
|
|
|
|
|
seen.set(base, i);
|
|
|
|
|
const cs = getComputedStyle(n);
|
|
|
|
|
const row: Record<string, string> = {};
|
|
|
|
|
for (const k of keys as string[]) row[k] = cs[k as keyof CSSStyleDeclaration] as string;
|
|
|
|
|
rows[`${base}#${i}`] = row;
|
|
|
|
|
}
|
|
|
|
|
return rows;
|
|
|
|
|
},
|
|
|
|
|
[component, PROPS] as const
|
|
|
|
|
);
|
|
|
|
|
} catch {
|
|
|
|
|
/* no openable trigger — skip the state */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hover + focus on every interactive part the recipe could paint.
|
|
|
|
|
await page.reload({ waitUntil: 'networkidle' });
|
|
|
|
|
await page.waitForTimeout(400);
|
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
await prepare();
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const targets = await page.evaluate(([kebab, extra]) => {
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const root = document.querySelector('[data-uix-stage]') ?? document.body;
|
|
|
|
|
return [...root.querySelectorAll<HTMLElement>('*')]
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
.filter(
|
|
|
|
|
(n) =>
|
|
|
|
|
[...n.attributes].some((a) => a.name.startsWith(`data-${kebab}`)) ||
|
|
|
|
|
(extra ? n.matches(extra) : false)
|
|
|
|
|
)
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
.map((n, i) => ({ i, tag: n.tagName.toLowerCase() }))
|
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
.filter((t) => ['button', 'a', 'input', 'li', 'div', 'tr'].includes(t.tag))
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
.slice(0, 24);
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
}, [component, EXTRA_NODES[component] ?? null] as const);
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
const hovered: Record<string, Record<string, string>> = {};
|
|
|
|
|
for (const t of targets) {
|
|
|
|
|
const handle = await page.evaluateHandle(
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
([kebab, idx, extra]) => {
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const root = document.querySelector('[data-uix-stage]') ?? document.body;
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
const all = [...root.querySelectorAll<HTMLElement>('*')].filter(
|
|
|
|
|
(n) =>
|
|
|
|
|
[...n.attributes].some((a) => a.name.startsWith(`data-${kebab}`)) ||
|
|
|
|
|
(extra ? n.matches(extra as string) : false)
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
);
|
|
|
|
|
return all[idx as number] ?? null;
|
|
|
|
|
},
|
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
[component, t.i, EXTRA_NODES[component] ?? null] as const
|
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
);
|
|
|
|
|
const el = handle.asElement();
|
|
|
|
|
if (!el) continue;
|
|
|
|
|
try {
|
|
|
|
|
await el.hover({ timeout: 1500 });
|
|
|
|
|
await page.waitForTimeout(400);
|
|
|
|
|
const row = await el.evaluate((n, keys) => {
|
|
|
|
|
const cs = getComputedStyle(n as HTMLElement);
|
|
|
|
|
const attrs = [...(n as HTMLElement).attributes]
|
|
|
|
|
.filter((a) => a.name.startsWith('data-') && !a.name.startsWith('data-event'))
|
|
|
|
|
.map((a) => (a.value ? `${a.name}=${a.value}` : a.name))
|
|
|
|
|
.sort()
|
|
|
|
|
.join('|');
|
|
|
|
|
const out: Record<string, string> = { __key: attrs };
|
|
|
|
|
for (const k of keys as string[]) out[k] = cs[k as keyof CSSStyleDeclaration] as string;
|
|
|
|
|
return out;
|
|
|
|
|
}, PROPS);
|
|
|
|
|
hovered[`${t.i}:${row.__key}`] = row;
|
|
|
|
|
} catch {
|
|
|
|
|
/* not hoverable (offscreen / covered) — skip */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result.hover = hovered;
|
|
|
|
|
|
|
|
|
|
await browser.close();
|
|
|
|
|
writeFileSync(out, JSON.stringify(result, null, '\t'), 'utf8');
|
|
|
|
|
const count = Object.keys(result.rest as object).length;
|
|
|
|
|
console.log(`probe ${component}: ${count} nodes at rest, ${Object.keys(hovered).length} hovered`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main();
|