11 KiB
tooltip — 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: 94% — 15 de 16 knobs por token público
- Knobs de apariencia: 20 — público 15 · privado 1 · global 0 · literal 0 · sistema 1 · excepción 2 · estructural 0 · puente 0 · canal 3 (los cinco últimos, fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 23 pública(s) —content-z,max-width,padding-block-sm,padding-inline-sm,padding-block-md,padding-inline-md,padding-block-lg,padding-inline-lg,font-size-sm,font-size-md,font-size-lg,font-family,font-weight,line-height,radius,border-width,bg,fg,border,shadow,ghost-blur,outline-arrow-bg,outline-arrow-border - Eje
size: sí · ficheros:tooltip.css
1. Knobs fuera de alcance
1.1 Directo a primitivo global (0)
Ninguno.
1.2 A través de un privado (1)
Sólo el residuo: el puente de paleta (§2-ter) y el canal de valor (§2-quater) salen aparte, porque no son deuda ni tienen nombre que acuñar.
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | tooltip.css:42 |
[data-tooltip-content] |
background |
var(--_tooltip-bg) |
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 | tooltip.css:27 |
[data-tooltip-content] |
inline-size |
var(--_tooltip-width) |
| 2 | tooltip.css:159 |
[data-tooltip-content][data-state='instant-open'] |
opacity |
1 |
2. Sistema transversal (1) — 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 | tooltip.css:188 |
[data-tooltip-trigger]:focus-visible |
outline |
var(--focus-ring-width) solid var(--focus-ring-color) |
2-quater. Canal de valor (3) — fuera del ratio
Acta 2026-08-26 — un knob cruzó de «excepción firmada» a «canal», por MEDIDA.
tooltip.css:27(inline-size: var(--_tooltip-width)) aparece arriba en §1.4 porque hasta hoy sólo lo salvaba la firma a mano de la declaración; la firma §14 extendió la regla de canal del censo al caso TRANSITIVO —un privado declarado cuyas fuentes resuelven TODAS a canales ES canal— y--_tooltip-widthes exactamente eso:var(--_tooltip-content-width-override, var(--_tooltip-match-anchor-width, auto)), dos nombres que nadie declara y que se escriben por instancia. El propio comentario de la declaración ya lo decía con esas palabras («per-instance VALUE CHANNEL»); lo que faltaba era el mecanismo, no el criterio. Por eso NO es una reclasificación a la baja: es el cuarto paso del censo funcionando como está escrito («una firma sobre un knob que la máquina ya adjudicó es un acta sin nada que firmar»). Al regenerar, esta hoja leerá canal 4 · excepción 1 · knobs 21 (elexceptionno entra en el total de knobs y elchannelsí; el ALCANCE no se mueve: 94 %, los dos están fuera del ratio).Lo que la extensión no se lleva por delante, y es la mutación de rigor que la delimita:
--_tooltip-max-widthleevar(--_tooltip-content-max-width-override, var(--tooltip-max-width))y su knob sigue siendo público, porque el segundo paso del censo (deriva de un público) corre ANTES que el tercero. Ese orden es carga estructural de la extensión, no casualidad. Un alias sobre un privado que SÍ está declarado tampoco cuela: resuelve al valor de esa declaración, cuyas refs son vacías o no son canal.
La receta lee un privado que nadie declara — ni su CSS ni el generador: lo
escribe soma o el envoltorio por instancia (un %, un rect medido, la talla
que pide una prop). Un tema no debe alcanzarlo: fijarlo rompe el
comportamiento, y por eso tabs rechazó por escrito esa misma propuesta.
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | tooltip.css:28 |
[data-tooltip-content] |
min-inline-size |
var(--_tooltip-content-min-width-override, auto) |
| 2 | tooltip.css:30 |
[data-tooltip-content] |
block-size |
var(--_tooltip-content-height-override, auto) |
| 3 | tooltip.css:31 |
[data-tooltip-content] |
min-block-size |
var(--_tooltip-content-min-height-override, auto) |
3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
|---|---|---|---|---|
--_tooltip-padding-block |
3 | var(--tooltip-padding-block-md), var(--tooltip-padding-block-sm), var(--tooltip-padding-block-lg) |
public | sí |
--_tooltip-padding-inline |
3 | var(--tooltip-padding-inline-md), var(--tooltip-padding-inline-sm), var(--tooltip-padding-inline-lg) |
public | sí |
--_tooltip-font-size |
3 | var(--tooltip-font-size-md), var(--tooltip-font-size-sm), var(--tooltip-font-size-lg) |
public | sí |
--_tooltip-bg |
3 | var(--tooltip-bg), transparent, color-mix(in srgb, var(--color-surface-overlay) 70%, transparent) |
exception, global, public | no |
--_tooltip-border |
3 | var(--tooltip-border), var(--color-border-strong), transparent |
global, literal, public | no |
--_tooltip-shadow |
3 | var(--tooltip-shadow), none |
exception, public | no |
--_tooltip-width |
1 | var(--_tooltip-content-width-override, var(--_tooltip-match-anchor-width, auto)) |
private | no |
--_tooltip-max-width |
1 | var(--_tooltip-content-max-width-override, var(--tooltip-max-width)) |
public | sí |
--_tooltip-max-height |
1 | var( --_tooltip-content-max-height-override, var(--floating-available-height, calc(100dvh - var(--space-4))) ) |
global | no |
Consumidos y no declarados en el CSS (vienen de base.ts o de un estilo inline del wrapper): --_tooltip-content-height-override, --_tooltip-content-max-height-override, --_tooltip-content-max-width-override, --_tooltip-content-min-height-override, --_tooltip-content-min-width-override, --_tooltip-content-width-override, --_tooltip-match-anchor-width.
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).
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 (--tooltip-…) |
scope TSC | valor propuesto | usos |
|---|---|---|---|
content-bg |
root |
⚠ var(--tooltip-bg) / transparent / color-mix(in srgb, var(--color-surface-overlay) 70%, transparent) |
3 |
content-width |
root |
var(--_tooltip-width) |
1 |
4.2 Sin nombre mecánico (1)
- ⚠ decisión:
1es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar — 1:opacity.
4.3 Avisos sobre los tokens propuestos (1)
- el privado
--_tooltip-bgdebe pasar a leer este público (o desaparecer) —--tooltip-content-bg
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 — 52 % → 75 %, 3 claves nuevas y 4 literales anotados.
Subiría más, pero medir destapó que cinco de sus claves no pintan: el plano
overlay le gana la superficie ENTERA.
Lo acuñado: el desenfoque del velo ghost (ghost-blur) y las dos tintas de la
flecha en outline (relleno y trazo), que se pintan por selector HERMANO desde
el contenido.
⚠⚠ EL PLANO NO SÓLO SE QUEDA LA TIPOGRAFÍA: SE QUEDA EL FONDO, EL BORDE Y LA
SOMBRA. [data-depth='overlay'] declara las tres con la misma especificidad
que [data-tooltip-content] y más tarde en la cascada. Medido: escribir
--tooltip-bg, --tooltip-border o --tooltip-shadow no mueve NADA, mientras
--depth-overlay-surface / -border / -shadow repintan el panel. Con
font-family y line-height, son cinco públicos que no alcanzan.
Y la consecuencia visual es peor que la contable: las tres variantes son la
misma. Medidas solid, outline y ghost con el panel abierto: fondo, borde
y sombra IDÉNTICOS en las tres. outline es indistinguible de solid; ghost
sólo se diferencia por un backdrop-filter que no se ve porque la superficie
que tiene delante es opaca. La máquina de variantes existe, alimenta privados y
el plano la anula entera. → §13.
Por eso no se acuñó ghost-bg: lo intenté, el centinela lo delató y se
retiró antes de commitear. Las cinco que ya estaban quedan adjudicadas por
escrito, no retiradas: son la FUENTE de esa máquina de variantes, y borrarlas
dejaría inválidos los privados sin arreglar nada. La corrección de fondo es la
precedencia del plano — la misma firma §12.9 que arrastran menubar, dropdown-menu
y combobox.
content-z sí está vivo, pero en otro nodo: aterriza en el ENVOLTORIO
flotante (90 → 4321), que no lleva ningún data-tooltip-* y por eso queda fuera
del conjunto medido.
Instrumento: un tooltip abre por HOVER, no por clic —openBy: 'hover', como
link-preview—, y con eso pasó de 0/24 a 14/24. El resto se midió con el
interruptor open de la demo: un panel abierto por puntero exige el ratón
quieto sobre el disparador toda la pasada, y no es medida fiable.
Verificación: diff de computed = 0 sobre 256 valores en 8 estados ·
centinela 15/23 con las ocho adjudicadas · censo 75 % · suite eidos con el
rojo conocido ajeno · rtl:check 0 · docs:check 0.