You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/audit/theming/toolbar.md

161 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# toolbar — 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](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
- **Medido**: 2026-08-24 · **Alcance**: **94%** — 30 de 32 knobs por token público
- **Knobs de apariencia**: 34 — público 30 · privado 2 · global 0 · literal 0 · sistema 2 · excepción 1 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 54 pública(s) — `gap-xs`, `gap-sm`, `gap-md`, `gap-lg`, `padding-inline-xs`, `padding-inline-sm`, `padding-inline-md`, `padding-inline-lg`, `padding-block-xs`, `padding-block-sm`, `padding-block-md`, `padding-block-lg`, `control-height-xs`, `control-height-sm`, `control-height-md`, `control-height-lg`, `control-padding-inline-xs`, `control-padding-inline-sm`, `control-padding-inline-md`, `control-padding-inline-lg`, `control-gap-xs`, `control-gap-sm`, `control-gap-md`, `control-gap-lg`, `font-family`, `font-size-xs`, `font-size-sm`, `font-size-md`, `font-size-lg`, `line-height`, `radius`, `bg`, `border`, `border-width`, `shadow`, `fg`, `group-gap`, `control-radius`, `control-border-width`, `control-border`, `hover-control-border`, `active-control-border`, `control-bg`, `active-control-bg`, `control-fg`, `hover-control-fg`, `active-control-fg`, `separator-bg`, `separator-thickness`, `separator-length`, `separator-radius`, `transition-duration`, `transition-ease`, `disabled-opacity`
- **Eje `size`**: sí · **ficheros**: `toolbar.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (0)
_Ninguno._
### 1.2 A través de un privado (2)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `toolbar.css:22` | `[data-toolbar]` | `background` | `var(--_toolbar-bg)` |
| 2 | `toolbar.css:23` | `[data-toolbar]` | `box-shadow` | `var(--_toolbar-shadow)` |
### 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 | `toolbar.css:158` | `[data-toolbar-separator][data-orientation='horizontal']` | `inline-size` | `100%` |
## 2. Sistema transversal (2) — 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 | `toolbar.css:122` | `[data-toolbar-link]:hover, [data-toolbar-group-item]:hover:not([data-disabled])` | `background-image` | `linear-gradient(var(--state-hover), var(--state-hover))` |
| 2 | `toolbar.css:128` | `[data-toolbar-link]:focus-visible, [data-toolbar-group-item]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
## 3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_toolbar-gap` | 4 | `var(--toolbar-gap-md)`, `var(--toolbar-gap-xs)`, `var(--toolbar-gap-sm)`, `var(--toolbar-gap-lg)` | public | **sí** |
| `--_toolbar-padding-inline` | 4 | `var(--toolbar-padding-inline-md)`, `var(--toolbar-padding-inline-xs)`, `var(--toolbar-padding-inline-sm)`, `var(--toolbar-padding-inline-lg)` | public | **sí** |
| `--_toolbar-padding-block` | 4 | `var(--toolbar-padding-block-md)`, `var(--toolbar-padding-block-xs)`, `var(--toolbar-padding-block-sm)`, `var(--toolbar-padding-block-lg)` | public | **sí** |
| `--_toolbar-control-height` | 4 | `var(--toolbar-control-height-md)`, `var(--toolbar-control-height-xs)`, `var(--toolbar-control-height-sm)`, `var(--toolbar-control-height-lg)` | public | **sí** |
| `--_toolbar-control-padding-inline` | 4 | `var(--toolbar-control-padding-inline-md)`, `var(--toolbar-control-padding-inline-xs)`, `var(--toolbar-control-padding-inline-sm)`, `var(--toolbar-control-padding-inline-lg)` | public | **sí** |
| `--_toolbar-control-gap` | 4 | `var(--toolbar-control-gap-md)`, `var(--toolbar-control-gap-xs)`, `var(--toolbar-control-gap-sm)`, `var(--toolbar-control-gap-lg)` | public | **sí** |
| `--_toolbar-font-size` | 4 | `var(--toolbar-font-size-md)`, `var(--toolbar-font-size-xs)`, `var(--toolbar-font-size-sm)`, `var(--toolbar-font-size-lg)` | public | **sí** |
| `--_toolbar-bg` | 3 | `var(--toolbar-bg)`, `transparent` | literal, public | no |
| `--_toolbar-border` | 2 | `var(--toolbar-border)`, `transparent` | literal, public | no |
| `--_toolbar-shadow` | 3 | `var(--toolbar-shadow)`, `none` | literal, public | no |
## 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 guard `recipe-css-contract` prohí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 (`--toolbar-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `bg` _(ya existe)_ | `root` | ⚠ `var(--toolbar-bg)` / `transparent` | 3 |
| `shadow` _(ya existe)_ | `root` | ⚠ `var(--toolbar-shadow)` / `none` | 3 |
### 4.2 Sin nombre mecánico (1)
- **⚠ 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** — 1: `inline-size`.
### 4.3 Avisos sobre los tokens propuestos (2)
- **el privado `--_toolbar-bg` debe pasar a leer este público (o desaparecer)** — `--toolbar-bg`
- **el privado `--_toolbar-shadow` debe pasar a leer este público (o desaparecer)** — `--toolbar-shadow`
### 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, un `background` en 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
<!-- veredicto:start -->
**Ejecutado 2026-08-24 · 91 % → 94 % — CERRADO en su número.** 34 knobs · 30
públicos · 2 privados · 1 excepción firmada · 2 sistema. Contrato **54** claves,
sin acuñar ninguna nueva. Diff de computed **VACÍO** (2.464 valores, 7 estados,
11 nodos). Centinela **52/54**, 2 adjudicadas.
**No había nada que acuñar, y eso es el hallazgo.** El censo daba `global 0`: la
receta ya lee su propio contrato en cada declaración, con el eje `size`
resuelto por el TSC a través de siete privados que sólo reapuntan claves
públicas por talla. Lo que quedaba fuera del alcance eran **tres cosas
clasificadas, no tres deudas**.
**1. Los dos privados son CONMUTADORES por variante** (medido variante a
variante en el nodo real): `--_toolbar-bg` vale `var(--toolbar-bg)`
(`oklch(0.9821 0 0)`) en `surface` y `transparent` en `outline` y `ghost`;
`--_toolbar-shadow` vale `var(--toolbar-shadow)` y `none` en las mismas. Ese
segundo valor es la **identidad de la variante**, no un knob: una barra `ghost`
ES la que no tiene relleno ni sombra, y un público encima dejaría que un tema la
rellenara y matara la variante en silencio. Aplanarlo obligaría además a
duplicar cada regla por variante — la clase «conmutador» de F2-B, quinto caso
tras `textarea`, `spinner`, `skeleton`, `code` y `label`. `--_toolbar-border` es
el mismo conmutador; el censo lo cuenta como público porque el atajo `border`
lleva también el ancho, que sí es token. **Ni escala por talla ni puente THM-2:
esta barra no tiene paleta.**
**2. El único literal es una IDENTIDAD y ahora está firmado.** El
`inline-size: 100%` del separador horizontal abarca el eje transversal de la
barra — el mismo trabajo que `align-self: stretch` hace en el gemelo vertical
(medido: 112 px sobre un contenedor de 126 px). Su grosor y su suelo (`min-inline-size`)
sí son tokens. Con su anotación `/* literal: */` sale del ratio: 91 % → 94 %.
**3. La cascada del componente compuesto NO le cuesta una sola clave.**
`Toolbar.Button` compone el `<Button>` canónico, así que sus nodos llevan
`data-button` Y `data-toolbar-button`, y `[data-button]` casa con la misma
especificidad (0,1,0) pero se emite DESPUÉS. La diferencia con `form` —que
conserva 24 declaraciones que Button anula— es que esta receta **ya cedió el
cromo del botón** (A-112) y no escribe ni una regla `[data-toolbar-button]`.
Medido antes de tocar nada: 51/54 vivos, y las tres silenciosas no eran del
botón. **Las claves `control-*` visten el Link y el GroupItem**, que sí son
superficie de la barra.
**Las dos silenciosas del guard, medidas.** `transition-duration` y
`transition-ease` **SON** la transición que el centinela congela para poder leer
todo lo demás. Medidas sin congelar sobre el Link real, que transiciona CUATRO
propiedades: `0.12s ×4 → 4.321s ×4` y `cubic-bezier(0.4, 0, 0.2, 1) ×4 →
steps(3) ×4`. Al ledger con esa razón.
**Y una que NO hizo falta adjudicar.** `disabled-opacity` leía muerta porque el
escenario no lleva el estado. El guard enciende ahora el interruptor «group
disabled» de la demo, y no tapa nada: la regla de hover es
`[data-toolbar-link]:hover, [data-toolbar-group-item]:hover:not([data-disabled])`
y el Link no pertenece al grupo, así que conserva las dos claves de hover.
Comprobado corriendo el guard antes y después del control: 51/54 → 52/54, el
conjunto muerto encoge en uno y no gana ninguno.
**Veredicto: CERRADO en 94 %.** Lo que queda fuera es un conmutador de dos
ramas cuya segunda rama es la identidad de la variante. Forzar la cifra sería
romper `variant`.
<!-- veredicto:end -->

Powered by TurnKey Linux.