9.1 KiB
color-field — 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-24 · Alcance: 93% — 14 de 15 knobs por token público
- Knobs de apariencia: 15 — público 14 · privado 0 · global 1 · literal 0 · sistema 0 · excepción 1 (los dos últimos, fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 26 pública(s) —segment-padding-inline-xs,segment-padding-inline-sm,segment-padding-inline-md,segment-padding-inline-lg,segment-padding-inline-xl,placeholder-fg,literal-fg,segment-radius,segment-fg,segment-invalid-fg,segment-readonly-bg,segment-readonly-fg,segment-readonly-decoration,swatch-size-xs,swatch-size-sm,swatch-size-md,swatch-size-lg,swatch-size-xl,format-select-fg,transition-duration,transition-ease,disabled-opacity,separator-bg,separator-thickness,segment-min-width,hex-segment-min-width - Eje
size: sí · ficheros:color-field.css
1. Knobs fuera de alcance
1.1 Directo a primitivo global (1)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | color-field.css:122 |
[data-color-field-swatch][data-color-swatch] |
border-radius |
var(--field-control-radius) ⤴ prestado de field |
1.2 A través de un privado (0)
Ninguno.
1.3 Literales (0)
Ninguno.
1.4 Excepciones firmadas (1) — 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.
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | color-field.css:158 |
[data-color-field-format-select][data-select] |
inline-size |
fit-content |
2. Sistema transversal (0) — informativo, fuera del ratio
Un tema los alcanza a nivel de sistema, por diseño (recipe-contract §2).
Ninguno.
3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
|---|---|---|---|---|
--_color-field-segment-padding-inline |
5 | var(--color-field-segment-padding-inline-md), var(--color-field-segment-padding-inline-xs), var(--color-field-segment-padding-inline-sm), var(--color-field-segment-padding-inline-lg), var(--color-field-segment-padding-inline-xl) |
public | sí |
--_color-field-swatch-size |
5 | var(--color-field-swatch-size-md), var(--color-field-swatch-size-xs), var(--color-field-swatch-size-sm), var(--color-field-swatch-size-lg), var(--color-field-swatch-size-xl) |
public | sí |
4. Propuesta de corrección
- Consume la capa compartida
list-surface. Un eje que la capa posee se consume comovar(--_x, var(--x)); el consumidor no acuña--color-field-{eje}para él — sería un vocabulario paralelo (README deeidos/components, «Capas compartidas» regla 2). - Consume la capa compartida
field-segment-state. Un eje que la capa posee se consume comovar(--_x, var(--x)); el consumidor no acuña--color-field-{eje}para él — sería un vocabulario paralelo (README deeidos/components, «Capas compartidas» regla 2). - Consume tokens públicos de
field. Un token prestado importa la semántica de su dueño: la corrección no es duplicarlo con prefijo propio, sino la decisión de familia que la auditoría de fase 1 dejó registrada (theming-audit.md§B, familia calendar). - Tiene eje
size: los tokens dimensionales van por talla ({part}-{eje}-{k}) apuntando al bundle--size-{k}-*, nunca al primitivo crudo (theming §5; el guardrecipe-css-contractprohíbe el primitivo).
4.1 Tokens a declarar en lib/recipes/base.ts (2)
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 (--color-field-…) |
scope TSC | valor propuesto | usos |
|---|---|---|---|
swatch-radius |
root |
var(--field-control-radius) |
1 |
format-select-width |
root |
fit-content |
1 |
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-23 — 56 % → 93 %. Cuatro claves nuevas (22 → 26), un literal firmado, un préstamo adjudicado y TRECE tokens preexistentes medidos uno a uno: el componente nunca había pasado por R-5.4. Diff de computed 0 sobre 2.336 valores en 8 estados.
Las cuatro claves. El componente es un Field y no realiasa nada suyo, así que lo que faltaba era pequeño y muy concreto:
separator-bg+separator-thickness— los separadores de canal («,», « / ») se pintan como líneas verticales de un pelo, y ni su tinta (--color-border-default) ni su grosor (1px) eran alcanzables. El1pxES--border-width: es un filete, ydropdown-menu.separator-thicknesslee la misma familia. El mismo nodo renderizado como GLIFO («#», «%») ya tenía suliteral-fg— una parte, dos tratamientos, y ahora los dos con mando.segment-min-width(3ch) +hex-segment-min-width(6ch) — el ancho fijo por número de caracteres, que impide el reflujo al teclear (99 → 100). Los gemelosdate-fieldytime-fieldcargan el mismo hecho DENTRO de uncalc(2ch + 2 * var(--…-segment-padding-inline)), así que el suyo ya viajaba con un token y el censo lo daba por alcanzable; aquí iba a pelo. Precedentes de unidadchen el catálogo:editable.area-min-inline-size(12ch) ytags-input.input-min-inline-size(8ch).
El 7 % que queda es una fila, y es doctrina. El chip de color lee
var(--field-control-radius) porque IGUALA el radio del control — el comentario
del CSS lo dice: «so the chip tracks the control». Qué DECIDE ese token: el
radio del control de campo. Un swatch-radius propio daría un segundo mando
para una decisión ajena y permitiría desincronizar el chip del campo que lo
contiene. Préstamo con dueño, se tema en la ficha de field — la misma lectura
que el --slider-disabled-opacity de waveform, el mismo día.
Y el fit-content del conmutador es identidad: el trigger se mide POR su
contenido, no contra una longitud. Firmado con su anotación, fuera del ratio.
Las trece adjudicaciones, todas PROBADAS forzando sobre nodos reales. La
demo arranca con valor, en md, editable y con tres formatos: cada estado y
cada paso de talla que no monta no tiene nodo que pintar. Seis de estado
(placeholder, invalid, los tres de readonly, disabled), cuatro de la
escala del chip (14 → 77, 16 → 77, 20 → 77, 32 → 77 px), la etiqueta del formato
BLOQUEADO —que sólo existe con un único formato permitido, así que se midió
desmarcando rgb y hsl con los chips de la propia demo, no fabricando el
nodo— y las dos de transición.
Las dos de transición costaron dos diagnósticos falsos, y el segundo es nuevo.
El primero es la ley ya escrita: el guard congela transition para hacer
medible todo lo demás, así que los tokens que SON la transición no se pueden
mover bajo él. El segundo fue mío: midiéndolas a mano leí 0s y sospeché del
@media (prefers-reduced-motion: reduce) del final del fichero — lo comprobé
corriendo con reducedMotion: 'no-preference' y seguía dando 0s, porque el
nodo que había cogido (querySelector('[data-color-field-segment]')) es el
PRIMER segmento, que es un literal y declara transition: none de su propia
cosecha. Sobre un segmento editable: 0.12s → 11.5s y
cubic-bezier(0.4,0,0.2,1) → steps(7). Mide el nodo que pinta, no el primero
que casa el selector.
Verificación: sonda antes/después 0 diffs (2.336 valores · 8 estados · 10
nodos) · R-5.4 13/26 con las trece restantes adjudicadas y medidas, cero STALE ·
component:audit PASS · censo 93 % · eidos-lint 14 morfo-backed / 14
eidos-only / 0 invalid, 0 class-hooks.