diff --git a/src/uix/eidos/ARCHETYPE_COHERENCE_AUDIT_2026-06-19.md b/src/uix/eidos/ARCHETYPE_COHERENCE_AUDIT_2026-06-19.md index 7fcc53d20..c490d2324 100644 --- a/src/uix/eidos/ARCHETYPE_COHERENCE_AUDIT_2026-06-19.md +++ b/src/uix/eidos/ARCHETYPE_COHERENCE_AUDIT_2026-06-19.md @@ -31,6 +31,35 @@ consuman por defecto**. --- +## ESTADO DE IMPLEMENTACIÓN — hand-off 2026-06-22 + +**B2 COMPLETO — el plano de elevación adoptado por TODOS los overlays.** 4 commits (pusheados a +`gita active-uix`): dropdown (`f80f2225`) · context-menu+menubar+navigation-menu (`009f5367`) · +link-preview+command (`be5396ce`) · select+combobox (`d578f832`). Patrón por overlay: el wrapper +eidos del `Content` estampa `data-depth="overlay"`, se podan border/bg/shadow del CSS (+ tokens del +recipe en dropdown/context-menu/select) y el arrow apunta a `--depth-overlay-surface`/`-border`. +dialog/drawer ya en plano `modal` (2026-06-20). + +- **FUERA por diseño** (no son targets del plano): `tooltip` (el variant ES el material — solid + relleno / outline transparente / ghost con blur —, no énfasis sobre un trigger) · `listbox` (lista + inline `surface-default` sin sombra, no overlay flotante). Falsos positivos descartados: + carousel/grid-list/tree-view (bg de item) · color-picker/date-range-picker (contenido dentro de un + popover, que ya tiene el plano). +- **select+combobox a plano-constante** (decisión del usuario): el variant tiñe solo el + trigger/control, ya NO la elevación del popup (se quitaron los overrides outline=raised / + ghost=transparent). Los 3 variants comparten la misma elevación overlay. +- **Regresión propia** (pusheada en f80f2225, arreglada en 009f5367): menubar reusa + `[data-dropdown-menu-content]` → el prune del dropdown lo dejó sin elevación; arreglado estampando + `data-depth` en su wrapper eidos. Lección: al podar un selector/recipe compartido, grepear los + reusadores. +- **Fila "Superficie / elevación" de §13 → `LIVE ✓`** + **lint anti-deriva** `elevation-plane.test.ts` + (cada `Content` de overlay debe estampar `data-depth`; tooltip/listbox excluidos por diseño). + +**Siguiente:** A2 (radio: `--radius-default`=sm + factor Radix + responder a `--scaling`) → A3 (estado +hover/active + foco unificado). + +--- + ## ESTADO DE IMPLEMENTACIÓN — hand-off 2026-06-20 **Hecho hoy (sobre el A1 de ayer):** @@ -779,7 +808,7 @@ cada una — no son faltas per-componente, son los arquetipos que faltan): | eje | canon — QUÉ consumir | NO hacer (deriva) | estado | |---|---|---|---| -| **Superficie / elevación** | `data-depth='overlay'\|'modal'\|…` → **bundle completo** (surface·shadow·halo·border·blur·z) | `surface-raised`/`-default` a dedo; `--{c}-overlay-z` propio; frost arbitrario | **A1** | +| **Superficie / elevación** | `data-depth='overlay'\|'modal'\|…` → **bundle completo** (surface·shadow·halo·border·blur·z) | `surface-raised`/`-default` a dedo; `--{c}-overlay-z` propio; frost arbitrario | **LIVE ✓** (B2, 2026-06-22; guard `elevation-plane.test.ts`) | | **Radio** | `--radius-default`(=sm) / factor global + `[data-shape-nest]` concéntrico | `calc(--radius-md − space)` a mano; px fijo | **A2** | | **Estado (hover/active)** | `--state-{variant}-hover/active` (ghost = state-layer `currentColor`) | `color-mix` ad-hoc; 9 familias sueltas | **A3** | | **Foco** | `--focus-ring-*` + `--focus-ring-surface` + `outline` (HCM-safe); intent vía `data-intent` | tokens de foco propios; box-shadow que muere en HCM | **A3** | diff --git a/src/uix/eidos/elevation-plane.test.ts b/src/uix/eidos/elevation-plane.test.ts new file mode 100644 index 000000000..5b7aa5a92 --- /dev/null +++ b/src/uix/eidos/elevation-plane.test.ts @@ -0,0 +1,57 @@ +import { describe, it, expect } from 'vitest'; +import { existsSync, readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const COMPONENTS = join(dirname(fileURLToPath(import.meta.url)), 'components'); + +/** + * Anti-drift guard for the elevation plane. + * + * ARCHETYPE_COHERENCE_AUDIT §13, axis "Superficie / elevación" → LIVE (B2 rollout, + * 2026-06-22). Every FLOATING OVERLAY takes its elevation (surface · border · + * shadow · halo) from the `data-depth` plane — it does NOT paint its own + * surface/shadow. So each overlay's eidos `Content` wrapper MUST stamp + * `data-depth` for the plane to apply. + * + * This catches the menubar-class regression: a panel that reuses another part's + * content selector (`[data-dropdown-menu-content]`) but forgets `data-depth` + * silently loses its elevation the moment the donor recipe is pruned. + * + * EXCLUDED by design (NOT plane targets — see §13 / the 2026-06-22 hand-off): + * tooltip — the variant IS the material (solid / outline / ghost), not emphasis; + * the plane would flatten it. + * listbox — an inline list (`surface-default`, no shadow), not a floating overlay. + */ +const OVERLAY_CONTENT_WRAPPERS: Record = { + 'dropdown-menu': ['dropdown-menu-content.svelte', 'dropdown-menu-sub-content.svelte'], + 'context-menu': ['context-menu-content.svelte', 'context-menu-sub-content.svelte'], + menubar: ['menubar-content.svelte'], + 'navigation-menu': ['navigation-menu-content.svelte'], + popover: ['popover-content.svelte'], + 'link-preview': ['link-preview-content.svelte'], + command: ['command.svelte'], + select: ['select-content.svelte'], + combobox: ['combobox-content.svelte'], + dialog: ['dialog-content.svelte'], + drawer: ['drawer-content.svelte'] +}; + +describe('elevation plane adoption (B2 anti-drift guard)', () => { + for (const [component, files] of Object.entries(OVERLAY_CONTENT_WRAPPERS)) { + for (const file of files) { + it(`${component} · ${file} stamps data-depth (consumes the elevation plane)`, () => { + const path = join(COMPONENTS, component, file); + expect( + existsSync(path), + `${file} not found — wrapper renamed? Update OVERLAY_CONTENT_WRAPPERS.` + ).toBe(true); + const src = readFileSync(path, 'utf8'); + expect( + /data-depth=/.test(src), + `${file} must stamp data-depth="overlay|modal" so the elevation plane paints the panel.` + ).toBe(true); + }); + } + } +});