6.5 KiB
color-swatch — 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: 100% — 7 de 7 knobs por token público
- Knobs de apariencia: 7 — público 7 · privado 0 · global 0 · literal 0 · sistema 0 · excepción 0 · estructural 0 · puente 0 · canal 0 (los cinco últimos, fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 14 pública(s) —size-xs,size-sm,size-md,size-lg,size-xl,radius-sm,radius-md,radius-lg,radius-full,border-width,border-fg,checker-cell,checker-bg,checker-square - Eje
size: sí · ficheros:color-swatch.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 (0)
Ninguno.
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 (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-swatch-size |
5 | var(--color-swatch-size-md), var(--color-swatch-size-xs), var(--color-swatch-size-sm), var(--color-swatch-size-lg), var(--color-swatch-size-xl) |
public | sí |
--_color-swatch-radius |
4 | var(--color-swatch-radius-sm), var(--color-swatch-radius-md), var(--color-swatch-radius-lg), var(--color-swatch-radius-full) |
public | sí |
4. Propuesta de corrección
- 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).
Nada que proponer: no hay knobs fuera de alcance.
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 — 70 % → 100 % (contrato 12 → 14 claves; knobs 10 → 7,
porque los tres border-radius por variante pasan a declarar el privado).
Diff de computed 0 sobre 832 valores en 15 estados (dos rutas), capturas 2×
byte a byte idénticas, centinela 12/14 con las dos adjudicadas, exit 0.
Lo que la §4 pedía y lo que se hizo. La §4 marcaba radius (ya existe) con
⚠ y tres valores en colisión: es la propuesta correcta a medias. No es una
colisión de nombre, es una escala — el eje rounded con cuatro pasos, y el
que ya estaba en el contrato ERA el paso sm bajo un nombre que no lo dice.
Contado en base.ts: siete recetas escriben radius-{k}, y una de ellas es
badge, el gemelo que lee este mismo data-rounded con el mismo conmutador
privado. Así que la escala entera (radius-sm/md/lg/full) más
--_color-swatch-radius, exactamente la forma que su propio eje size ya usaba
dos líneas más arriba. Mantener radius al lado de radius-md habría dejado el
paso sm llamándose radius: un nombre que miente.
fill RETIRADO del contrato — es un canal de valor, no un knob.
(Anotación 2026-08-26: renombrado a --_color-swatch-fill por el codemod de
los 14 canales — la ley del espacio cerrado. La medida de abajo fue correcta
con el nombre de su día y no se reescribe.) El wrapper
escribe --color-swatch-fill: {color} INLINE en cada render desde una prop
obligatoria. Medido sobre un chip real (transiciones congeladas): escribir el
token en :root deja el ::before en rgb(124, 58, 237) — la declaración
inline gana siempre. Un público encima sólo podía mentir, y la forma correcta ya
estaba escrita en el propio guard de la capa: recipe-css-contract sanciona
var(--x, default) para las vars que el runtime escribe («el respaldo ES el
default»), que es justo lo que la receta tenía. Por eso el respaldo NO se retira
aquí: al salir del contrato deja de ser código muerto y pasa a ser el default.
⚠ El centinela daba fill por VIVO, y es un falso positivo suyo. El guard
escribe el token en :root y en el style inline de cada nodo del
componente, que es exactamente donde vive el canal de valor: lo pisa y lee
«mueve». Es la cara opuesta de drag-drop.preview-z (donde la adjudicación se
había medido sobre un nodo fabricado). Un token escrito inline por el
componente no se puede juzgar con el guard: se mide a mano escribiendo sólo en
:root.
Las dos adjudicaciones son el anillo opt-in (border-width, border-fg):
bordered nace apagado y ningún consumidor del repo lo enciende, así que su
::after no existe en ninguna página. Forzado data-bordered sobre un chip real
de la ruta de gradient-builder, los dos llegan (inset 0 0 0 1px → 1234px,
oklch(0.931 0 0) → rgb(1, 2, 3)).
El instrumento estaba ciego, dos veces. (1) color-swatch no tiene ruta de
demo (404): es el QUINTO canónico en ese estado, tras picker-shell, mockup,
surface y audio-player. Se mide donde de verdad se renderiza —
gradient-builder (3 chips en el stage) y color-picker (el del trigger). (2)
El eje rounded no lo monta nadie: ningún consumidor pasa la prop, así que
los tres pasos que no son el default no tenían nodo que pintar; el guard los
barre con sweepAttr: data-rounded.
Lo que queda fuera y no es deuda: nada. Los 7 knobs pasan por token público.