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

11 KiB

navigation-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 · método y protocolo: PLAN-theming.md §1, §2, §7.

  • Medido: 2026-08-24 · Alcance: 100% — 33 de 33 knobs por token público
  • Knobs de apariencia: 37 — público 33 · privado 0 · global 0 · literal 0 · sistema 4 · excepción 1 (los dos últimos, fuera del ratio)
  • Contrato hoy (lib/recipes/base.ts): 44 pública(s) — content-z, indicator-w, indicator-thickness, indicator-bg, indicator-radius, trigger-height-sm, trigger-height-md, trigger-height-lg, trigger-font-size-sm, trigger-font-size-md, trigger-font-size-lg, trigger-line-height-sm, trigger-line-height-md, trigger-line-height-lg, trigger-padding-inline-sm, trigger-padding-inline-md, trigger-padding-inline-lg, trigger-radius-sm, trigger-radius-md, trigger-radius-lg, trigger-height, trigger-font-size, trigger-line-height, trigger-padding-inline, trigger-radius, trigger-fg, active-trigger-fg, active-trigger-bg, disabled-trigger-fg, trigger-font-family, trigger-gap, chevron-size, chevron-stroke, list-gap-sm, list-gap-md, list-gap-lg, list-gap, content-min-width, content-padding, content-radius, content-fg, content-link-padding-block, content-link-padding-inline, content-link-radius
  • Eje size: no · ficheros: navigation-menu.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 (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 navigation-menu.css:360 [data-navigation-menu-indicator][data-state='open'] opacity 1

2. Sistema transversal (4) — 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 navigation-menu.css:130 [data-navigation-menu-trigger]:focus-visible, [data-navigation-menu-link]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
2 navigation-menu.css:151 [data-navigation-menu-trigger]::after opacity var(--opacity-muted)
3 navigation-menu.css:232 [data-navigation-menu-content] :is(a, [data-navigation-menu-link]):hover background-image linear-gradient(var(--state-hover), var(--state-hover))
4 navigation-menu.css:236 [data-navigation-menu-content] :is(a, [data-navigation-menu-link]):focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)

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

  • Consume la capa compartida menu-indicator. Un eje que la capa posee se consume como var(--_x, var(--x)); el consumidor no acuña --navigation-menu-{eje} para él — sería un vocabulario paralelo (README de eidos/components, «Capas compartidas» regla 2).

4.1 Tokens a declarar en lib/recipes/base.ts (0)

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 (--navigation-menu-…) scope TSC valor propuesto usos

4.2 Sin nombre mecánico (1)

  • ⚠ 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 — 1: opacity.

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

EJECUTADO 2026-08-23 — 44 % → 100 %. Contrato 26 → 44 claves (19 nuevas, una retirada). Diff de computed 0 sobre 2.752 valores en 8 estados; guard R-5.4 43/44 con una adjudicación escrita. Bloque B1 de D-TH.4.

Los 19 knobs, y de dónde salió cada nombre. Ninguno se inventó: el catálogo los tenía. dropdown-menu / context-menu (los gemelos cerrados el mismo día) dan content-{min-width,padding,radius,fg} y chevron-{size,stroke}; accordion da trigger-font-family y disabled-trigger-fg; nav-tree y card-group confirman que el tamaño de un chevron es un literal en las cuatro recetas que lo declaran (0.42em, 0.5em, 0.625rem) — un glifo no es un paso de la escala de espacio. Al revés con el subrayado: 2px ES --border-width-medium, y el precedente dropdown-menu.separator-thickness dice que un grosor decorativo se nombra por esa familia.

Lo que la §4 generada proponía, y por qué NO se siguió — cinco fallos, uno nuevo. Llamaba trigger-width / trigger-height al CHEVRON (nombrando por el primer selector de la regla, […-trigger]::after, y colisionando con trigger-height, que ya existe y es la altura del control); fundía en content-radius dos nodos con dos valores (panel --radius-lg y fila --radius-md); cruzaba los nombres (content-padding-* para lo que es de la FILA, y el padding real del panel a §4.2 «sin nombre mecánico»); llamaba content-width a un min-inline-size. Y el fallo NUEVO: abría pidiendo «consume la capa compartida menu-indicator» — homonimia: esa capa es el CHECK de los CheckboxItem de dropdown/context-menu, no tiene nada que ver con el subrayado de esta barra. LAYER_VOCABULARY sólo registra calendar-surface, y nav-menu no consume ninguna capa.

Las filas del panel no son item- ni link-. En los gemelos, item ES la fila; aquí item es el <li> de la barra (parte del morfo) y el Link de barra viste el cromo del trigger. Un --navigation-menu-item-radius o un --navigation-menu-link-radius prometerían a un tema un nodo que no alcanzan. Se acuñan como content-link-* — el nodo, nombrado por donde vive. Su tinta sigue leyendo trigger-fg, como venía (D-TH.5: el default no se mueve).

El privado era una ESCALA, no un conmutador. --_navigation-menu-list-gap tenía tres fuentes (0 / --space-1 / --space-2) por data-size: eso sube al TSC como list-gap-{sm,md,lg} + el resuelto, el mismo molde que el bundle del trigger ya tenía al lado. Los dos bloques [data-size] del CSS se retiran (los emite el TSC; dejarlos vivos da un diff de 0 por la ruta vieja).

indicator-x era declaración MUERTA y se retiró. Soma escribe las cuatro coordenadas del rect INLINE sobre el indicador (-x, -y, -w, -h); la receta lee sólo -w y -h, y su propio comentario registra que sumar translateX(var(--…-x)) DUPLICABA el desplazamiento. Nadie la leía. Retirada, 0 diffs — la prueba de que estaba muerta (precedente: el re-point de --command-radius, el trío item-gap* de carousel). -w se queda: vive, y es canal de valor, no superficie de tema.

El panel NO acuña tipografía, y es a propósito. Lleva [data-depth='overlay'], y ese plano declara font-family / line-height con la misma especificidad (0,1,0) y más tarde en la cascada: un token de la receta ahí leería muerto. Es la firma §12.9 pendiente, la misma que hizo retirar claves en menubar, dropdown-menu, context-menu y tooltip. Lo que sí se acuña es la familia de la BARRA (trigger-font-family), que no es overlay y alcanza.

Lo que el instrumento aprendió aquí (tres cosas, todas medidas):

  1. La sonda y el centinela eran ciegos a la mitad del componente. Las filas del mega-menú son los <a> DESNUDOS del consumidor, sin atributo propio: el filtro data-{c}-* veía 10 nodos y ninguno era el panel ni una fila — 9 de los 19 knobs quedaban fuera del diff. Con EXTRA_NODES / extraNodes la sonda pasa a 16 nodos abiertos. Y el paso open de la sonda no honraba EXTRA_NODES: ahora sí.
  2. El guard cerraba el panel él mismo. Este mega-menú abre por pointerenter y pointerleave programa el cierre; el guard abría con clic y después aparcaba el puntero en (0,0) — que es exactamente lo que lo cierra. Dos corridas del mismo código discrepaban en content-link-padding-inline. Con openBy: 'hover' el cursor se queda en el trigger: dos corridas idénticas, 43/44. El síntoma tenía además una cara de falso POSITIVO: ese mismo token leía «vivo» antes de ver las filas, porque su padding ensancha el panel que sí se medía.
  3. color está en transición en esta parte, así que forzar data-disabled y leer en el acto devuelve el valor VIEJO: tres diagnósticos falsos («ni el inline lo mueve») hasta congelar transition. Es la trampa del cuentagotas del color-picker, en otro componente. Congelado: reposo oklch(0.2435 0 0) → disabled oklch(0.61 0 0), y el centinela lo mueve a rgb(1,2,3) en el trigger y en el Link.

La adjudicación (1): disabled-trigger-fg — la demo no monta ningún trigger ni Link deshabilitado; forzado alcanza en las dos partes. En el ledger.

Una nota de contabilidad, no del componente: esta ficha dice ahora «eje size: no». El censo detecta el eje grepeando data-size en el CSS de la receta, y el protocolo §7.4 ORDENA retirar esos bloques cuando la cascada la emite el TSC — así que todo componente que aplique bien el protocolo aparecerá sin eje. Ya le pasa a sidebar y nav-tree. Anotado en next-features §13; el eje existe y se emite en generated/base.css.

Verificación: sonda antes/después 0 diffs (2.752 valores · 8 estados · 16 nodos con el panel abierto) · R-5.4 43/44, dos corridas idénticas · component:audit PASS · censo 100 % · eidos-lint 30 morfo-backed / 3 eidos-only / 0 invalid, 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el único rojo es skin-media-player, el conocido) · check sin error nuevo en los ficheros tocados (el de sideOffset en navigation-menu-content.svelte es preexistente, commit 3097cfcb6) · verificado en Chrome con el panel abierto (panel 8/10px/224px · fila 8/12/6px · trigger 36px/6px/gap 4px · indicador 2px). Tras el cambio del guard, command, table y tooltip re-verificados sin regresión ni STALE.

Powered by TurnKey Linux.