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/onion-menu.md

151 lines
8.4 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.

# onion-menu — 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**: **84%** — 16 de 19 knobs por token público
- **Knobs de apariencia**: 22 — público 16 · privado 0 · global 1 · literal 2 · sistema 3 · excepción 5 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 19 pública(s) — `trigger-lift`, `trigger-shadow`, `trigger-radius`, `trigger-fg`, `sector-shadow`, `sector-ring-fg`, `sector-ring-width`, `sector-hover-ring-width`, `label-font-family`, `label-font-weight`, `glyph-size`, `glyph-bar-thickness`, `glyph-bar-radius`, `muted-opacity`, `hover-ring-opacity`, `rim-width`, `rim-glow-width`, `rim-glow-opacity`, `rim-glow-blur`
- **Eje `size`**: no · **ficheros**: `onion-menu.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (1)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `onion-menu.css:202` | `.onion-menu-trigger` | `background` | `var(--_onion-trigger-fill)` |
### 1.2 A través de un privado (0)
_Ninguno._
### 1.3 Literales (2)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `onion-menu.css:180` | `.onion-menu-icon :global(svg)` | `inline-size` | `70%` |
| 2 | `onion-menu.css:181` | `.onion-menu-icon :global(svg)` | `block-size` | `70%` |
### 1.4 Excepciones firmadas (5) — 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 | `onion-menu.css:86` | `[data-look='luminous'] g:has([data-onion-menu-item]:hover) [data-onion-rim='glow']` | `opacity` | `1` |
| 2 | `onion-menu.css:146` | `.onion-menu-sector-group:not(.is-disabled):hover .onion-menu-label, .onion-menu-sector-group:not(.is-disabled):hover .onion-menu-icon` | `opacity` | `1` |
| 3 | `onion-menu.css:160` | `.onion-menu-icon` | `inline-size` | `100%` |
| 4 | `onion-menu.css:161` | `.onion-menu-icon` | `block-size` | `100%` |
| 5 | `onion-menu.css:165` | `.onion-menu-icon` | `line-height` | `1` |
## 2. Sistema transversal (3) — 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 | `onion-menu.css:50` | `.onion-menu-sector[data-disabled]` | `opacity` | `var(--opacity-muted, 0.55)` |
| 2 | `onion-menu.css:55` | `.onion-menu-sector:focus-visible` | `stroke` | `var(--focus-ring-color, currentColor)` |
| 3 | `onion-menu.css:230` | `.onion-menu-trigger:focus-visible` | `outline` | `2px solid var(--focus-ring-color, currentColor)` |
## 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 (`--onion-menu-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `width` | `root` | `70%` | 1 |
| `height` | `root` | `70%` | 1 |
| `bg` | `root` | `var(--_onion-trigger-fill)` | 1 |
### 4.2 Sin nombre mecánico (5)
- **⚠ decisión: `1` 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** — 3: `opacity`, `line-height`.
- **⚠ 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`, `block-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, 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-23 — 29 % → 84 %**, 7 claves nuevas (12 → 19) y 5 literales
ANOTADOS. Lo que queda fuera son TRES filas, y ninguna es deuda de tokenización:
una es canal de valor y dos viven en una regla que el navegador DESCARTA.
Lo acuñado: el color del **anillo del sector** —UNO para los dos estados, porque
el propio comentario del CSS dice que el hover usa «el mismo color que el anillo
de selección, más claro», y lo que los distingue es la opacidad que ya tenía
token—, la **tipografía de la etiqueta** (familia y peso), el **radio y la tinta
del disparador**, y las dos piezas del glifo `+`→`×` (su proporción y el radio
de las barras).
**Dos limpiezas de paso**: `var(--style-label-font-family, var(--style-label-font-family))`
era respaldo de sí mismo (el mismo defecto que se cazó en context-menu), y
`var(--radius-full, 50%)` / `var(--radius-full, 1px)` arrastraban respaldos que
no puede haber — el token existe.
**Cinco literales pasan a excepción por IDENTIDAD**: dos `opacity: 1` que
DESHACEN un atenuado (el de la marca muted y el del brillo del rim: «sin
atenuar» es 1 por definición) y la caja del icono (`100%` × 2 y `line-height: 1`).
**⚠ Una regla del recipe NO EXISTE: `.onion-menu-icon :global(svg)`.**
`:global()` es un envoltorio de SVELTE y esto es un CSS plano, así que el
selector es inválido y el navegador descarta la regla ENTERA. Medido: el glifo
computa 14px (el tamaño propio del Icon), y el `70%` que el fichero cree estar
pintando no pinta. Acuñé un `icon-glyph-size` y el centinela lo delató; lo
RETIRÉ y dejé los literales con el defecto escrito encima, porque arreglar el
selector empieza a pintar el 70 % y **mueve píxel**. Mismo bug en
`timeline.css:331`; `image-picker.css` documenta la trampa desde antes. → §13.
**Canal de valor**: el fondo del disparador (`--_onion-trigger-fill`) lo escribe
el componente INLINE desde el motor de color (`onion-menu.svelte:590`), como los
rellenos de cada sector. Ningún token gana a un estilo inline: no es superficie
de tema.
**Los 12 rojos del guard**: 6 los destapó el instrumento y 5 se midieron a mano.
- **El guard CERRABA el menú.** Esta superficie nace ABIERTA, y el clic de
«abrir» la cerraba: 12 de 20 tokens leían muertos. Ahora, si hay `openMarker`
y ya casa, no se pulsa nada. Con eso, 8 → 14.
- **El instrumento no veía las tripas**: sectores, etiquetas, iconos y glifo
cuelgan de CLASES, no de `data-onion-*` — sonda y guard miden ahora esos nodos
(37 en reposo, contra los 5 con atributo).
- `trigger-lift` **transiciona**: leído en el acto devuelve el valor viejo.
Congelado, alcanza.
- Los cuatro del rim son del look `luminous`, **que la demo del componente no
renderiza** (es una prop de Svelte que emite OTRO marcado, así que no hay
atributo que forzar): medidos en `/active/docs/agnt`.
- `rim-glow-opacity` enseñó algo nuevo: **el rim está bajo una ANIMACIÓN**, y
congelando sólo las transiciones se lee el valor animado (0,482956) y el token
parece muerto. Congelando también la animación computa 0,45 y sigue al token.
Verificación: **diff de computed = 0** sobre 7.328 valores en 8 estados (37
nodos) · centinela **14/19** con las cinco adjudicadas · censo 84 % ·
`component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 ·
`docs:check` 0 · `check` sin errores propios · capturas de reposo, sector en
hover y disparador.
<!-- veredicto:end -->

Powered by TurnKey Linux.