20 KiB
Auditoría de alcance de tema — el catálogo entero
Generado, no escrito a mano:
node --import tsx/esm scripts/theming-census.ts --report. Este README es la vista de conjunto; una ficha por componente al lado, con su análisis y su propuesta de corrección. Método, clases, protocolo de verificación y fases:PLAN-theming.md. La auditoría del SISTEMA de theming (fase 1, cerrada 2026-07-07) estheming-audit.md; ésta es la deuda de adopción que aquélla dejó apuntada en su §5.3-3.
- Medido: 2026-08-20 · 162 recetas con CSS + 8 componentes sin receta = 170 fichas, el árbol entero de
eidos/components/ - La pregunta: ¿cuánto de la apariencia de cada componente puede cambiar un tema sin tocar el sistema ni la receta?
- Alcance global: 35% — 1734 de 4971 knobs pasan por un token público del componente
- Reparto: público 1734 · privado 852 · global 1771 · literal 614 · sistema transversal 233 (fuera del ratio)
- Sin token público propio: 61 · alcance < 20 %: 57 · alcance 100 %: 6 · con eje
size: 80
Cómo se lee
| clase | qué es | ¿lo alcanza un tema del componente? |
|---|---|---|
public |
var(--{c}-…), el contrato del componente |
sí |
private |
var(--_{c}-…), nombre interno |
sólo si el privado deriva de un público (cada ficha lo dice en §3) |
global |
primitivo del sistema (--space-*, --radius-*, --color-*, bundle --size-{k}-*…) |
sólo moviendo el sistema entero |
literal |
ni token: 8px, 1.25, #fff |
no — y viola R-2/R-4 |
system |
sistemas transversales que la receta CONSUME por contrato (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).
Límites de la medida (regex sobre el CSS; sobre-reporta, nunca infra-reporta):
una declaración con varios tokens se clasifica por la primera clase que casa
(público → privado → sistema → global); el token público de OTRO componente
cuenta como global y la ficha lo marca «⤴ prestado»; los valores dentro de
@keyframes cuentan como cualquier otro. Tres defectos que ningún regex ve —
privado que no deriva, velo en el nodo equivocado, doble animación — van en la
checklist §4.4 de cada ficha.
Qué NO propone una ficha
La propuesta deriva nombres de la doctrina; no la contradice. Por eso una ficha nunca propone acuñar un token para:
- lo que posee una capa compartida (
list-surface,spin-field,picker-shell,viewport-placement,field-segment-state,menu-indicator,sliding-indicator): un eje = un token público de la capa- una ranura privada, consumido
var(--_x, var(--x))— el consumidor no acuña--{c}-{eje}(README deeidos/components, «Capas compartidas» regla 2);
- una ranura privada, consumido
- el foco (
--focus-ring-*, theming §32) ni la capa de estado (--state-*, §38): un knob del sistema, no del componente; - un token prestado de otro componente (la familia
calendaren los pickers): la corrección es la decisión de familia registrada entheming-audit.md§B, no un duplicado con prefijo propio; - un shorthand o un eje físico (
padding,border,height): primero se parte en ejes lógicos (recipe-contract §1, R-4.4), y eso es decisión.
Sin receta CSS (8)
Ni un .css en su directorio: no hay knob que medir, y eso es una
respuesta, no un hueco. Cada ficha dice —medido, no supuesto— dónde vive su
visual: el componente que compone, la capa compartida que consume, o la receta
ajena que pinta sus attrs (y cuyos knobs ya están contados allí).
affix · count-up · format-date · format-number · icon-button · relative-time · svg · trans
Y el vocabulario de nombres tiene una desviación medida: el catálogo habla
mayoritariamente con el modificador al final (-bg-hover, -bg-active) mientras
theming §6.7 lo pone delante (hover-bg). Las fichas proponen la forma
documentada y lo dejan anotado: la normalización es D-TH.6, sin firmar.
Los 20 con más knobs fuera del contrato
| # | componente | fuera de alcance | alcance | knobs | contrato |
|---|---|---|---|---|---|
| 1 | palabras | 363 | 22% | 471 | 0 |
| 2 | chronos | 236 | 1% | 245 | 9 |
| 3 | range-calendar | 95 | 0% | 98 | 0 |
| 4 | proof-of-human | 91 | 0% | 95 | 0 |
| 5 | time-range-picker | 84 | 0% | 88 | 0 |
| 6 | chart | 80 | 9% | 92 | 17 |
| 7 | natural-time-picker | 76 | 0% | 78 | 0 |
| 8 | prose | 73 | 1% | 74 | 2 |
| 9 | month-grid | 58 | 0% | 61 | 0 |
| 10 | year-grid | 58 | 0% | 61 | 0 |
| 11 | time-picker | 57 | 0% | 59 | 0 |
| 12 | date-range-picker | 52 | 0% | 55 | 0 |
| 13 | command | 50 | 0% | 52 | 0 |
| 14 | media-player | 45 | 0% | 45 | 2 |
| 15 | color-picker | 43 | 46% | 82 | 54 |
| 16 | table | 42 | 0% | 46 | 0 |
| 17 | field-langs | 39 | 0% | 41 | 0 |
| 18 | tree-grid | 39 | 0% | 42 | 0 |
| 19 | heading | 36 | 0% | 36 | 0 |
| 20 | gradient-picker | 35 | 0% | 38 | 0 |
Sin ningún token público propio (61)
Ni una clave pública en lib/recipes/base.ts — alguno tiene privados forward
(_palette-*), que no son contrato: un tema no puede nombrarlos.
alert-dialog · announce · aspect-ratio · auto-grid · avatar · card-group · carousel · cascade · clipboard · code · code-block · command · css-field · date-picker · date-range-picker · display · feed · field-langs · gradient-picker · grid-list · heading · highlight · kbd · knob · label · link · link-preview · listbox · mark · mask-field · menu-dial · mockup · month-grid · motion · natural-time-picker · number-field · palabras · picker-shell · proof-of-human · range-calendar · scroll-frames · skeleton · skin-media-player · spinner · stack · table · text · text-blur · text-circular · text-focus · text-gradient · text-scramble · textarea · time-picker · time-range-picker · tree-grid · tree-view · virtual-grid · virtual-list · wrap · year-grid
Tabla completa (162 recetas, por alcance ascendente)
La columna «contrato» cuenta las claves públicas del bloque del componente.
| componente | alcance | knobs | público | privado | global | literal | sistema | contrato | size |
|---|---|---|---|---|---|---|---|---|---|
| range-calendar | 0% | 98 | 0 | 7 | 84 | 4 | 3 | 0 | y |
| proof-of-human | 0% | 95 | 0 | 18 | 36 | 37 | 4 | 0 | y |
| time-range-picker | 0% | 88 | 0 | 6 | 61 | 17 | 4 | 0 | y |
| natural-time-picker | 0% | 78 | 0 | 0 | 69 | 7 | 2 | 0 | y |
| month-grid | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
| year-grid | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
| time-picker | 0% | 59 | 0 | 3 | 42 | 12 | 2 | 0 | y |
| date-range-picker | 0% | 55 | 0 | 0 | 49 | 3 | 3 | 0 | y |
| command | 0% | 52 | 0 | 9 | 35 | 6 | 2 | 0 | y |
| table | 0% | 46 | 0 | 23 | 14 | 5 | 4 | 0 | y |
| media-player | 0% | 45 | 0 | 0 | 37 | 8 | 0 | 2 | y |
| tree-grid | 0% | 42 | 0 | 29 | 8 | 2 | 3 | 0 | y |
| field-langs | 0% | 41 | 0 | 0 | 31 | 8 | 2 | 0 | – |
| gradient-picker | 0% | 38 | 0 | 7 | 23 | 5 | 3 | 0 | y |
| listbox | 0% | 38 | 0 | 9 | 23 | 3 | 3 | 0 | – |
| carousel | 0% | 36 | 0 | 14 | 12 | 5 | 5 | 0 | y |
| heading | 0% | 36 | 0 | 36 | 0 | 0 | 0 | 0 | – |
| feed | 0% | 33 | 0 | 13 | 16 | 3 | 1 | 0 | y |
| grid-list | 0% | 32 | 0 | 8 | 17 | 2 | 5 | 0 | y |
| textarea | 0% | 28 | 0 | 16 | 5 | 4 | 3 | 0 | y |
| tree-view | 0% | 28 | 0 | 8 | 14 | 4 | 2 | 0 | y |
| code-block | 0% | 26 | 0 | 2 | 24 | 0 | 0 | 0 | – |
| card-group | 0% | 24 | 0 | 0 | 18 | 4 | 2 | 0 | y |
| text | 0% | 24 | 0 | 24 | 0 | 0 | 0 | 0 | – |
| spinner | 0% | 23 | 0 | 15 | 4 | 4 | 0 | 0 | y |
| picker-shell | 0% | 21 | 0 | 4 | 17 | 0 | 0 | 0 | y |
| link-preview | 0% | 17 | 0 | 4 | 9 | 1 | 3 | 0 | y |
| drag-drop | 0% | 16 | 0 | 3 | 6 | 0 | 7 | 1 | – |
| kbd | 0% | 14 | 0 | 1 | 9 | 4 | 0 | 0 | – |
| link | 0% | 14 | 0 | 4 | 2 | 5 | 3 | 0 | – |
| code | 0% | 13 | 0 | 6 | 3 | 4 | 0 | 0 | – |
| virtual-list | 0% | 13 | 0 | 2 | 6 | 4 | 1 | 0 | y |
| virtual-grid | 0% | 12 | 0 | 2 | 6 | 3 | 1 | 0 | y |
| skeleton | 0% | 11 | 0 | 9 | 1 | 1 | 0 | 0 | y |
| skin-media-player | 0% | 11 | 0 | 0 | 2 | 7 | 2 | 0 | y |
| scroll-frames | 0% | 9 | 0 | 1 | 4 | 4 | 0 | 0 | – |
| announce | 0% | 8 | 0 | 0 | 8 | 0 | 0 | 0 | – |
| clipboard | 0% | 8 | 0 | 2 | 5 | 1 | 0 | 0 | – |
| label | 0% | 8 | 0 | 6 | 2 | 0 | 0 | 0 | – |
| menu-dial | 0% | 8 | 0 | 3 | 1 | 4 | 0 | 0 | y |
| display | 0% | 6 | 0 | 6 | 0 | 0 | 0 | 0 | – |
| mark | 0% | 5 | 0 | 2 | 1 | 2 | 0 | 0 | – |
| aspect-ratio | 0% | 3 | 0 | 0 | 1 | 2 | 0 | 0 | – |
| date-picker | 0% | 2 | 0 | 0 | 0 | 2 | 0 | 0 | – |
| sticky | 0% | 2 | 0 | 1 | 0 | 1 | 0 | 1 | – |
| text-blur | 0% | 2 | 0 | 0 | 0 | 2 | 0 | 0 | – |
| cascade | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 0 | – |
| motion | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 0 | – |
| section | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 4 | – |
| chronos | 1% | 245 | 2 | 22 | 202 | 12 | 7 | 9 | y |
| prose | 1% | 74 | 1 | 0 | 43 | 30 | 0 | 2 | y |
| nav-tree | 4% | 25 | 1 | 0 | 17 | 6 | 1 | 1 | – |
| s-text | 7% | 30 | 2 | 28 | 0 | 0 | 0 | 3 | – |
| chart | 9% | 92 | 8 | 0 | 66 | 14 | 4 | 17 | – |
| result | 9% | 22 | 2 | 1 | 15 | 4 | 0 | 8 | – |
| mockup | 14% | 29 | 4 | 7 | 13 | 5 | 0 | 0 | – |
| menubar | 15% | 27 | 4 | 6 | 16 | 0 | 1 | 5 | y |
| anchor-nav | 20% | 11 | 2 | 0 | 8 | 0 | 1 | 2 | – |
| banner | 20% | 10 | 2 | 6 | 1 | 1 | 0 | 42 | y |
| button | 21% | 30 | 6 | 16 | 0 | 7 | 1 | 105 | y |
| palabras | 22% | 471 | 103 | 1 | 272 | 90 | 5 | 0 | – |
| toggle | 22% | 28 | 6 | 17 | 1 | 3 | 1 | 119 | y |
| date-range-field | 25% | 9 | 2 | 0 | 4 | 2 | 1 | 3 | – |
| time-range-field | 25% | 9 | 2 | 0 | 4 | 2 | 1 | 3 | – |
| surface | 25% | 4 | 1 | 3 | 0 | 0 | 0 | 25 | – |
| callout | 27% | 15 | 4 | 3 | 7 | 1 | 0 | 28 | – |
| meter | 29% | 14 | 4 | 6 | 2 | 2 | 0 | 28 | y |
| knob | 29% | 27 | 7 | 4 | 9 | 4 | 3 | 0 | y |
| onion-menu | 29% | 27 | 7 | 0 | 8 | 9 | 3 | 12 | – |
| empty-state | 29% | 17 | 5 | 7 | 5 | 0 | 0 | 6 | y |
| search-field | 31% | 14 | 4 | 5 | 0 | 4 | 1 | 17 | y |
| password-field | 31% | 36 | 11 | 5 | 9 | 10 | 1 | 23 | y |
| aura | 31% | 35 | 11 | 4 | 14 | 6 | 0 | 24 | y |
| toggle-group | 33% | 3 | 1 | 0 | 1 | 1 | 0 | 1 | – |
| background | 35% | 26 | 8 | 6 | 6 | 3 | 3 | 31 | – |
| avatar | 36% | 36 | 13 | 17 | 0 | 6 | 0 | 0 | y |
| audio-player | 37% | 19 | 7 | 0 | 8 | 4 | 0 | 5 | – |
| tooltip | 38% | 22 | 8 | 9 | 3 | 1 | 1 | 20 | y |
| button-group | 40% | 5 | 2 | 0 | 0 | 3 | 0 | 1 | – |
| badge | 41% | 22 | 9 | 10 | 1 | 2 | 0 | 65 | y |
| popover | 42% | 51 | 20 | 6 | 22 | 0 | 3 | 36 | y |
| qr-code | 43% | 7 | 3 | 0 | 0 | 4 | 0 | 10 | – |
| navigation-menu | 44% | 38 | 15 | 1 | 13 | 5 | 4 | 26 | y |
| waveform | 45% | 11 | 5 | 1 | 1 | 4 | 0 | 10 | y |
| color-picker | 46% | 82 | 36 | 10 | 22 | 11 | 3 | 54 | y |
| checkbox | 48% | 34 | 16 | 12 | 2 | 3 | 1 | 45 | y |
| progress | 49% | 35 | 17 | 9 | 3 | 6 | 0 | 41 | y |
| tag-group | 49% | 46 | 21 | 21 | 0 | 1 | 3 | 91 | y |
| color-swatch | 50% | 10 | 5 | 2 | 3 | 0 | 0 | 12 | y |
| text-scramble | 50% | 4 | 2 | 0 | 0 | 2 | 0 | 0 | – |
| split-button | 50% | 2 | 1 | 0 | 1 | 0 | 0 | 1 | y |
| timeline | 51% | 49 | 25 | 21 | 0 | 3 | 0 | 45 | y |
| field | 51% | 73 | 35 | 15 | 7 | 11 | 5 | 60 | y |
| context-menu | 53% | 33 | 16 | 0 | 11 | 3 | 3 | 18 | – |
| rating-group | 53% | 16 | 8 | 4 | 1 | 2 | 1 | 25 | y |
| metrics | 54% | 50 | 27 | 10 | 9 | 4 | 0 | 68 | y |
| sidebar | 55% | 45 | 23 | 0 | 14 | 5 | 3 | 50 | – |
| drawer | 55% | 62 | 33 | 9 | 13 | 5 | 2 | 44 | y |
| color-field | 56% | 16 | 9 | 0 | 2 | 5 | 0 | 22 | y |
| image | 57% | 35 | 20 | 2 | 1 | 12 | 0 | 22 | y |
| dropdown-menu | 57% | 30 | 16 | 0 | 9 | 3 | 2 | 19 | – |
| switch | 57% | 22 | 12 | 8 | 1 | 0 | 1 | 52 | y |
| s-text-virtual-list | 58% | 12 | 7 | 0 | 3 | 2 | 0 | 9 | – |
| form | 59% | 52 | 30 | 14 | 5 | 2 | 1 | 54 | y |
| float-panel | 59% | 53 | 29 | 3 | 12 | 5 | 4 | 28 | – |
| slider | 59% | 33 | 19 | 12 | 0 | 1 | 1 | 39 | y |
| radio-cards | 60% | 72 | 42 | 0 | 24 | 4 | 2 | 39 | y |
| card | 60% | 36 | 21 | 14 | 0 | 0 | 1 | 97 | y |
| cropper | 60% | 27 | 15 | 0 | 3 | 7 | 2 | 15 | – |
| emoji-picker | 61% | 32 | 17 | 0 | 8 | 3 | 4 | 17 | – |
| pin-input | 61% | 19 | 11 | 0 | 6 | 1 | 1 | 20 | y |
| editable | 63% | 44 | 25 | 12 | 1 | 2 | 4 | 56 | y |
| text-focus | 63% | 8 | 5 | 0 | 1 | 2 | 0 | 0 | – |
| spin-field | 64% | 27 | 16 | 0 | 8 | 1 | 2 | 20 | – |
| file-upload | 64% | 61 | 38 | 16 | 1 | 4 | 2 | 98 | y |
| tags-input | 67% | 46 | 28 | 13 | 1 | 0 | 4 | 90 | y |
| toolbar | 67% | 35 | 22 | 10 | 0 | 1 | 2 | 54 | y |
| image-adjustments | 67% | 18 | 10 | 0 | 4 | 1 | 3 | 12 | – |
| text-gradient | 67% | 9 | 6 | 0 | 0 | 3 | 0 | 0 | – |
| separator | 67% | 6 | 4 | 0 | 0 | 2 | 0 | 3 | – |
| select | 69% | 72 | 45 | 14 | 3 | 3 | 7 | 101 | y |
| dialog | 70% | 33 | 23 | 5 | 4 | 1 | 0 | 37 | y |
| image-picker | 71% | 20 | 12 | 0 | 1 | 4 | 3 | 13 | – |
| pagination | 71% | 26 | 17 | 7 | 0 | 0 | 2 | 34 | y |
| stepper | 71% | 60 | 40 | 15 | 0 | 1 | 4 | 69 | y |
| skip-link | 71% | 8 | 5 | 0 | 0 | 2 | 1 | 8 | – |
| date-field | 73% | 11 | 8 | 3 | 0 | 0 | 0 | 21 | y |
| time-field | 73% | 11 | 8 | 3 | 0 | 0 | 0 | 21 | y |
| calendar | 75% | 71 | 51 | 13 | 0 | 4 | 3 | 76 | y |
| combobox | 76% | 97 | 68 | 12 | 3 | 6 | 8 | 106 | – |
| accordion | 77% | 65 | 49 | 10 | 0 | 5 | 1 | 76 | y |
| radio-group | 77% | 75 | 56 | 10 | 7 | 0 | 2 | 61 | y |
| chat-log | 77% | 42 | 30 | 0 | 4 | 5 | 3 | 31 | – |
| chat-composer | 79% | 44 | 31 | 0 | 3 | 5 | 5 | 31 | – |
| gradient-builder | 80% | 60 | 45 | 7 | 1 | 3 | 4 | 72 | – |
| chat-message | 82% | 84 | 63 | 2 | 6 | 6 | 7 | 75 | y |
| fab | 82% | 17 | 14 | 0 | 2 | 1 | 0 | 10 | – |
| toast | 83% | 42 | 35 | 6 | 0 | 1 | 0 | 85 | – |
| text-circular | 83% | 6 | 5 | 0 | 1 | 0 | 0 | 0 | – |
| tabs | 88% | 76 | 66 | 6 | 2 | 1 | 1 | 79 | y |
| chat-typing | 89% | 9 | 8 | 0 | 1 | 0 | 0 | 7 | – |
| breadcrumb | 90% | 23 | 18 | 2 | 0 | 0 | 3 | 28 | y |
| collapsible | 90% | 12 | 9 | 0 | 1 | 0 | 2 | 11 | – |
| scroll-area | 94% | 17 | 15 | 0 | 0 | 1 | 1 | 13 | – |
| splitter | 100% | 19 | 18 | 0 | 0 | 0 | 1 | 16 | – |
| chat-list | 100% | 18 | 18 | 0 | 0 | 0 | 0 | 18 | – |
| box | 100% | 9 | 9 | 0 | 0 | 0 | 0 | 43 | – |
| barcode | 100% | 5 | 5 | 0 | 0 | 0 | 0 | 7 | – |
| flex | 100% | 2 | 2 | 0 | 0 | 0 | 0 | 7 | – |
| grid | 100% | 2 | 2 | 0 | 0 | 0 | 0 | 13 | – |
| alert-dialog | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| auto-grid | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| container | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
| css-field | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| float | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
| group | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
| highlight | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| icon | — | 0 | 0 | 0 | 0 | 0 | 0 | 2 | – |
| mask-field | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| number-field | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| stack | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
| wrap | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
Veredicto y decisiones
(pendiente — lo escribe el autor; se conserva al regenerar)