|
|
# PLAN — Theming: que TODO componente sea personalizable por un tema (eje `theme-reach`)
|
|
|
|
|
|
> **Estado (act. 2026-08-20): EN EJECUCIÓN — 7 componentes corregidos, 20
|
|
|
> fichas revisadas; las D-TH.1…8 de §4 FIRMADAS TODAS el 2026-08-20** (más las
|
|
|
> tres decisiones hermanas del mismo día: familia calendar = capa compartida,
|
|
|
> mandato Field ejecutable, hover→capa de estado — ver «Firmas del 2026-08-20»
|
|
|
> del CONTINUE). El registro con cifras y commits está en §8, y el punto
|
|
|
> de entrada diario es [`CONTINUE-theming.md`](./CONTINUE-theming.md). Toda
|
|
|
> decisión NUEVA que surja se sigue presentando una por mensaje, con las
|
|
|
> cinco preguntas.
|
|
|
>
|
|
|
> **Origen (conversación 2026-08-19)**: al arreglar `navigation-menu` salió que
|
|
|
> el radio de su trigger vivía en un privado clavado a `--radius-default` y que
|
|
|
> el contrato del componente sólo publicaba tres knobs: ningún tema podía decir
|
|
|
> «píldora» sin mover el radio del sistema entero. El autor, textual: **«esto
|
|
|
> ha abierto una duda importante, y es si los componentes creados son
|
|
|
> themables; si no lo son, es un error como framework. Necesitaríamos
|
|
|
> desarrollar un plan para auditar todos los componentes, verificar qué grado
|
|
|
> de personalización soportan y desarrollar una corrección a cada uno de ellos
|
|
|
> para que sean totalmente personalizables.»** Y sobre la ejecución: **«lo
|
|
|
> ejecutará Opus, y Opus falla mucho, por lo que tienes que establecer procesos
|
|
|
> de verificación en todo el plan.»** Este documento obedece a las dos frases:
|
|
|
> §1 es la auditoría MEDIDA (reproducible por script, no por memoria), §5 son
|
|
|
> las fases, y §7 es el protocolo de verificación que cada sesión ejecuta sin
|
|
|
> excepción.
|
|
|
>
|
|
|
> **Kickoff para sesión nueva**: _«Lee `docs/process/PLAN-theming.md` ENTERO y
|
|
|
> después `CONTINUE-theming.md`; si las D-TH de §4 están firmadas, ejecuta el
|
|
|
> siguiente bloque de §5 con el protocolo de §7, un componente por commit; si
|
|
|
> no, PARA y preséntalas una a una.»_
|
|
|
>
|
|
|
> Fuentes de doctrina que este plan cita y NO copia:
|
|
|
> [`docs/theming/reference.md`](../theming/reference.md) §1bis, §3, §5, §6,
|
|
|
> §7, §12, §16 · [`docs/canon/tsc.md`](../canon/tsc.md) ·
|
|
|
> [`docs/canon/recipe-contract.md`](../canon/recipe-contract.md) §1–§5 ·
|
|
|
> [`docs/theming/motion.md`](../theming/motion.md) §"When both write
|
|
|
> `animation` on ONE node" · [`docs/guides/component-guide.md`](../guides/component-guide.md)
|
|
|
> §Build contract · [`src/uix/eidos/components/README.md`](../../src/uix/eidos/components/README.md)
|
|
|
> · el precedente ejecutado y firmado: [`PLAN-sidebar.md`](./PLAN-sidebar.md)
|
|
|
> §3 + F3 (el eje `size` de la fila, 2026-08-19) y `navigation-menu`
|
|
|
> (`ae9e277fa` · `a82794845`, el cromo del trigger en tokens públicos).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 0. Veredicto corto
|
|
|
|
|
|
1. **La doctrina ya lo exige; los guards no lo comprueban.** recipe-contract §1:
|
|
|
«Every recipe declares its knobs in `lib/recipes/base.ts`»; theming §6: el
|
|
|
token público de componente es `--{c}-{slot}`; la TSC decide dónde se emite.
|
|
|
Pero R-1…R-4 comprueban que **no haya literales** (y que lo que haya sea un
|
|
|
`var(`), no que cada knob sea **alcanzable por un tema**. Una receta con
|
|
|
todo en `var(--radius-md)` y en privados `--_{c}-*` pasa `component:audit`
|
|
|
en PASS y la dimensión 10 «Adopción theming» de la ficha en ✓ — y sólo se
|
|
|
puede temar moviendo el planeta. Es un error de framework porque rompe la
|
|
|
promesa que el framework hace por escrito.
|
|
|
2. **Medido, no opinado** (§1, `scripts/theming-census.ts`): de 5.205 knobs
|
|
|
de apariencia en 162 recetas, **1.621 (33 %) pasan por un token público del
|
|
|
componente**; 1.880 atan directo a un primitivo global; 856 a privados;
|
|
|
614 son literales. **62 componentes no tienen una sola entrada en el
|
|
|
contrato**; 59 tienen alcance < 20 %; 6 están al 100 %. `navigation-menu`,
|
|
|
tras el trabajo de hoy, está en 44 %: el eje no se cierra arreglando un
|
|
|
componente.
|
|
|
3. **La corrección es mecánica y ya tiene forma firmada**: la de la fila del
|
|
|
`Sidebar` (D-SB.5/D-SB.6, `PLAN-sidebar.md` §3) y la del trigger del nav
|
|
|
(`ae9e277fa`): tokens públicos por talla que apuntan al bundle
|
|
|
`--size-{k}-*`, nombre RESUELTO por `data-size`, acentos de estado en
|
|
|
`background-color`, y **el default queda idéntico** — sólo cambia quién
|
|
|
puede moverlo. Lo que NO hay que hacer: rediseñar nada por el camino.
|
|
|
4. **Sin guard no hay cierre**: el censo de hoy se repetirá en seis meses si
|
|
|
R-5 no existe. F0 crea el guard en `warn` con la cifra de hoy como suelo; F3
|
|
|
lo gradúa a `error` cuando el backfill termina. Igual que hizo R-4.x el
|
|
|
2026-07-02.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 1. Inventario medido (2026-08-19)
|
|
|
|
|
|
**Instrumento**: `node --import tsx/esm scripts/theming-census.ts` (añadido
|
|
|
con este plan; `--json` para máquina; `--only {c}` por componente). Cuenta, por
|
|
|
receta CSS, cada declaración de APARIENCIA (lista `KNOB_PROPS` en el script:
|
|
|
fondo, tinta, borde, radio, sombra, padding, gap, tipografía, tamaño, opacidad,
|
|
|
fill/stroke, filtros) y la clasifica por el ORIGEN de su valor:
|
|
|
|
|
|
| Clase | Qué es | ¿La alcanza un tema de componente? |
|
|
|
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
|
| `public` | `var(--{c}-…)` — token del contrato del componente | **Sí** |
|
|
|
| `private` | `var(--_{c}-…)` — nombre interno | No (salvo que el privado DERIVE de un público — el script no lo distingue, cuenta como no) |
|
|
|
| `global` | cualquier otro `var(--…)`: `--space-*`, `--radius-*`, `--color-*`, `--font-size-*`, `--size-*`… | Sólo moviendo el sistema |
|
|
|
| `literal` | sin `var(`: `8px`, `1.25`, `#fff` | No, y además viola R-4/R-2 |
|
|
|
| `system` | sistemas transversales que una receta CONSUME: capa de estado, anillo de foco, planos de depth, motion, bandas z, opacidad, shape, `floating-gap` | Sí, **a nivel de sistema**, por diseño (recipe-contract §2) — fuera del ratio |
|
|
|
|
|
|
**Alcance** = `public / (public + private + global + literal)`.
|
|
|
|
|
|
### 1.1 Totales
|
|
|
|
|
|
| Medida | Valor |
|
|
|
| -------------------------------------- | ---------------- |
|
|
|
| Componentes con receta CSS | 162 |
|
|
|
| Knobs de apariencia | 5.205 |
|
|
|
| Por token público del componente | **1.621 (33 %)** |
|
|
|
| Por privado | 856 |
|
|
|
| Directo a primitivo global | 1.880 |
|
|
|
| Literales | 614 |
|
|
|
| Sistema transversal (fuera del ratio) | 234 |
|
|
|
| **Sin ninguna entrada en el contrato** | **62** |
|
|
|
| Alcance < 20 % | 59 |
|
|
|
| Alcance = 100 % | 6 |
|
|
|
| Con eje `data-size` en la receta | 82 |
|
|
|
|
|
|
### 1.2 Por familia (propuesta de familias en D-TH.4 — el autor la firma o la cambia)
|
|
|
|
|
|
| Familia | Comp. | Knobs | Alcance | Sin contrato | Fuera del contrato |
|
|
|
| ----------------------------------- | ----: | ----: | ------: | -----------: | -----------------: |
|
|
|
| Tiempo (chronos · fecha/hora) | 15 | 879 | 9 % | 9 | 774 |
|
|
|
| Campos | 24 | 905 | 38 % | 9 | 526 |
|
|
|
| Controles · marcas | 33 | 867 | 39 % | 9 | 502 |
|
|
|
| Menús · listas · navegación | 24 | 735 | 37 % | 10 | 432 |
|
|
|
| Superficies · overlays · estado | 34 | 807 | 45 % | 10 | 429 |
|
|
|
| WIP (`palabras`) | 1 | 471 | 22 % | 1 | 363 |
|
|
|
| Texto · tipografía | 12 | 238 | 9 % | 10 | 217 |
|
|
|
| Media · chat | 9 | 283 | 61 % | 1 | 104 |
|
|
|
| Layout (primitivos) | 9 | 14 | 93 % | 3 | 1 |
|
|
|
| (`separator`, sin familia asignada) | 1 | 6 | 67 % | 0 | 2 |
|
|
|
|
|
|
### 1.3 Los tres defectos que el censo NO ve y la ejecución sí tiene que mirar
|
|
|
|
|
|
El script es un regex sobre texto: sobre-reporta, nunca infra-reporta. Tres
|
|
|
clases de defecto de theming que un alcance del 100 % no garantiza:
|
|
|
|
|
|
- **Privado que no deriva de un público** (`--_c-radius: var(--radius-default)`):
|
|
|
cuenta como `private`; la corrección es que el privado lea el público o
|
|
|
desaparezca.
|
|
|
- **Velo o acento en el nodo equivocado**: `archetype: 'item'` en un `<li>`
|
|
|
envoltorio (`navigation-menu`, `822b78cf2`), o el shorthand `background`
|
|
|
matando la capa de estado (`Sidebar` F3, `navigation-menu` `ae9e277fa`). No
|
|
|
es un knob: es un nodo. Se detecta midiendo desde el píxel hacia arriba (§7.3).
|
|
|
- **Doble animación al mover un sello** a una superficie con animación propia
|
|
|
(`navigation-menu` `822b78cf2`: `present-rise` + la entrada de receta). Se
|
|
|
detecta con un registro de `animationstart/end`, no con `getComputedStyle`.
|
|
|
|
|
|
### 1.4 Tabla completa por componente
|
|
|
|
|
|
Al final del documento (§9), ordenada por alcance. Se REGENERA con el script
|
|
|
en cada bloque; no se edita a mano.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 2. Contrato objetivo — qué significa «totalmente personalizable» (los cuatro ejes)
|
|
|
|
|
|
Un componente es personalizable cuando un tema puede moverlo **sin tocar el
|
|
|
sistema ni la receta**, en estos ejes:
|
|
|
|
|
|
| Eje | Mecanismo canónico | Cómo se comprueba |
|
|
|
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
|
| **A · Tokens** (forma, color, espacio, tipografía) | todo knob de apariencia lee `--{c}-{slot}` del contrato (`recipes/base.ts`), nombre RESUELTO por talla/estado; los privados sólo derivan de públicos | censo al 100 % **+** prueba de centinela (§7.4) |
|
|
|
| **B · Talla** | `size` → `data-size` en el wrapper; tokens `{part}-{eje}-{k}` apuntando al bundle `--size-{k}-*` (theming §5; recipe-contract §1) | computed por talla = bundle; `md` idéntico al default anterior |
|
|
|
| **C · Color / variante** | `data-color` / `data-variant` vía paleta (`--{c}-{role}-{slot}`, `--{c}-palette-*`), los 9 roles (theming §4) | cada variante lee tokens, ninguna un `--scale-*` (R-4.6) |
|
|
|
| **D · Estados** | hover/press/selected neutros = la capa del sistema en el nodo CON forma; acentos de estado (`on-bg`…) en `background-color` para que la capa componga | `background-image` presente en hover, `<li>`/envoltorios sin velo, abierto + hover = acento + capa |
|
|
|
|
|
|
**Regla de oro del eje**: **el default no cambia.** Cada componente se mide
|
|
|
antes y después en sus estados (reposo · hover · activo/abierto · disabled ·
|
|
|
foco) y tallas, y el diff de computed styles es **cero** salvo donde una
|
|
|
decisión firmada diga lo contrario. Este eje mueve QUIÉN puede cambiar cada
|
|
|
cosa, no QUÉ se ve.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 3. Contrato objetivo — la regla R-5 «alcance de tema»
|
|
|
|
|
|
Nueva regla de `component-audit` (familia R-5), misma mecánica que R-4.x:
|
|
|
|
|
|
- **R-5.1** — Toda declaración de apariencia (`KNOB_PROPS`) en una receta lee
|
|
|
(a) un público `var(--{c}-…)`, (b) un privado `--_{c}-*` cuya definición en
|
|
|
la misma receta lee un público, o (c) un token de sistema transversal (la
|
|
|
lista `SYSTEM` del censo). Otra cosa es fallo.
|
|
|
- **R-5.2** — Todo componente con receta tiene entrada en `recipes/base.ts`.
|
|
|
- **R-5.3** — Los nombres de los tokens siguen recipe-contract §1 (ejes
|
|
|
lógicos, `{part}-{eje}-{k}`) y theming §6 regla 7 (slots de color: `bg, fg,
|
|
|
border, on-bg, on-fg, on-border, hover-bg, on-hover-bg`). **Hoy no se
|
|
|
cumple** ni en recetas viejas (`tabs`: `trigger-color-*`) ni en las de hoy
|
|
|
(`navigation-menu`: `trigger-bg-active`, `trigger-color-active`) — ver
|
|
|
D-TH.6.
|
|
|
- **Válvula** (recipe-contract §3): `R-5.1 exception: <razón>` en el README
|
|
|
del componente, greppable, UNA por knob o grupo de knobs con la razón (p. ej.
|
|
|
«glifo ∝ diámetro, excepción canónica avatar/marker»). Sin razón escrita no
|
|
|
hay excepción.
|
|
|
- **Severidad**: `warn` desde F0 con el suelo del censo; `error` en F3 (D-TH.7
|
|
|
— firmada con enmienda: **R-5.3 gradúa a `error` directo tras el codemod**,
|
|
|
su deuda muere en el mismo pass; R-5.1/5.2 esperan F3).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 4. Decisiones que firma el autor (una por mensaje, con sus cinco preguntas)
|
|
|
|
|
|
| Id | Decisión | Propuesta | Estado |
|
|
|
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
|
| **D-TH.1** | ¿R-5 es regla DURA? («todo knob público salvo sistema transversal o excepción firmada») | Sí. Es lo que recipe-contract §1 ya dice sin guard. | **FIRMADA 2026-08-20** tal cual. Ancla: la medición 2026-07-01 (canon sin guard deriva 30-85 %) y el mandato origen del eje. |
|
|
|
| **D-TH.2** | Perímetro de «knob» | La lista `KNOB_PROPS` del script (apariencia; layout fuera). Cambios a la lista = cambio del guard, firmados aquí. | **FIRMADA 2026-08-20** con la opción (b) de la ficha `heading`: la familia tipográfica B5 mide su superficie por `--style-*` como sistema transversal (verdad estructural — la vertebración tipográfica RECHAZA acoplar componentes a la capa semántica; acuñar `--heading-*` = 36 alias de una capa ya pública, la clase que §39 mató). No se acuñan `--{c}-*` para los primitivos tipográficos. |
|
|
|
| **D-TH.3** | Tracks WIP (`palabras`, `words`, `chronos` y su familia de fecha/hora) | En el CENSO siempre; en R-5 `error` sólo cuando salgan de su carril (coherente con R-4.x, que los excluye). | **FIRMADA 2026-08-20** tal cual. |
|
|
|
| **D-TH.4** | Familias y ORDEN del backfill | El de §5 F2: menús/navegación → campos → controles → superficies → texto → media/chat → tiempo (el último por ser el más grande y estar en carril propio). Dentro de cada familia, sin contrato primero, luego por knobs fuera del contrato. | **FIRMADA 2026-08-20** con enmienda: la cola REVISADA del CONTINUE (fichas con veredicto §5 verificado) tiene prioridad sobre el orden de familias — trabajo revisado no se deja enfriar. |
|
|
|
| **D-TH.5** | El default NO cambia en este eje | Sí. Toda mejora visual que aparezca se anota como deuda y se firma aparte (como hoy con `navigation-menu`). | **FIRMADA 2026-08-20** sin matices — es lo que hace verificable el eje (diff de computed = 0 como gate). Única excepción viva: la migración hover→capa de estado, firmada aparte el mismo día (ver «Firmas del 2026-08-20» del CONTINUE), que mueve píxel con captura y diff explicado. |
|
|
|
| **D-TH.6** | Vocabulario de slots (R-5.3): ¿se NORMALIZAN los nombres que ya se desvían (`trigger-color-*` de `tabs`, `*-bg-active`/`*-color-active` del nav de hoy, …) con un codemod value-preserving como el de px/py del 2026-07-06? | Sí, en F1, ANTES del backfill — si no, el backfill escribirá más nombres fuera de vocabulario. Inventario exacto de desviaciones sale en F0 (el censo añade `--names`). | **FIRMADA COMPLETA 2026-08-20**, en dos actos. (1) El slot de tinta es **`fg`**; `color` como slot MUERE (196 claves cola). Razón: el principio de plataforma del 2026-07-06 gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` (si gobernara, `bg` sería `background-color`); `color` colisiona con `--color-*`, `data-color` y los 9 roles; `on-fg` compone. (2) Modificador recipe-level DELANTE — regla: **delante lo interactivo, detrás lo dimensional y contextual** (`hover-bg` pero `control-height-md`, `scrim-fg-over-dark`); rol/paleta conserva su gramática propia (detrás, `COLOR_ROLE_SLOTS` — las 47 `{rol}-{slot-de-rol}` son canónicas). Modificador válido ∈ vocabulario universal (+`current`, aria) ∪ valores `data-state`/ejes del MORFO del componente (así `partial` de rating-group y `read/failed` de chat-message validan contra el compilado, igual que la parte). `waveform.played/buffered` = pseudo-partes eidos-only (`played-fg`). Los hovers neutros se EXCLUYEN del codemod: migran a la capa de estado (firma aparte, mismo día). Detalle operativo: CONTINUE §«Mañana». |
|
|
|
| **D-TH.7** | Cuándo gradúa R-5 a `error` | Cuando el censo global dé 100 % o excepción documentada (F3), nunca antes de terminar F2 — un `error` a medio backfill rompe el `component:audit` de todo el parque. | **FIRMADA 2026-08-20** con enmienda: **R-5.3 (gramática de nombres) gradúa a `error` DIRECTO tras el codemod** — su deuda muere en el mismo pass (precedente R-4.4, «sin allowlist»). R-5.1/R-5.2 esperan F3 como propone la fila. |
|
|
|
| **D-TH.8** | ¿Entra la exposición en la demo de temas (`/temas`: un panel que liste los tokens públicos por componente y permita moverlos)? | Sí pero DESPUÉS (F4, opcional): es la prueba viva de A; sin el backfill no hay nada que exponer. | **FIRMADA 2026-08-20** tal cual — el instrumental existe (`listRecipes()` / `getRecipeTokens()`; la ruta `/temas` existe). |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 5. Fases y gates
|
|
|
|
|
|
Cada fase: **qué leer ANTES** (entero), **qué producir**, **guard**. Ninguna
|
|
|
arranca sin la anterior en verde. Todo bloque de F2 ejecuta el protocolo de §7
|
|
|
**por componente**, sin atajos: es la parte del plan que existe porque «Opus
|
|
|
falla mucho».
|
|
|
|
|
|
### F0 — Instrumento + guard en `warn` (una sesión)
|
|
|
|
|
|
- Leer: theming §1bis, §3, §5, §6, §7, §12, §16 · tsc.md entero ·
|
|
|
recipe-contract §1–§5 · `scripts/component-audit.ts` (cómo se declara una
|
|
|
regla R-x, `readmeException`, severidades) · `src/uix/eidos/recipe-css-contract.test.ts`
|
|
|
(qué ya guarda) · `PLAN-sidebar.md` §3 y F3 · este plan entero.
|
|
|
- Producir: (a) `scripts/theming-census.ts` endurecido: `--names` (inventario
|
|
|
de nombres de token fuera del vocabulario §1/§6.7), detección «privado que
|
|
|
deriva de público» (leer `--_c-x: var(--c-y)` en la misma receta y
|
|
|
reclasificar), salida `--json` estable; (b) **R-5.1/5.2/5.3 en
|
|
|
`component-audit`** con severidad `warn` y la válvula `R-5.x exception:`;
|
|
|
(c) `docs/theming/reference.md` §12 (tabla de tooling) gana la fila del censo;
|
|
|
(d) un test `scripts/theming-census.test.ts` o bajo `src/uix/eidos/` que
|
|
|
**fije el suelo**: alcance global ≥ el de hoy (33 %) y literales ≤ 614 — el
|
|
|
número SUBE o el test falla (muta-prueba: meter un literal en una receta y ver
|
|
|
el rojo antes de dar el test por bueno — memoria `a-guard-that-inspects-nothing-passes`.
|
|
|
Ya pasó una vez HOY: la primera versión del censo no contaba una regla de una
|
|
|
sola línea, y la mutación `padding-inline: 8px` no movió la cifra; se endureció
|
|
|
el regex y la mutación pasó a 6→7→8).
|
|
|
- Guard: `node --import tsx/esm scripts/theming-census.ts` reproduce §1.1 a
|
|
|
la cifra · `npm run component:audit` NO añade ningún `error` (sólo `warn`) ·
|
|
|
`npx vitest run src/uix/eidos` sin nuevos rojos (el rojo conocido es
|
|
|
`skin-media-player`, ajeno) · `npm run check` con cero errores en los
|
|
|
ficheros tocados (§7.6).
|
|
|
|
|
|
### F1 — Doctrina + vocabulario (una sesión)
|
|
|
|
|
|
- Leer: F0 + theming §6 (reglas estrictas) + el codemod del 2026-07-06
|
|
|
(recipe-contract §1, bloque «Normalización ejecutada») como molde.
|
|
|
- Producir: recipe-contract §1 gana la regla R-5 (y §2 una fila «Alcance de
|
|
|
tema»), §4 la tabla de enforcement, §5 el checklist (punto 12: «censo del
|
|
|
componente al 100 % o excepción»); theming §6 referencia cruzada; el
|
|
|
checklist de cierre (`docs/guides/completion-checklist.md`) y el
|
|
|
`COMPONENT_AUDIT_GUIDE` endurecen las dimensiones 5 y 10 («usa tokens» ≠
|
|
|
«es temable»: la ficha exige el % del censo). **D-TH.6**: codemod
|
|
|
value-preserving de los nombres fuera de vocabulario (lista de F0), con
|
|
|
`generated/base.css` regenerado y diff = renombres 1:1, computed idéntico en
|
|
|
navegador (mismo triple muro que px/py).
|
|
|
- Guard: `docs:check` 0 · el diff de `generated/base.css` son SOLO renombres ·
|
|
|
censo idéntico antes/después del codemod (un rename no cambia el alcance) ·
|
|
|
sonda de computed en 3 componentes renombrados = idéntico.
|
|
|
- **Repaso de lo ya ejecutado (2026-08-20)**: firmar una gramática obliga a
|
|
|
releer lo corregido ANTES de ella. Auditados los 7 de §8 contra `fg` +
|
|
|
familias (`scripts/__names-audit7.ts`): 6 limpios, y una sola corrección —
|
|
|
`gradient-builder.checker-color` → `checker-fg` (slot, no sustantivo; 4
|
|
|
consumos en `gradient-builder.css`). Las 4 claves `stop-color-*` del mismo
|
|
|
componente son falso amigo verificado (`stop-color` es la PARTE) y NO se
|
|
|
tocan. La corrección entra DENTRO del codemod. Detalle y tabla:
|
|
|
[`CONTINUE-theming.md`](./CONTINUE-theming.md) §«Primera posición».
|
|
|
|
|
|
### F2 — Backfill por familias (6–8 bloques de sesión; **un componente = un commit**)
|
|
|
|
|
|
Orden propuesto (D-TH.4). Dentro de cada bloque: sin contrato primero, luego
|
|
|
por knobs fuera del contrato. Cada componente sigue §7 entero.
|
|
|
|
|
|
| Bloque | Familia | Comp. | Knobs fuera | Entran primero (sin contrato) |
|
|
|
| ------ | ----------------------------------------------------- | ----: | ----------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| B1 | Menús · listas · navegación | 24 | 432 | `command`, `listbox`, `table`, `tree-grid`, `tree-view`, `grid-list`, `virtual-list`, `virtual-grid`, `menu-dial`, `feed` — y `navigation-menu` (44 %) hasta el 100 % |
|
|
|
| B2 | Campos | 24 | 526 | `combobox` (1), `textarea`, `css-field`, `mask-field`, `number-field`, `field-langs`, `gradient-builder`, `gradient-picker`, `label` |
|
|
|
| B3 | Controles · marcas | 33 | 502 | `knob`, `avatar`, `kbd`, `link`, `mark`, `highlight`, `clipboard`, `proof-of-human`, `aspect-ratio` |
|
|
|
| B4 | Superficies · overlays · estado | 34 | 429 | `alert-dialog`, `announce`, `carousel`, `link-preview`, `skeleton`, `spinner`, `scroll-frames`, `motion`, `mockup`, `cascade`, `card-group` |
|
|
|
| B5 | Texto · tipografía | 12 | 217 | `heading`, `text`, `s-text`, `display`, `code`, `code-block`, `text-*` (los que no tienen contrato) |
|
|
|
| B6 | Media · chat | 9 | 104 | `skin-media-player` |
|
|
|
| B7 | Tiempo (chronos · fecha/hora) — **si D-TH.3 lo mete** | 15 | 774 | `range-calendar`, `month-grid`, `year-grid`, `date-picker`, `date-range-picker`, `time-picker`, `time-range-picker`, `natural-time-picker`, `picker-shell` |
|
|
|
| B8 | `palabras` — **si D-TH.3 lo mete** | 1 | 363 | — |
|
|
|
|
|
|
Por componente se produce: entrada (o ampliación) en `recipes/base.ts` con los
|
|
|
nombres de §1/§6.7 — dimensionales por talla si el componente tiene `size`
|
|
|
(patrón `Sidebar`: `{part}-{eje}-{k}` + nombre resuelto con `declarations` por
|
|
|
`scope: 'size:{k}'`), colores por rol/slot, acentos de estado; la receta
|
|
|
consume SOLO nombres resueltos (nunca un primitivo crudo, nunca un literal);
|
|
|
privados sólo si derivan de públicos; `generated/base.css` regenerado por el
|
|
|
script (**jamás a mano**, theming §16 F); README de eidos con la tabla de
|
|
|
tokens («Talla y tema», molde: `navigation-menu`); registro en §8.
|
|
|
|
|
|
- Guard por componente: §7 entero, y el censo `--only {c}` al **100 %** (o
|
|
|
`R-5.x exception:` con razón) — si no llega, el commit NO se hace.
|
|
|
- Guard por bloque: **revisión adversarial** (§7.7) antes de dar el bloque por
|
|
|
cerrado: un pase escéptico por componente que intente REFUTAR «el default es
|
|
|
idéntico» y «cada token alcanza» con medición propia, no con la del autor
|
|
|
del commit.
|
|
|
|
|
|
### F3 — R-5 a `error` + cierre (una sesión)
|
|
|
|
|
|
- Producir: severidad `error` en R-5.1/5.2/5.3 (D-TH.7); el test del suelo
|
|
|
pasa a exigir 100 % global (o excepciones listadas); theming §12 y
|
|
|
recipe-contract §4 lo reflejan; `CONTINUE-theming.md` cerrado.
|
|
|
- Guard: `component:audit` PASS en los 162 · censo 100 % · `docs:check` 0.
|
|
|
|
|
|
### F4 — Exposición en la demo de temas (opcional, D-TH.8)
|
|
|
|
|
|
- Producir: en `/temas` (o en cada demo) un panel que lista los públicos del
|
|
|
componente desde `recipes/base.ts` y los mueve en vivo — la prueba viva del
|
|
|
eje A, y el detector de tokens que no alcanzan (mover y que nada cambie).
|
|
|
- Guard: mover cada token del componente en la demo y ver cambiar el computed
|
|
|
(automatizable con el centinela de §7.4).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 6. Deuda transversal que este plan destapa — NO se ejecuta aquí
|
|
|
|
|
|
| Id | Dónde | Qué |
|
|
|
| ---------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| **T-TH.1** | `component-audit` dims 5 y 10 | Dan ✓ a «usa tokens»; el criterio se endurece en F1. Las fichas ya escritas (`docs/audit/components/*.md`) quedan con el ✓ viejo: se corrigen al pasar cada componente por F2, no en masa. |
|
|
|
| **T-TH.2** | Vocabulario de slots (theming §6.7) | Existe y no se guarda: `tabs` (`trigger-color-*`), `navigation-menu` (`-bg-active`, `-color-active`) y más lo incumplen. D-TH.6. |
|
|
|
| **T-TH.3** | `menubar` | Misma clase que el nav: cromo de barra en privados («the bar itself styles via foundation privates», `recipes/base.ts`) + `commit-select` en el trigger al DESPLEGAR (otra sesión, sema). |
|
|
|
| **T-TH.4** | `archetype: 'item'` en envoltorios | Hay que censar qué otras partes `<li>`/wrapper lo declaran (memoria `archetype-item-pulls-interactive-styling`: Timeline, Breadcrumb, NavigationMenu ya corregidos). Un guard de morfo («un `item` no envuelve a un `trigger`») es candidato. |
|
|
|
| **T-TH.5** | `--control-height-*` en `:root` (T-6 del sidebar) | La densidad/zoom por SUBÁRBOL no re-deriva; afecta a la promesa de theming «por ámbito». Eje de theming aparte. |
|
|
|
| **T-TH.6** | 25 knobs visuales fuera del morfo (`component-visual-attrs`, eje Affix) | Filas sin firmar `image/skeleton/qr-code/s-text`. El eje C (variantes) depende de ellas. |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 7. PROTOCOLO DE VERIFICACIÓN — por componente, sin excepciones
|
|
|
|
|
|
Existe porque el que ejecuta falla, y porque en un solo día (2026-08-19,
|
|
|
`navigation-menu`) cuatro de estos pasos ausentes costaron cuatro commits de
|
|
|
corrección: se dio por arreglado un hover leyendo el nodo equivocado; se
|
|
|
resolvió un doble de animación en la dirección contraria a la doctrina; se
|
|
|
inventó un hover por componente; y se declaró «idéntico» sin captura. Cada paso
|
|
|
tiene un **artefacto** (número, captura, salida de comando) que va al mensaje
|
|
|
de commit. Sin artefacto, el paso no se ha hecho.
|
|
|
|
|
|
### 7.1 Antes de tocar el componente (las cinco preguntas + lectura)
|
|
|
|
|
|
1. Las cinco preguntas del autor, UN componente por mensaje cuando haya
|
|
|
decisión (nombres fuera de vocabulario, una excepción, un default que
|
|
|
parece defecto): qué soluciona · leído todo o presupuesto · qué afecta ·
|
|
|
qué doctrina · qué modificaciones. Si no hay decisión nueva (el componente
|
|
|
sólo necesita tokens con nombres canónicos), se ejecuta sin preguntar y se
|
|
|
reporta.
|
|
|
2. Leer ENTEROS: la receta del componente, su entrada en `recipes/base.ts`,
|
|
|
su README de eidos y de soma, su morfo (¿qué partes llevan arquetipo?), su
|
|
|
ficha en `docs/audit/components/`. Y la doctrina de §0 (fuentes) si la
|
|
|
sesión no la ha leído hoy.
|
|
|
3. `git status` + `git log -1`: ¿hay otra sesión con el árbol sucio?
|
|
|
**Nunca `git stash`** para medir una base (le arranca el trabajo a otro).
|
|
|
|
|
|
### 7.2 Medir ANTES (el suelo del «idéntico»)
|
|
|
|
|
|
4. `node --import tsx/esm scripts/theming-census.ts --only {c}` → guardar la
|
|
|
línea.
|
|
|
5. Sonda Playwright **headless desde la raíz del repo** (la pantalla oculta
|
|
|
congela rAF; `playwright` no resuelve desde el scratchpad) contra la demo
|
|
|
del componente: para cada parte visible y cada talla, computed de los
|
|
|
knobs (`backgroundColor`, `backgroundImage`, `color`, `borderRadius`,
|
|
|
`padding*`, `fontSize`, `lineHeight`, `blockSize`/`inlineSize`,
|
|
|
`boxShadow`, `borderColor`) en reposo · hover · activo/abierto ·
|
|
|
disabled · `:focus-visible`. Muestrear FUERA de callbacks de
|
|
|
`MutationObserver` (miden el instante anterior al flush). Guardar JSON.
|
|
|
6. Captura 2× de la demo en reposo y en hover (sirve de «antes» para la
|
|
|
comparación a ojo).
|
|
|
|
|
|
### 7.3 Editar (la forma firmada — nada más)
|
|
|
|
|
|
7. Tokens con los nombres de recipe-contract §1 / theming §6.7. Por talla si
|
|
|
hay `size`. Acentos de estado en `background-color`. Hover/press/selected
|
|
|
neutros = la capa del sistema (nunca `background:` a mano, nunca
|
|
|
`background-image: none` para «limpiar», nunca una escalera de color
|
|
|
propia). Privados sólo derivando de públicos. Literales: cero.
|
|
|
8. `npm run generate:eidos-css` y `git diff --stat src/uix/eidos/generated/`:
|
|
|
el diff son SOLO los tokens del componente. Si toca otra cosa, parar.
|
|
|
9. Si un envoltorio lleva `archetype: 'item'`/`'option'`/`'trigger'` sin ser
|
|
|
el interactivo, es una DECISIÓN (morfo): se presenta, no se toca de oficio.
|
|
|
|
|
|
### 7.4 Medir DESPUÉS (los tres artefactos)
|
|
|
|
|
|
10. **Idéntico**: repetir la sonda de 7.2 → diff de computed por parte/estado/talla
|
|
|
= **vacío**. Un solo valor distinto = parar y explicar (o es defecto
|
|
|
previo que se firma, o es error del commit).
|
|
|
11. **Alcanza**: la **prueba de centinela** — por cada token NUEVO del
|
|
|
componente, poner en el root del componente un valor imposible de
|
|
|
confundir (`9999px`, `rgb(1, 2, 3)`, `0.123`) y leer el computed del
|
|
|
nodo que lo consume: tiene que seguirlo. Si un token no mueve nada, es
|
|
|
un token que miente (fantasma o nombre equivocado). Se automatiza en la
|
|
|
misma sonda (`el.style.setProperty('--{c}-…', sentinel)` → `getComputedStyle`).
|
|
|
12. **Desde el píxel hacia arriba** en los estados de hover: `elementsFromPoint`
|
|
|
en el centro del control y la pila de ancestros con `backgroundImage` /
|
|
|
`backgroundColor` — el velo cae en el nodo CON forma y en ningún
|
|
|
envoltorio (memoria `measure-the-node-the-user-points-at`). Si hay
|
|
|
animación propia y un sello de sema en el mismo nodo, registro de
|
|
|
`animationstart/end` (no `getAnimations` en un solo instante): UNA
|
|
|
entrada por ocurrencia (memoria motion.md §"when both write `animation`").
|
|
|
13. Captura 2× después, al lado de la de antes. Mirarla.
|
|
|
|
|
|
### 7.5 Guards mecánicos (todos, cada componente)
|
|
|
|
|
|
14. `node --import tsx/esm scripts/theming-census.ts --only {c}` → **100 %** o
|
|
|
excepción escrita. Y el global NO baja.
|
|
|
15. `node --import tsx/esm scripts/component-audit.ts --only {c}` → PASS, sin
|
|
|
R-5 nuevos (en `warn` durante F2, pero se listan y se resuelven).
|
|
|
16. `node --import tsx/esm scripts/eidos-lint.ts {c}` → 0 invalid.
|
|
|
17. `npx vitest run src/uix/eidos` → sin rojos nuevos (comparar **por
|
|
|
fichero de test**, no por cifra: el rojo conocido es `skin-media-player`).
|
|
|
18. `npm run rtl:check` 0 · `npm run docs:check` 0 · `npx prettier --check`
|
|
|
en los ficheros tocados (ojo: `autocrlf=true` hace que prettier se queje
|
|
|
del CRLF del checkout — comprobar el contenido normalizado a LF, no el
|
|
|
fichero; git guarda LF).
|
|
|
19. `npm run check`: atribuir errores **por fichero** (`grep ERROR | grep {c}`),
|
|
|
nunca por cifra global; la rama tiene sesiones concurrentes y el total
|
|
|
se mueve solo. Si el log no llega a `COMPLETED`, es `tmp/lexical/`:
|
|
|
relanzar.
|
|
|
|
|
|
### 7.6 Commit (uno por componente)
|
|
|
|
|
|
20. `git add` con rutas EXPLÍCITAS (sólo lo del componente + `recipes/base.ts`
|
|
|
- `generated/base.css` + su README + este plan §8); `git diff --cached --stat`
|
|
|
y `git show :ruta` para verificar el ÁRBOL INDEXADO, no el de trabajo;
|
|
|
`git status` para ver que no entra nada de otra sesión. Mensaje con
|
|
|
`git commit -F fichero` (backticks en `-m` se ejecutan en bash), en
|
|
|
castellano, con: qué knobs entran, la cifra del censo antes → después,
|
|
|
el diff de computed (vacío), el centinela (n tokens probados), los
|
|
|
guards. **Nunca `--amend`** en la rama compartida.
|
|
|
21. Registro en §8 de este plan (componente · commit · censo antes→después ·
|
|
|
excepciones) y, si el bloque cierra, en `CONTINUE-theming.md`.
|
|
|
|
|
|
### 7.7 Revisión adversarial por bloque
|
|
|
|
|
|
22. Al cerrar un bloque, una pasada escéptica (otra sesión o un pase separado)
|
|
|
que por componente intente REFUTAR con medición propia: «el default es
|
|
|
idéntico» (sonda 7.2 vs 7.4 rehecha, no leída del commit), «cada token
|
|
|
alcanza» (centinela rehecho), «el velo cae donde debe» (píxel arriba),
|
|
|
«no hay doble animación». Hallazgos reales se arreglan en el bloque; los
|
|
|
refutados se anotan. El molde es la revisión del `Sidebar` (21
|
|
|
hallazgos · 17 refutados · 4 reales, `bae03e55c`).
|
|
|
|
|
|
### 7.8 Lo que NO se hace en este eje (y se anota como deuda si aparece)
|
|
|
|
|
|
- Rediseñar un default (radio, color, altura…): deuda firmable, no cambio.
|
|
|
- Tocar sema/morfo salvo un arquetipo en un envoltorio (decisión aparte).
|
|
|
- Cascadear a otro componente «ya que estamos» (memoria `no-cascade-changes`).
|
|
|
- Inventar nombres de token fuera de §1/§6.7, o un hover/estado por componente.
|
|
|
- Editar `generated/base.css` a mano.
|
|
|
- Dar un paso por hecho sin su artefacto.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 8. Registro
|
|
|
|
|
|
- 2026-08-19 — Censo medido (§1) con `scripts/theming-census.ts` (añadido en
|
|
|
este commit como instrumento, sin guard). Plan entregado. **Nada firmado,
|
|
|
nada construido.** Precedente ejecutado hoy que fija la forma:
|
|
|
`navigation-menu` (`ae9e277fa`: tokens del trigger por talla, default
|
|
|
idéntico; `a82794845`: el hover es el del sistema; `822b78cf2`: el `<li>`
|
|
|
sin arquetipo) — y aun así el componente queda en 44 %, prueba de que hace
|
|
|
falta el guard.
|
|
|
|
|
|
- 2026-08-20 — **Informe + primeros siete componentes** (`2591ec2f0` el informe
|
|
|
y el instrumento; `3bfe0d413` la revisión de las fichas 11-20). El censo pasa
|
|
|
a `--report`: `docs/audit/theming/` con un README de conjunto y **170 fichas**
|
|
|
(162 recetas + 8 sin receta), cada una con análisis, propuesta derivada de la
|
|
|
doctrina y un bloque de **veredicto** que se conserva al regenerar.
|
|
|
|
|
|
| Componente | Censo antes → después | Commit | Excepciones / lo que queda fuera |
|
|
|
| --------------------------- | --------------------: | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
|
| `gradient-builder` (piloto) | 0 % → 80 % | `3cdb5b5f0` | foco (sistema) + 3 literales de layout; damero tapado por el `background` inline del wrapper (anotado) |
|
|
|
| `combobox` | 0 % → 76 % | `cef2d32f1` | 3 hovers bespoke (esperan firma) + 6 literales; `content-font-family/-line-height` inertes bajo `[data-depth='overlay']` |
|
|
|
| `natural-time-picker` | 0 % → 61 % | `e774ca7e8` | cielos = excepción de tono fijo ya firmada; panel presta `--popover-*` por composición |
|
|
|
| `date-range-picker` | 0 % → 42 % | `07778b597` | mitad calendario (§B) + mitad campo (§5.3-3) |
|
|
|
| `time-range-picker` | 0 % → 19 % | `68eb8af26` | préstamos de Field/Slider/Toggle |
|
|
|
| `time-picker` | 0 % → 18 % | `e4fcdd62e` | préstamos de Field |
|
|
|
| `proof-of-human` | 0 % → 14 % | `ae91573c3` | escena = `FIXED_TONE_COMPONENTS`; hooks de clase (eje aparte) |
|
|
|
|
|
|
**Global: 33 % → 37 %** (1.621 → 1.841 públicos; 62 → 56 sin contrato).
|
|
|
Protocolo §7 aplicado entero en los siete: diff de computed **vacío** en todos
|
|
|
(6.612 · 1.566 · 6.438 · 493 · 725 · 580 · 406 valores, 7-8 estados cada uno),
|
|
|
centinela por token, `component:audit` PASS, `eidos-lint` 0 invalid,
|
|
|
`rtl:check` 0, `docs:check` 0, suite eidos con el único rojo conocido
|
|
|
(`skin-media-player`).
|
|
|
|
|
|
Cuatro defectos del método que la verificación destapó y que el handoff
|
|
|
recoge: **clave duplicada** en `recipes/base.ts` descarta el bloque en
|
|
|
silencio · dejar vivos los bloques `[data-size]` del CSS hace que el diff dé
|
|
|
0 por la ruta vieja · la sonda debe congelar `transition` pero **no**
|
|
|
`animation` (Presence no monta) · un token RESUELTO no se mueve desde `:root`
|
|
|
por diseño.
|
|
|
|
|
|
Prefijos abreviados o ajenos corregidos de paso (el censo los contaba como
|
|
|
`global` y se cruzarían al anidar): `--gb-*`, `--_ntp-*`, `--_time-field-*` en
|
|
|
los dos time-pickers, `--_date-field-*` y `--_calendar-font-size` en el
|
|
|
date-range-picker.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 9. Tabla completa por componente (2026-08-19 — regenerar con el script, no editar)
|
|
|
|
|
|
| Componente | Familia | Alcance | Knobs | Público | Privado | Global | Literal | Sistema | Contrato | size |
|
|
|
| --------------------- | ------------------------------- | ------: | ----: | ------: | ------: | -----: | ------: | ------: | -------: | :--: |
|
|
|
| `range-calendar` | Tiempo (chronos · fecha/hora) | 0% | 98 | 0 | 7 | 84 | 4 | 3 | 0 | y |
|
|
|
| `combobox` | Campos | 0% | 96 | 0 | 15 | 67 | 6 | 8 | 1 | y |
|
|
|
| `proof-of-human` | Controles · marcas | 0% | 95 | 0 | 18 | 36 | 37 | 4 | 0 | y |
|
|
|
| `time-range-picker` | Tiempo (chronos · fecha/hora) | 0% | 88 | 0 | 6 | 61 | 17 | 4 | 0 | y |
|
|
|
| `natural-time-picker` | Tiempo (chronos · fecha/hora) | 0% | 78 | 0 | 0 | 69 | 7 | 2 | 0 | y |
|
|
|
| `gradient-builder` | Campos | 0% | 62 | 0 | 8 | 46 | 3 | 5 | 0 | y |
|
|
|
| `month-grid` | Tiempo (chronos · fecha/hora) | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
|
|
|
| `year-grid` | Tiempo (chronos · fecha/hora) | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
|
|
|
| `time-picker` | Tiempo (chronos · fecha/hora) | 0% | 59 | 0 | 3 | 42 | 12 | 2 | 0 | y |
|
|
|
| `date-range-picker` | Tiempo (chronos · fecha/hora) | 0% | 55 | 0 | 0 | 49 | 3 | 3 | 0 | y |
|
|
|
| `command` | Menús · listas · navegación | 0% | 52 | 0 | 9 | 35 | 6 | 2 | 0 | y |
|
|
|
| `table` | Menús · listas · navegación | 0% | 46 | 0 | 23 | 14 | 5 | 4 | 0 | y |
|
|
|
| `media-player` | Media · chat | 0% | 45 | 0 | 0 | 37 | 8 | 0 | 2 | y |
|
|
|
| `tree-grid` | Menús · listas · navegación | 0% | 42 | 0 | 29 | 8 | 2 | 3 | 0 | y |
|
|
|
| `field-langs` | Campos | 0% | 41 | 0 | 0 | 31 | 8 | 2 | 0 | – |
|
|
|
| `gradient-picker` | Campos | 0% | 38 | 0 | 7 | 23 | 5 | 3 | 0 | y |
|
|
|
| `listbox` | Campos | 0% | 38 | 0 | 9 | 23 | 3 | 3 | 0 | – |
|
|
|
| `carousel` | Superficies · overlays · estado | 0% | 36 | 0 | 14 | 12 | 5 | 5 | 0 | y |
|
|
|
| `heading` | Texto · tipografía | 0% | 36 | 0 | 36 | 0 | 0 | 0 | 0 | – |
|
|
|
| `feed` | Menús · listas · navegación | 0% | 33 | 0 | 13 | 16 | 3 | 1 | 0 | y |
|
|
|
| `grid-list` | Menús · listas · navegación | 0% | 32 | 0 | 8 | 17 | 2 | 5 | 0 | y |
|
|
|
| `textarea` | Campos | 0% | 28 | 0 | 16 | 5 | 4 | 3 | 0 | y |
|
|
|
| `tree-view` | Menús · listas · navegación | 0% | 28 | 0 | 8 | 14 | 4 | 2 | 0 | y |
|
|
|
| `code-block` | Texto · tipografía | 0% | 26 | 0 | 2 | 24 | 0 | 0 | 0 | – |
|
|
|
| `card-group` | Superficies · overlays · estado | 0% | 24 | 0 | 0 | 18 | 4 | 2 | 0 | y |
|
|
|
| `text` | Texto · tipografía | 0% | 24 | 0 | 24 | 0 | 0 | 0 | 0 | – |
|
|
|
| `spinner` | Superficies · overlays · estado | 0% | 23 | 0 | 15 | 4 | 4 | 0 | 0 | y |
|
|
|
| `picker-shell` | Tiempo (chronos · fecha/hora) | 0% | 21 | 0 | 4 | 17 | 0 | 0 | 0 | y |
|
|
|
| `link-preview` | Superficies · overlays · estado | 0% | 17 | 0 | 4 | 9 | 1 | 3 | 0 | y |
|
|
|
| `drag-drop` | Controles · marcas | 0% | 16 | 0 | 3 | 6 | 0 | 7 | 1 | – |
|
|
|
| `kbd` | Controles · marcas | 0% | 14 | 0 | 1 | 9 | 4 | 0 | 0 | – |
|
|
|
| `link` | Controles · marcas | 0% | 14 | 0 | 4 | 2 | 5 | 3 | 0 | – |
|
|
|
| `code` | Texto · tipografía | 0% | 13 | 0 | 6 | 3 | 4 | 0 | 0 | – |
|
|
|
| `virtual-list` | Menús · listas · navegación | 0% | 13 | 0 | 2 | 6 | 4 | 1 | 0 | y |
|
|
|
| `virtual-grid` | Menús · listas · navegación | 0% | 12 | 0 | 2 | 6 | 3 | 1 | 0 | y |
|
|
|
| `skeleton` | Superficies · overlays · estado | 0% | 11 | 0 | 9 | 1 | 1 | 0 | 0 | y |
|
|
|
| `skin-media-player` | Media · chat | 0% | 11 | 0 | 0 | 2 | 7 | 2 | 0 | y |
|
|
|
| `scroll-frames` | Superficies · overlays · estado | 0% | 9 | 0 | 1 | 4 | 4 | 0 | 0 | – |
|
|
|
| `announce` | Superficies · overlays · estado | 0% | 8 | 0 | 0 | 8 | 0 | 0 | 0 | – |
|
|
|
| `clipboard` | Controles · marcas | 0% | 8 | 0 | 2 | 5 | 1 | 0 | 0 | – |
|
|
|
| `label` | Campos | 0% | 8 | 0 | 6 | 2 | 0 | 0 | 0 | – |
|
|
|
| `menu-dial` | Menús · listas · navegación | 0% | 8 | 0 | 3 | 1 | 4 | 0 | 0 | y |
|
|
|
| `display` | Texto · tipografía | 0% | 6 | 0 | 6 | 0 | 0 | 0 | 0 | – |
|
|
|
| `mark` | Controles · marcas | 0% | 5 | 0 | 2 | 1 | 2 | 0 | 0 | – |
|
|
|
| `aspect-ratio` | Controles · marcas | 0% | 3 | 0 | 0 | 1 | 2 | 0 | 0 | – |
|
|
|
| `date-picker` | Tiempo (chronos · fecha/hora) | 0% | 2 | 0 | 0 | 0 | 2 | 0 | 0 | – |
|
|
|
| `sticky` | Superficies · overlays · estado | 0% | 2 | 0 | 1 | 0 | 1 | 0 | 1 | – |
|
|
|
| `text-blur` | Texto · tipografía | 0% | 2 | 0 | 0 | 0 | 2 | 0 | 0 | – |
|
|
|
| `cascade` | Menús · listas · navegación | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 0 | – |
|
|
|
| `motion` | Superficies · overlays · estado | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 0 | – |
|
|
|
| `section` | Layout (primitivos) | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 4 | – |
|
|
|
| `chronos` | Tiempo (chronos · fecha/hora) | 1% | 245 | 2 | 22 | 202 | 12 | 7 | 9 | y |
|
|
|
| `prose` | Texto · tipografía | 1% | 74 | 1 | 0 | 43 | 30 | 0 | 2 | y |
|
|
|
| `nav-tree` | Menús · listas · navegación | 4% | 25 | 1 | 0 | 17 | 6 | 1 | 1 | – |
|
|
|
| `s-text` | Texto · tipografía | 7% | 30 | 2 | 28 | 0 | 0 | 0 | 3 | – |
|
|
|
| `chart` | Controles · marcas | 9% | 92 | 8 | 0 | 66 | 14 | 4 | 17 | – |
|
|
|
| `result` | Superficies · overlays · estado | 9% | 22 | 2 | 1 | 15 | 4 | 0 | 8 | – |
|
|
|
| `mockup` | Superficies · overlays · estado | 14% | 29 | 4 | 7 | 13 | 5 | 0 | 0 | – |
|
|
|
| `menubar` | Menús · listas · navegación | 15% | 27 | 4 | 6 | 16 | 0 | 1 | 5 | y |
|
|
|
| `anchor-nav` | Menús · listas · navegación | 20% | 11 | 2 | 0 | 8 | 0 | 1 | 2 | – |
|
|
|
| `banner` | Superficies · overlays · estado | 20% | 10 | 2 | 6 | 1 | 1 | 0 | 42 | y |
|
|
|
| `button` | Controles · marcas | 21% | 30 | 6 | 16 | 0 | 7 | 1 | 105 | y |
|
|
|
| `palabras` | WIP (tracks paralelos) | 22% | 471 | 103 | 1 | 272 | 90 | 5 | 0 | – |
|
|
|
| `toggle` | Controles · marcas | 22% | 28 | 6 | 17 | 1 | 3 | 1 | 119 | y |
|
|
|
| `date-range-field` | Tiempo (chronos · fecha/hora) | 25% | 9 | 2 | 0 | 4 | 2 | 1 | 3 | – |
|
|
|
| `time-range-field` | Tiempo (chronos · fecha/hora) | 25% | 9 | 2 | 0 | 4 | 2 | 1 | 3 | – |
|
|
|
| `surface` | Superficies · overlays · estado | 25% | 4 | 1 | 3 | 0 | 0 | 0 | 25 | – |
|
|
|
| `callout` | Superficies · overlays · estado | 27% | 15 | 4 | 3 | 7 | 1 | 0 | 28 | – |
|
|
|
| `meter` | Superficies · overlays · estado | 29% | 14 | 4 | 6 | 2 | 2 | 0 | 28 | y |
|
|
|
| `knob` | Controles · marcas | 29% | 27 | 7 | 4 | 9 | 4 | 3 | 0 | y |
|
|
|
| `onion-menu` | Menús · listas · navegación | 29% | 27 | 7 | 0 | 8 | 9 | 3 | 12 | – |
|
|
|
| `empty-state` | Superficies · overlays · estado | 29% | 17 | 5 | 7 | 5 | 0 | 0 | 6 | y |
|
|
|
| `search-field` | Campos | 31% | 14 | 4 | 5 | 0 | 4 | 1 | 17 | y |
|
|
|
| `password-field` | Campos | 31% | 36 | 11 | 5 | 9 | 10 | 1 | 23 | y |
|
|
|
| `aura` | Superficies · overlays · estado | 31% | 35 | 11 | 4 | 14 | 6 | 0 | 24 | y |
|
|
|
| `toggle-group` | Controles · marcas | 33% | 3 | 1 | 0 | 1 | 1 | 0 | 1 | – |
|
|
|
| `background` | Superficies · overlays · estado | 35% | 26 | 8 | 6 | 6 | 3 | 3 | 31 | – |
|
|
|
| `avatar` | Controles · marcas | 36% | 36 | 13 | 17 | 0 | 6 | 0 | 0 | y |
|
|
|
| `audio-player` | Media · chat | 37% | 19 | 7 | 0 | 8 | 4 | 0 | 5 | – |
|
|
|
| `tooltip` | Superficies · overlays · estado | 38% | 22 | 8 | 9 | 3 | 1 | 1 | 20 | y |
|
|
|
| `button-group` | Controles · marcas | 40% | 5 | 2 | 0 | 0 | 3 | 0 | 1 | – |
|
|
|
| `badge` | Controles · marcas | 41% | 22 | 9 | 10 | 1 | 2 | 0 | 65 | y |
|
|
|
| `popover` | Superficies · overlays · estado | 42% | 51 | 20 | 6 | 22 | 0 | 3 | 36 | y |
|
|
|
| `qr-code` | Controles · marcas | 43% | 7 | 3 | 0 | 0 | 4 | 0 | 10 | – |
|
|
|
| `navigation-menu` | Menús · listas · navegación | 44% | 38 | 15 | 1 | 13 | 5 | 4 | 26 | y |
|
|
|
| `waveform` | Media · chat | 45% | 11 | 5 | 1 | 1 | 4 | 0 | 10 | y |
|
|
|
| `color-picker` | Campos | 46% | 82 | 36 | 10 | 22 | 11 | 3 | 54 | y |
|
|
|
| `checkbox` | Controles · marcas | 48% | 34 | 16 | 12 | 2 | 3 | 1 | 45 | y |
|
|
|
| `progress` | Superficies · overlays · estado | 49% | 35 | 17 | 9 | 3 | 6 | 0 | 41 | y |
|
|
|
| `tag-group` | Controles · marcas | 49% | 46 | 21 | 21 | 0 | 1 | 3 | 91 | y |
|
|
|
| `color-swatch` | Controles · marcas | 50% | 10 | 5 | 2 | 3 | 0 | 0 | 12 | y |
|
|
|
| `text-scramble` | Texto · tipografía | 50% | 4 | 2 | 0 | 0 | 2 | 0 | 0 | – |
|
|
|
| `split-button` | Controles · marcas | 50% | 2 | 1 | 0 | 1 | 0 | 0 | 1 | y |
|
|
|
| `timeline` | Superficies · overlays · estado | 51% | 49 | 25 | 21 | 0 | 3 | 0 | 45 | y |
|
|
|
| `field` | Campos | 51% | 73 | 35 | 15 | 7 | 11 | 5 | 60 | y |
|
|
|
| `context-menu` | Menús · listas · navegación | 53% | 33 | 16 | 0 | 11 | 3 | 3 | 18 | – |
|
|
|
| `rating-group` | Controles · marcas | 53% | 16 | 8 | 4 | 1 | 2 | 1 | 25 | y |
|
|
|
| `metrics` | Controles · marcas | 54% | 50 | 27 | 10 | 9 | 4 | 0 | 68 | y |
|
|
|
| `sidebar` | Menús · listas · navegación | 55% | 45 | 23 | 0 | 14 | 5 | 3 | 50 | – |
|
|
|
| `drawer` | Superficies · overlays · estado | 55% | 62 | 33 | 9 | 13 | 5 | 2 | 44 | y |
|
|
|
| `color-field` | Campos | 56% | 16 | 9 | 0 | 2 | 5 | 0 | 22 | y |
|
|
|
| `image` | Controles · marcas | 57% | 35 | 20 | 2 | 1 | 12 | 0 | 22 | y |
|
|
|
| `dropdown-menu` | Menús · listas · navegación | 57% | 30 | 16 | 0 | 9 | 3 | 2 | 19 | – |
|
|
|
| `switch` | Controles · marcas | 57% | 22 | 12 | 8 | 1 | 0 | 1 | 52 | y |
|
|
|
| `s-text-virtual-list` | Menús · listas · navegación | 58% | 12 | 7 | 0 | 3 | 2 | 0 | 9 | – |
|
|
|
| `form` | Campos | 59% | 52 | 30 | 14 | 5 | 2 | 1 | 54 | y |
|
|
|
| `float-panel` | Superficies · overlays · estado | 59% | 53 | 29 | 3 | 12 | 5 | 4 | 28 | – |
|
|
|
| `slider` | Controles · marcas | 59% | 33 | 19 | 12 | 0 | 1 | 1 | 39 | y |
|
|
|
| `radio-cards` | Controles · marcas | 60% | 72 | 42 | 0 | 24 | 4 | 2 | 39 | y |
|
|
|
| `card` | Superficies · overlays · estado | 60% | 36 | 21 | 14 | 0 | 0 | 1 | 97 | y |
|
|
|
| `cropper` | Controles · marcas | 60% | 27 | 15 | 0 | 3 | 7 | 2 | 15 | – |
|
|
|
| `emoji-picker` | Campos | 61% | 32 | 17 | 0 | 8 | 3 | 4 | 17 | – |
|
|
|
| `pin-input` | Campos | 61% | 19 | 11 | 0 | 6 | 1 | 1 | 20 | y |
|
|
|
| `editable` | Campos | 63% | 44 | 25 | 12 | 1 | 2 | 4 | 56 | y |
|
|
|
| `text-focus` | Texto · tipografía | 63% | 8 | 5 | 0 | 1 | 2 | 0 | 0 | – |
|
|
|
| `spin-field` | Campos | 64% | 27 | 16 | 0 | 8 | 1 | 2 | 20 | – |
|
|
|
| `file-upload` | Campos | 64% | 61 | 38 | 16 | 1 | 4 | 2 | 98 | y |
|
|
|
| `tags-input` | Campos | 67% | 46 | 28 | 13 | 1 | 0 | 4 | 90 | y |
|
|
|
| `toolbar` | Menús · listas · navegación | 67% | 35 | 22 | 10 | 0 | 1 | 2 | 54 | y |
|
|
|
| `image-adjustments` | Controles · marcas | 67% | 18 | 10 | 0 | 4 | 1 | 3 | 12 | – |
|
|
|
| `text-gradient` | Texto · tipografía | 67% | 9 | 6 | 0 | 0 | 3 | 0 | 0 | – |
|
|
|
| `separator` | SIN FAMILIA | 67% | 6 | 4 | 0 | 0 | 2 | 0 | 3 | – |
|
|
|
| `select` | Campos | 69% | 72 | 45 | 14 | 3 | 3 | 7 | 101 | y |
|
|
|
| `dialog` | Superficies · overlays · estado | 70% | 33 | 23 | 5 | 4 | 1 | 0 | 37 | y |
|
|
|
| `image-picker` | Campos | 71% | 20 | 12 | 0 | 1 | 4 | 3 | 13 | – |
|
|
|
| `pagination` | Menús · listas · navegación | 71% | 26 | 17 | 7 | 0 | 0 | 2 | 34 | y |
|
|
|
| `stepper` | Menús · listas · navegación | 71% | 60 | 40 | 15 | 0 | 1 | 4 | 69 | y |
|
|
|
| `skip-link` | Superficies · overlays · estado | 71% | 8 | 5 | 0 | 0 | 2 | 1 | 8 | – |
|
|
|
| `date-field` | Tiempo (chronos · fecha/hora) | 73% | 11 | 8 | 3 | 0 | 0 | 0 | 21 | y |
|
|
|
| `time-field` | Tiempo (chronos · fecha/hora) | 73% | 11 | 8 | 3 | 0 | 0 | 0 | 21 | y |
|
|
|
| `calendar` | Tiempo (chronos · fecha/hora) | 75% | 71 | 51 | 13 | 0 | 4 | 3 | 76 | y |
|
|
|
| `accordion` | Superficies · overlays · estado | 77% | 65 | 49 | 10 | 0 | 5 | 1 | 76 | y |
|
|
|
| `radio-group` | Controles · marcas | 77% | 75 | 56 | 10 | 7 | 0 | 2 | 61 | y |
|
|
|
| `chat-log` | Media · chat | 77% | 42 | 30 | 0 | 4 | 5 | 3 | 31 | – |
|
|
|
| `chat-composer` | Media · chat | 79% | 44 | 31 | 0 | 3 | 5 | 5 | 31 | – |
|
|
|
| `chat-message` | Media · chat | 82% | 84 | 63 | 2 | 6 | 6 | 7 | 75 | y |
|
|
|
| `fab` | Controles · marcas | 82% | 17 | 14 | 0 | 2 | 1 | 0 | 10 | – |
|
|
|
| `toast` | Superficies · overlays · estado | 83% | 42 | 35 | 6 | 0 | 1 | 0 | 85 | – |
|
|
|
| `text-circular` | Texto · tipografía | 83% | 6 | 5 | 0 | 1 | 0 | 0 | 0 | – |
|
|
|
| `tabs` | Menús · listas · navegación | 88% | 76 | 66 | 6 | 2 | 1 | 1 | 79 | y |
|
|
|
| `chat-typing` | Media · chat | 89% | 9 | 8 | 0 | 1 | 0 | 0 | 7 | – |
|
|
|
| `breadcrumb` | Menús · listas · navegación | 90% | 23 | 18 | 2 | 0 | 0 | 3 | 28 | y |
|
|
|
| `collapsible` | Superficies · overlays · estado | 90% | 12 | 9 | 0 | 1 | 0 | 2 | 11 | – |
|
|
|
| `scroll-area` | Superficies · overlays · estado | 94% | 17 | 15 | 0 | 0 | 1 | 1 | 13 | – |
|
|
|
| `splitter` | Superficies · overlays · estado | 100% | 19 | 18 | 0 | 0 | 0 | 1 | 16 | – |
|
|
|
| `chat-list` | Media · chat | 100% | 18 | 18 | 0 | 0 | 0 | 0 | 18 | – |
|
|
|
| `box` | Layout (primitivos) | 100% | 9 | 9 | 0 | 0 | 0 | 0 | 43 | – |
|
|
|
| `barcode` | Controles · marcas | 100% | 5 | 5 | 0 | 0 | 0 | 0 | 7 | – |
|
|
|
| `flex` | Layout (primitivos) | 100% | 2 | 2 | 0 | 0 | 0 | 0 | 7 | – |
|
|
|
| `grid` | Layout (primitivos) | 100% | 2 | 2 | 0 | 0 | 0 | 0 | 13 | – |
|
|
|
| `alert-dialog` | Superficies · overlays · estado | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `auto-grid` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `container` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
|
|
|
| `css-field` | Campos | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `float` | Superficies · overlays · estado | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
|
|
|
| `group` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
|
|
|
| `highlight` | Controles · marcas | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `icon` | Controles · marcas | — | 0 | 0 | 0 | 0 | 0 | 0 | 2 | – |
|
|
|
| `mask-field` | Campos | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `number-field` | Campos | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `stack` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `wrap` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|