6.0 KiB
s-text-virtual-list — 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: 70% — 7 de 10 knobs por token público
- Knobs de apariencia: 10 — público 7 · privado 0 · global 3 · literal 0 · sistema 0 · excepción 2 · estructural 0 · puente 0 · canal 0 (los cinco últimos, fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 9 pública(s) —line-height,fg,bg,border-width,border-fg,radius,row-padding-inline,row-border-width,row-border-fg - Eje
size: no · ficheros:s-text-virtual-list.css
1. Knobs fuera de alcance
1.1 Directo a primitivo global (3)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | s-text-virtual-list.css:23 |
[data-s-text-virtual-list] |
font-family |
var(--_s-tvl-font-family, var(--font-family-primary)) |
| 2 | s-text-virtual-list.css:24 |
[data-s-text-virtual-list] |
font-size |
var(--_s-tvl-font-size, var(--font-size-md)) |
| 3 | s-text-virtual-list.css:25 |
[data-s-text-virtual-list] |
font-weight |
var(--_s-tvl-font-weight, var(--font-weight-regular)) |
1.2 A través de un privado (0)
Ninguno.
1.3 Literales (0)
Ninguno.
1.4 Excepciones firmadas (2) — 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 | s-text-virtual-list.css:22 |
[data-s-text-virtual-list] |
inline-size |
100% |
| 2 | s-text-virtual-list.css:41 |
[data-s-text-virtual-list-spacer] |
inline-size |
100% |
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?
La receta no declara privados propios en su CSS.
4. Propuesta de corrección
4.1 Tokens a declarar en lib/recipes/base.ts (3)
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 (--s-text-virtual-list-…) |
scope TSC | valor propuesto | usos |
|---|---|---|---|
font-family |
root |
var(--_s-tvl-font-family, var(--font-family-primary)) |
1 |
font-size |
root |
var(--_s-tvl-font-size, var(--font-size-md)) |
1 |
font-weight |
root |
var(--_s-tvl-font-weight, var(--font-weight-regular)) |
1 |
4.2 Sin nombre mecánico (2)
- ⚠ 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 — 2:inline-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-23 — 58 % → 70 %. CERO claves nuevas: dos literales firmados y tres declaraciones adjudicadas por doctrina. Diff de computed 0 sobre 2.240 valores en 7 estados; guard R-5.4 9/9, sin una sola adjudicación — su contrato ya era sano.
Los tres que faltan son un CANAL DE VALOR, no deuda. font-family,
font-size y font-weight leen var(--_s-tvl-*, <primitivo>), y el privado lo
escribe el componente INLINE en cada render:
eidos.resolve(size, 'md') / (family, 'primary') / (weight, 'regular')
siempre producen un valor, así que el estilo inline siempre está y el fallback
del CSS sólo cubre el render previo a que aterrice. Un
--s-text-virtual-list-font-* quedaría pisado por ese inline y mentiría —
la clase de --gp-current-gradient, del preview-z de drag-drop y del canal de
rect del indicador de navigation-menu.
El mando aquí ES la prop (size / family / weight), y el tema llega por
donde viven esos tokens: la capa tipográfica. Hay además una razón dura para que
el triple viaje por una variable y no por un token de receta: el canvas que
mide el texto lee getComputedStyle del contenedor, así que la fuente pintada
y la medida tienen que ser la MISMA — cualquier indirección que pudiera
divergir rompería el cálculo de anchuras de la virtualización.
Los dos literales son identidad: la lista ES el ancho de su contenedor y el espaciador ES el del scroller. Firmados con su anotación, fuera del ratio.
Su techo real es el 70 %, y está medido. Mismo caso que listbox (68 % a
propósito) o waveform (86 %): lo que queda fuera no es deriva, es una decisión
con dueño escrita.
Verificación: sonda antes/después 0 diffs (2.240 valores · 7 estados · 10
nodos) · R-5.4 9/9 · component:audit PASS · censo 70 % con las tres filas
restantes explicadas · eidos-lint 4 morfo-backed / 0 invalid, 0
class-hooks.