10 KiB
chart — alcance de tema: análisis y propuesta
Generado por
node --import tsx/esm scripts/theming-census.ts --report. Lo medido y la propuesta se regeneran; el Veredicto (§5) se conserva. Vista de conjunto: README · método y protocolo:PLAN-theming.md§1, §2, §7.
- Medido: 2026-08-25 · Alcance: 89% — 81 de 91 knobs por token público
- Knobs de apariencia: 95 — público 81 · privado 0 · global 0 · literal 10 · sistema 4 · excepción 0 · estructural 0 · puente 0 · canal 0 (los cinco últimos, fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 45 pública(s) —line-width,axis-width,grid-width,bar-radius,point-radius,area-opacity,slice-stroke-width,transition-duration,transition-ease,tooltip-bg,tooltip-border,tooltip-radius,tooltip-shadow,tooltip-padding,tooltip-gap,crosshair-fg,crosshair-width,caption-font-size,caption-fg,label-font-size,label-fg,label-font-weight,gauge-label-font-size,axis-fg,grid-fg,separator-fg,smith-boundary-fg,track-bg,track-height,track-radius,gap,legend-row-gap,legend-column-gap,legend-item-gap,swatch-size,swatch-radius,tooltip-swatch-size,bar-list-row-gap,bar-list-column-gap,bar-segment-gap,bar-segment-track-gap,bar-segment-track-radius,bar-segment-fill-min-inline-size,bar-segment-legend-row-gap,bar-segment-legend-column-gap - Eje
size: no · ficheros:chart.css
1. Knobs fuera de alcance
1.1 Directo a primitivo global (0)
Ninguno.
1.2 A través de un privado (0)
Ninguno.
1.3 Literales (10)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | chart.css:27 |
[data-chart-frame] |
inline-size |
100% |
| 2 | chart.css:31 |
[data-chart-plot] |
inline-size |
100% |
| 3 | chart.css:37 |
[data-chart] |
inline-size |
100% |
| 4 | chart.css:47 |
[data-chart-empty] |
block-size |
100% |
| 5 | chart.css:137 |
[data-chart-tooltip] |
min-inline-size |
max-content |
| 6 | chart.css:173 |
[data-chart-figure] |
inline-size |
100% |
| 7 | chart.css:217 |
[data-chart-bar-list] |
inline-size |
100% |
| 8 | chart.css:239 |
[data-chart-bar-list-bar] |
block-size |
100% |
| 9 | chart.css:256 |
[data-chart-bar-segment] |
inline-size |
100% |
| 10 | chart.css:266 |
[data-chart-bar-segment-fill] |
block-size |
100% |
1.4 Excepciones firmadas (0) — fuera del ratio
Literales que llevan su anotación /* literal: <razón> */ en la propia
declaración: la válvula de recipe-contract §3, la misma que honra
component-audit. Una desviación firmada no es deuda — se listan para que la
razón se lea, no para acuñarlas.
Ninguno.
2. Sistema transversal (4) — informativo, fuera del ratio
Un tema los alcanza a nivel de sistema, por diseño (recipe-contract §2).
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | chart.css:273 |
[data-chart-bar-segment-fill][data-dim='true'] |
opacity |
var(--opacity-scrim) |
| 2 | chart.css:315 |
[data-chart-heat-cell][data-dim='true'] |
opacity |
var(--opacity-scrim) |
| 3 | chart.css:323 |
[data-chart-cal-cell][data-dim='true'] |
opacity |
var(--opacity-scrim) |
| 4 | chart.css:363 |
[data-chart-polar-petal][data-dim='true'] |
opacity |
var(--opacity-scrim) |
3. Privados de la receta — ¿de dónde sale su valor?
La receta no declara privados propios en su CSS.
4. Propuesta de corrección
4.1 Tokens a declarar en lib/recipes/base.ts (1)
Valor verbatim del CSS de hoy: el default no se mueve, sólo cambia quién
puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla
al final) y theming §6.7 (slots de color, modificador delante). Un token con
DOS valores distintos es una colisión de nombre: son dos knobs, o el nombre
no distingue lo que debería — se marca ⚠.
token (--chart-…) |
scope TSC | valor propuesto | usos |
|---|---|---|---|
tooltip-width |
root |
max-content |
1 |
4.2 Sin nombre mecánico (9)
- ⚠ decisión:
100%es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar — 9:inline-size,block-size.
4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)
- Privado que no deriva de un público — §3 lo marca; el privado debe leer el público o desaparecer.
- Velo o acento en el nodo equivocado (
archetype: 'item'en un envoltorio, unbackgrounden shorthand que mata la capa de estado) — se mide desde el píxel hacia arriba. - Doble animación al mover un sello a una superficie con animación propia — registro de
animationstart/animationend. - Diff de computed = 0 en reposo · hover · abierto · disabled · foco, por talla, antes y después.
- Centinela por token nuevo: valor imposible en el root → el nodo lo sigue. Si no, el token miente.
5. Veredicto
EJECUTADO 2026-08-22 — 9 % → 49 % → 89 %, en dos pasadas: 22 claves de tinta-no-texto y geometría, y luego 6 de COSTURA para el texto. El 89 % es el techo: lo que queda fuera son los diez literales de identidad.
La propuesta §4 pedía 71 claves y habría escrito ~20 con el MISMO valor. La
medición que lo decidió: las 84 filas fuera de alcance colapsaban a 26 valores
distintos — 9× content-subtle, 9× content-primary, 9× 100%, 6×
font-size-sm, 6× font-size-xs, 6× font-weight-medium, 5×
surface-default, 4× radius-sm, 3× border-default. Nombrar por parte
habría dado cinco claves para el pelo que separa marcas y nueve para la tinta
de anotación. Es la inflación que F2-B ya cazó en spinner, con otra forma.
El texto adopta DOS ROLES del canon, con costura (firmado 2026-08-22). La
primera pasada dejó el CSS leyendo var(--style-caption-font-size) y
var(--color-content-*) a pelo: el VALOR era correcto pero faltaba la costura
que PLAN §2-A exige —todo knob lee --{c}-{slot}—, y sin ella un tema no puede
aclarar las anotaciones de un gráfico denso sin mover caption en toda la app,
ni getRecipeTokens() ve esa superficie. Seis claves:
--chart-caption-font-size var(--style-caption-font-size) eje · leyenda · tooltip · smith
--chart-caption-fg var(--style-caption-color)
--chart-label-font-size var(--style-label-font-size) título · bar-list · funnel · empty
--chart-label-fg var(--style-label-color)
--chart-label-font-weight var(--style-label-font-weight) los seis nodos en medium
--chart-gauge-label-font-size var(--size-xl-font-size) el readout, sin rol en el canon
Es el molde que la propia vertebración tipográfica documenta
(--accordion-trigger-font-family: var(--style-label-font-family)), y NO el
alias que §39 mató: aquello espejaba 36 claves de una capa; esto acuña una
costura por eje, tres ejes sobre 19 nodos de texto. Tamaño y tinta son
ortogonales a propósito: empty y bar-list-value son tamaño label con
tinta caption, y el CSS lo dice.
D-TH.2 no aplica aquí y su propio texto lo aclara: los seis primitivos tipográficos quedan fuera porque la capa ES su API, y «un componente que sólo LEE un named style para un eje no es un primitivo y no está en el conjunto».
Con la costura, global cae a CERO y el alcance a 89 %. La nota que dejé
en §13 diciendo que el censo penalizaba hacer lo correcto era mía y estaba
equivocada: el censo medía bien, faltaba la costura.
Lo que la receta sí posee: la tinta de lo que no es texto — cinco claves,
cada una un concepto que el CSS repite: axis-fg (eje + rejilla smith +
conector del funnel), grid-fg (rejilla + radar), separator-fg (el pelo de
superficie entre marcas contiguas: porción, punto activo, punto smith, pétalo,
segmento), smith-boundary-fg (el borde del disco, más fuerte a propósito) y
track-bg (raíl del bar-list y del gauge). Más 17 de geometría de cromo.
Un incumplimiento heredado, corregido: el CSS leía
var(--control-height-sm, var(--space-7)) — coordenada CRUDA, que
recipe-css-contract prohíbe en un token de receta, con un respaldo muerto (el
primitivo existe). El contrato guarda var(--size-sm-control-height), el
bundle, que es 1:1 con él.
Fuera de contrato por identidad (los 10 literales): nueve 100% que
significan «ocupa a tu padre» y el min-inline-size: max-content del tooltip,
que es la corrección de composición de la misma clase ya adjudicada en
date-picker. Moverlos no es tematizar, es romper el layout.
La escotilla del gauge, cerrada: su número es un READOUT de dato y ningún
estilo con nombre juega ese papel (un h2 es un encabezado), así que su
costura toma el bundle de talla en vez de un rol.
El instrumento estaba ciego de tres maneras, y las tres se arreglaron ANTES de medir (ninguna era culpa de los tokens):
- La superficie de chart vive en DIECISÉIS rutas de demo, una por tipo de
gráfico:
/chartmonta una línea con área y nada más (58 nodos de 302 en la página). El guard ganóurls— un token está VIVO si alguna superficie del componente lo sigue— y la sonda se corrió por las dieciséis. - El guard no leía NINGUNA propiedad SVG. Sin
fill/stroke/strokeWidth/fillOpacity/r/rx, doce de las 39 claves de un componente que dibuja en SVG leían muertas estando vivas. Misma clase que el hueco defilter/backdrop-filterdel día anterior. - El valor centinela se elegía por SUBCADENA:
slice-stroke-widthrecibíargb(1, 2, 3)por contener «stroke», valor inválido para una longitud, y leía muerta. Ahora la dimensión se decide por el final del nombre.
Con eso: sonda 0 diffs en 161.850 valores computados (16 rutas × 7 estados)
y centinela 37/39, con transition-duration y -ease adjudicadas y
medidas sin la congelación (0.12s → 11.5s · cubic-bezier → steps(4)).