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/process/CONTINUE-nav-tree.md

100 lines
5.8 KiB

uix(nav-tree): F1.8 CERRADA · demo + navegador + review adversarial Cierra el árbol de navegación data-driven (E-1) de F1: demo canónica de 9 pestañas con el mapa real de docs (43 nodos, 3 niveles), verificación en navegador real y review adversarial (5 dimensiones × 3 verificadores escépticos; 22 hallazgos brutos, 10 confirmados) con todos los confirmados arreglados. Arreglos del review - sema: la parte `group` —target de los eventos emerge— se registraba SIN `ref`, así que `runtime.trigger` lanzaba `SomaRuntimeTargetError` en silencio y el pack no sonaba nunca (cero `data-event-*` en el grupo frente a los de collapsible). El provider posee ahora el ref del `<ul>`. - eidos: en una fila navegable el chevron resolvía `inline-size: 100%` como flex-basis y ocupaba media fila (101 de 231 px en «Soma»), robándole clics al enlace. Toggle compacto con suelo de diana de 24 px (WCAG 2.5.8). - soma: una clave duplicada podía volver cíclico `parentByKey` y colgar la pestaña dentro de `trailKeys` (deriva en render) → clave sufijada + aviso del logger + guarda de ciclo en el paseo. - soma: el colapso es CONTEXTUAL (recuerda el `activeKey` bajo el que se hizo): cerrar la sección que lees se respeta, pero caduca al navegar DENTRO del grupo, para que la página actual nunca quede sin fila visible. Sigue siendo query pura, sin `$effect` que escriba estado. - soma: `child` recibe también `children` (el árbol renderizado); antes dejaba el landmark vacío, porque un árbol data-driven no lo puede reautorar el consumidor. - morfo + langs: el nombre accesible del chevron se declara en el contrato y se localiza («Alternar sección {label}»); ya no duplica el del enlace. - eidos: RTL completo — el glyph espeja solo (bordes lógicos), lo que no espeja es el giro, así que bajo `[dir='rtl']` las dos rotaciones se intercambian. El Gap «dirección del chevron en RTL» queda RESUELTO. - demo: paridad de snippet con los controles vivos; fuera el token fantasma `--nav-tree-rail-width` del docblock del recipe. badge en v1 (decisión del usuario, delegada) Está en el suelo de paridad del dossier §P5 (los 6 refs lo llevan). Se resuelve con SNIPPET, no con recursión a nivel de eidos: el morfo declara la parte `badge`, soma renderiza el snippet recibido (sin él, el valor crudo — sigue siendo headless) y el wrapper de eidos pasa el `Badge` canónico. Va DENTRO del control de la fila, así su texto entra en el nombre accesible («TSC, New, enlace»). `disabled` se descarta en v1 (fuera del suelo, y un enlace de navegación deshabilitado es semánticamente dudoso); ambos quedan registrados en la tabla de Gaps. Verificado: `component:audit` PASS · eidos-lint 26 morfo-backed / 0 invalid · `svelte-check` 0 errores en estos archivos · `vitest src/uix/eidos` 353/353 · navegador real (Playwright): trail auto-expandido, sema estampando en el grupo, teclado nativo, foco visible, claro y oscuro, RTL, 375 px sin desbordes, 0 errores de consola. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
# CONTINUE — F1.8 `nav-tree` (handoff 2026-07-22) · **CERRADO**
> **F1.8 HECHA (2026-07-22).** Este handoff queda como registro de la tanda:
> demo, verificación en navegador real, review adversarial (10 hallazgos
> confirmados, todos arreglados) y cierre están completos. El registro
> definitivo vive en `docs/process/PLAN-blocks.md` §7. Lo que sigue es el
> estado tal como quedó al PARAR aquella sesión (histórico).
Estado al parar: **componente COMPLETO y en verde en todos los gates
estáticos; falta demo + verificación en navegador + review adversarial +
commit final + registro**. Plan maestro: `docs/process/PLAN-blocks.md` §F1.8.
## Qué es (decisiones ya tomadas y ratificadas en fase 0)
Árbol de navegación **data-driven** (E-1) para docs-shell: el app pasa
`nodes` (datos) + `activeHref` (su URL); el componente resuelve el nodo activo,
deriva el trail de ancestros y **auto-expande** el trail. APG **Disclosure
Navigation** (landmark `<nav>` + links nativos + botones disclosure), NO
`tree-view` (que es un WIDGET de selección `role=tree`).
**Frontera vs `tree-view`**: rol + interacción + modelo de datos distintos →
componente separado, no extensión. (Scope-approval cerrado.)
**Decisiones de diseño** (todas implementadas):
- **Disclosure propio** (no compone Collapsible): el estado `open` es un getter
de soma (el expand-set) que alimenta `aria-expanded`/`data-state`; el toggle
dispara `emerge-expand`/`emerge-collapse` vía `runtime.trigger` (sema +
`setExpanded`). NO hay máquina de eventos que sostenga el estado.
- **`emerge` + pack de sema**: corregido en fase 5 — el audit A-3.1 exige
eventos en un componente interactivo; el toggle de disclosure ES un `emerge`
canónico (espeja collapsible/tree-view). scope = `['soma','sema','eidos']`.
- **Filas propias** (`<a>`/`<button>` estilizados por el recipe), NO `Link`/
`Button` compuestos — como anchor-nav; el contrato a11y es de nav-tree.
- **`isExpanded` es query PURA** (sin `$effect` que escriba estado): abierto si
no-colapsado-por-usuario Y (expandido-por-usuario O en-trail O `defaultOpen`).
- **Profundidad = CSS var** `--_nav-tree-depth` (no attr por nivel).
- **Nodo padre navegable** = link + chevron (patrón Fumadocs); sin href = botón.
## Ficheros (todos escritos, type-clean)
- Morfo: `src/uix/morfo/components/nav-tree.ts` (6 partes; eventos emerge;
`expression:'pack'`).
- Soma: `src/uix/soma/components/nav-tree/` — `nav-tree-provider.svelte.ts`
(`NavTreeProvider` raíz + `NavTreeItemProvider` por nodo), `types.ts`,
`langs.ts`, `components/nav-tree.svelte` (Provider), `components/nav-tree-node.svelte`
(recursivo), `exports.ts`, `index.ts`, `README.md`.
- Eidos: `src/uix/eidos/components/nav-tree/` — `nav-tree.svelte` (forward),
`nav-tree.css` (recipe), `types.ts`, `index.ts`, `README.md`.
- Sema pack: `src/uix/sema/components/nav-tree.ts`.
- Langs: `src/uix/langs/components/nav-tree.ts`.
- Registros: `langs/components/index.ts`, `soma/components/index.ts`,
`sema/components/index.ts`, `eidos/lib/recipes/base.ts` (token `indent`),
`eidos/generated/base.css` (generado), `web/routes/uix/+layout@.svelte`
(pack `navTreeSema` registrado).
## Gates que YA pasan
- `npx tsx scripts/component-audit.ts --only nav-tree` → **PASS**.
- `npx tsx scripts/eidos-lint.ts nav-tree` → 20 morfo-backed, 0 invalid.
- `npx svelte-check` → 0 errores en nav-tree + pack.
- `npx vitest run src/uix/contracts.test.ts` → mis partes limpias.
⚠️ Quedan **2 fallos AJENOS** (menubar-provider DOM-write · radio-group
`data-ready`) de sesiones paralelas SIN commitear — NO son de nav-tree.
## Qué FALTA (orden para mañana)
1. **Demo** `web/routes/uix/components/nav-tree/+page.svelte` — canónica, misma
profundidad que anchor-nav (9 pestañas: live/system/motion/sema/services/
api/morfo/recipe/a11y; harness `SystemAxes`/`MotionPanel`/`SemaPanel`/
`DemoTrace`; `type Tab` en UNA línea con `// prettier-ignore`). Contenido
live: un árbol REAL de ~40 nodos y 3 niveles (p. ej. el mapa de `docs/`),
control de `activeHref` (select o los propios links moviéndolo), trail vivo.
El pack de sema YA está registrado en el layout.
2. **Entrada de nav**: añadir `nav-tree` a la lista de componentes en
`web/routes/uix/+layout@.svelte` (donde se añadió `anchor-nav`).
3. **Verificar en NAVEGADOR** (obligatorio, es UI): árbol renderiza; trail
auto-expandido al cambiar `activeHref`; chevron rota en `data-state=open`;
link activo toma color primary + peso; grupo colapsado = `hidden`;
`aria-current="page"` + `aria-expanded`/`aria-controls` correctos; DARK
(`colorScheme:'dark'` vía Playwright) y RTL. ⚠️ El Browser pane SUSPENDIDO
da `getComputedStyle` de color OBSOLETO (lección anchor-nav) — si el color
activo se ve mal, verifícalo en chromium foreground, NO es bug.
4. **Review adversarial** (workflow, como sticky/anchor-nav): dimensiones
correctness-scrollspy/trail · reactividad-lifecycle · morfo-a11y ·
css-recipe. Verificador escéptico por hallazgo. Arregla confirmados.
5. **Commit final + registro** en `PLAN-blocks.md` §7 (F1.8 HECHA) + memoria
`project_blocks_tier_2026-07-21.md` (F1 = 7/8) + `MEMORY.md`.
## Gotchas / lecciones de esta tanda
- **Correr `contracts.test.ts`**, no solo `npm run check` — destapa READMEs de
soma faltantes (le pasó a anchor-nav) y attrs/DOM-writes hardcodeados.
- `aria-expanded` necesita `stateRef` (da `'true'/'false'`); un `propRef`
booleano NO (el resolver solo convierte booleanos en aria para `stateRef`).
- El estado de un part se puede alimentar con un getter (`states:{open:()=>…}`)
sin evento; los eventos emerge son para la sema (espeja collapsible).
- `resolveProps(bindings)` es puro pero NO incluye el marker/id; el patrón
data-driven blessed es **providers per-nodo con `renderProps()`** (menubar).

Powered by TurnKey Linux.