From b1b1e39dc0fd4f9dfe0dea654b9f7eff4b33ac8a Mon Sep 17 00:00:00 2001 From: dev Date: Sat, 23 May 2026 22:14:44 +0200 Subject: [PATCH] fix(carousel): chevron direction follows orientation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vertical carousel still rendered horizontal chevrons (< / >) for the prev / next triggers, which read as wrong-direction even though the click handlers worked correctly. The user complaint "varios clicks" was the visual mismatch making each click look like it did nothing — value WAS advancing index 0→1→2 on each click but the icons pointed sideways in a vertical rail. - Added `orientation` to the eidos carousel context so the prev / next trigger wrappers can pick the right chevron without passing props. - Re-exported `Direction` + `Orientation` from soma's carousel module so the eidos context can type-check them. - Prev trigger now uses `direction='up'` in vertical, `'left'` in horizontal. Next trigger mirrors with `'down'` / `'right'`. Verified: index goes 0→1→2 on successive clicks; chevrons now show `^` (top) and `v` (bottom) in vertical orientation. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/uix/eidos/codex_audit.md | 388 ++++++++++++++++++ .../components/carousel/carousel-context.ts | 6 +- .../carousel/carousel-next-trigger.svelte | 4 +- .../carousel/carousel-prev-trigger.svelte | 4 +- .../eidos/components/carousel/carousel.svelte | 5 + src/uix/soma/components/carousel/exports.ts | 2 + 6 files changed, 405 insertions(+), 4 deletions(-) create mode 100644 src/uix/eidos/codex_audit.md diff --git a/src/uix/eidos/codex_audit.md b/src/uix/eidos/codex_audit.md new file mode 100644 index 000000000..217cdbce6 --- /dev/null +++ b/src/uix/eidos/codex_audit.md @@ -0,0 +1,388 @@ +# Auditoria Codex de Eidos / UIX demos + +Fecha: 2026-05-23 +Rama auditada: `active-uix` +Ambito principal: `src/uix/eidos/components/*` y demos publicas en +`web/routes/uix/components/*` + +## Resumen ejecutivo + +El ecosistema Eidos/UIX ya tiene una base visual y documental amplia: todas las +83 demos publicas bajo `web/routes/uix/components` cargan, renderizan `canvas`, +`stage` y seis tabs de documentacion; no se detectaron errores de consola en la +pasada Playwright de escritorio. Tambien hay coherencia visual general: stage +comun, trace strip, controles agrupados, tokens Eidos, props visuales +homogeneas y un patron compound bastante estable. + +Pero el resultado no puede considerarse cerrado. La auditoria automatica del +repo marca 12 componentes como `NEEDS-WORK`, hay demos que incumplen el contrato +obligatorio de snippets, existen gaps de Sema/playback en componentes +interactivos y el shell `/uix` no es usable en viewport movil: todas las rutas +auditadas desbordan horizontalmente a 390px por un problema del marco de docs. + +El area de mayor riesgo sigue siendo la familia de pickers/calendarios. Han +mejorado respecto a los fallos anteriores: hay controles visibles para +min/max, minDays/maxDays, modal/inline, footer por composicion, clear/cancel/close +y numberOfMonths. Aun asi, DatePicker, DateRangePicker, Tooltip, MonthGrid y +YearGrid no cumplen del todo el contrato de playback Sema/demo y necesitan tests +funcionales especificos para apertura, seleccion, cierre, limites y navegacion. + +## Evidencia usada + +Comandos y recorridos ejecutados: + +- `npm run component:audit` +- Recorrido Playwright desktop `1440x1000` sobre las 83 demos publicas. +- Recorrido Playwright mobile `390x844` para detectar overflow del shell. +- Capturas del stage de todas las demos en `tmp/uix-audit/screens/*.png`. +- Hojas de contacto visuales en: + - `tmp/uix-audit/contact-sheet-1.png` + - `tmp/uix-audit/contact-sheet-2.png` + - `tmp/uix-audit/contact-sheet-3.png` +- Resumen estructural en `tmp/uix-audit/quick-summary.json`. +- Reporte canonico generado en `tmp/component-audit.md`. + +Nota: habia cambios previos en `src/uix/soma/components/carousel/*`. Esta +auditoria observa el estado actual sin revertir ni tocar esos cambios. + +## Resultado cuantitativo + +### `npm run component:audit` + +| Metrica | Resultado | +| --- | ---: | +| Componentes auditados por contrato | 92 | +| PASS | 80 | +| NEEDS-WORK | 12 | +| BROKEN | 0 | + +### Recorrido visual/funcional Playwright + +| Metrica | Resultado | +| --- | ---: | +| Demos publicas recorridas | 83 | +| Rutas con error HTTP/consola | 0 | +| Demos sin `data-uix-canvas-inner` | 0 | +| Demos sin `data-uix-stage` | 0 | +| Demos sin seis tabs declaradas | 0 | +| Overflow desktop | 0 | +| Overflow mobile | 83 | +| Demos con menos de 2 bloques de snippet en Live | 5 | + +El dato de overflow mobile es sistemico: los valores se repiten en todas las +rutas, por lo que apunta al shell `/uix` y no a un componente concreto. + +## Hallazgos P1 + +### P1.1 — 12 componentes no pasan el auditor canonico + +Estos componentes no deberian declararse cerrados: + +| Componente | Errores principales | +| --- | --- | +| `alert-dialog` | Falta selector root `[data-alert-dialog]` en recipe. | +| `button` | Verbo Sema `action` invalido, mismatch `commit.action`, falta README. | +| `carousel` | Falta README y falta `somaSnippet` en demo. | +| `command` | Falta README, no hay `:focus-visible`, falta APG, tipografia literal. | +| `grid-list` | Falta README, color raw `#fff`, falta `somaSnippet`, readonly sin estilo. | +| `link-preview` | Falta README, tipografia literal. | +| `listbox` | Falta README, readonly sin estilo, tipografia literal. | +| `menubar` | Falta README, tipografia literal. | +| `navigation-menu` | Falta README, falta `somaSnippet`, falta APG. | +| `range-calendar` | Falta README, falta `somaSnippet`, readonly sin estilo. | +| `search-field` | No hay `:focus-visible`, falta APG, readonly sin estilo. | +| `time-range-field` | Falta README, falta `somaSnippet`, readonly/invalid sin estilo. | + +Accion: cerrar primero estos 12 antes de seguir ampliando componentes. El +script ya da la lista exacta de reglas incumplidas. + +### P1.2 — El shell `/uix` no es responsive en mobile + +En viewport `390x844`, todas las demos desbordan horizontalmente. El overflow +detectado es practicamente constante (`+495` a `+529px`), lo que indica un +problema del layout documental: rail/sidebar/canvas con anchura minima fija o +grid no colapsado. + +Impacto: + +- No se puede auditar mobile por componente con fiabilidad. +- Los overlays, popovers y pickers quedan condicionados por un marco que ya + esta roto. +- La web de docs no cumple un minimo de consumo movil. + +Accion: + +- Revisar `web/routes/uix/+layout@.svelte` y `web/routes/uix/uix.css`. +- Definir breakpoint real para ocultar/convertir sidebar en drawer. +- Asegurar que `data-uix-canvas-inner`, tabs, stage y tablas no fuerzan + `min-width` por encima del viewport. +- Repetir auditoria mobile tras corregir el shell. + +### P1.3 — Demos con contrato Live incompleto: falta `somaSnippet` + +El contrato de `DEMO_AUTHORING_GUIDE.md` exige snippets Soma y Eidos en Live. +Faltan en: + +- `carousel` +- `grid-list` +- `navigation-menu` +- `range-calendar` +- `time-range-field` + +Impacto: + +- La demo no enseña el contrato headless real. +- El consumidor ve la capa Eidos pero no la composicion Soma equivalente. +- Rompe la promesa de separacion por capas del ecosistema. + +Accion: añadir `somaSnippet` reactivo y comprobar que refleja los controles +visibles del stage. + +### P1.4 — Gaps de Sema/playback en componentes interactivos + +Varias demos interactivas no tienen playback Sema normalizado con +`data-uix-play` o el auditor avisa que no hay `uix.events.emit(...)`. + +Casos relevantes: + +- `date-picker`: PASS con warning `D-4.3`; no hay `uix.events.emit(...)`. +- `date-range-picker`: PASS con warning `D-4.3`; no hay `uix.events.emit(...)`. +- `tooltip`: PASS con warning `D-4.3`; no hay playback claro. +- `month-grid` y `year-grid`: eventos `nav-step` no siguen la forma + `{verb}-X` o `{family}-X`; el play usa chip/boton no estandar. +- `button`: usa verbo Sema invalido `action`. +- `alert-dialog`: aparece como pasivo aunque la demo muestra acciones de + dialogo heredadas; hay que aclarar si el evento pertenece al wrapper o al + compuesto. + +Impacto: + +- El usuario no puede verificar eventos desde la tab Sema de forma uniforme. +- La documentacion vuelve ambiguo que eventos son propios, heredados o + compuestos. +- Se rompe la trazabilidad Morfo -> Soma -> Sema -> Eidos. + +Accion: + +- Normalizar todos los botones de playback a `data-uix-play`. +- Para componentes compuestos, documentar y listar eventos heredados sin decir + que la superficie es 0 si el stage permite acciones visibles. +- Corregir nombres de eventos que no respetan el vocabulario Sema. + +### P1.5 — Pickers y calendarios siguen siendo zona de alto riesgo + +Estado visual observado: + +- `calendar` renderiza uno/dos meses con heading centrado y trace funcional. +- `range-calendar` renderiza seleccion y rango, pero falla auditor por README y + `somaSnippet`. +- `date-picker` muestra field + popover + calendar + footer de acciones. +- `date-range-picker` muestra dos inputs, dos meses, footer y controles de + limites/rango. +- `time-picker` y `time-range-picker` muestran popover con sliders y footer. + +Riesgos abiertos: + +- DatePicker/DateRangePicker no tienen playback Sema normalizado. +- La apertura por trigger necesita test E2E estable; en una pasada automatizada + el selector `data-date-picker-trigger` no dejo el provider en `open`, aunque + la captura visual previa si lo muestra abierto. +- RangePicker debe tener regresiones automatizadas para: + - seleccionar start sin desplazar al mes siguiente de forma inesperada, + - seleccionar end sin auto-navegar, + - deseleccionar solo endpoint afectado, + - mantener start/end con colores diferenciados, + - respetar `minValue`, `maxValue`, `minDays`, `maxDays`, + - validar min/max invalidos y surfacing via UI/logger, + - clear sin cierre accidental, + - cancel revirtiendo snapshot de apertura, + - modal bloqueando outside click y manteniendo escape/cierre compuesto. + +Accion: crear suite Playwright especifica para `calendar`, `range-calendar`, +`date-picker`, `date-range-picker`, `time-picker` y `time-range-picker`. + +## Hallazgos P2 + +### P2.1 — Warnings de CSS/token contract + +Hay warnings que no rompen render, pero indican drift con Eidos: + +- Literales tipograficos en `command`, `link-preview`, `listbox`, `menubar`, + `code-block`, `field`, `kbd`, `combobox`, `time-range-picker`. +- Raw color en `grid-list` (`#fff`). +- Estados declarados pero no estilados: `readonly`, `invalid`, segun + componente. +- `:focus-visible` ausente en `command` y `search-field`. + +Accion: + +- Sustituir literales por tokens o justificar con comentario `/* literal: ... */`. +- Eliminar raw color. +- Estilar `readonly`/`invalid` donde Morfo los declara. +- Añadir focus ring visible a componentes interactivos. + +### P2.2 — Demos con controles presentes pero valor pedagogico desigual + +La plantilla se aplica de forma amplia, pero no siempre con el mismo nivel de +claridad: + +- Componentes complejos (`file-upload`, `stepper`, `listbox`, `grid-list`, + `range-calendar`, `date-range-picker`) quedan comprimidos en un stage pequeno. +- Algunas demos muestran mucho estado en trace, pero el stage no evidencia de + un vistazo que cambio produjo cada control. +- Los controles de segmentos en `date-range-picker` existen, pero necesitan + copy y ejemplo visual mas directo para que se entienda por que start/end + segments importan si el usuario tambien elige fechas en calendario. +- `pagedNavigation` existe como control, pero deberia acompañarse de estado + observable: mes actual antes/despues, step esperado y diferencia cuando hay + dos meses. + +Accion: + +- Para componentes compuestos, ampliar el stage o usar escenarios separados + dentro de Live. +- Añadir microestado visible cuando un control no modifica visualmente de forma + obvia el componente. +- Evitar controles que solo cambian el snippet o una prop interna sin evidencia + visual inmediata. + +### P2.3 — Componentes pasivos con 0 eventos necesitan justificacion visible + +El ecosistema ya acepta componentes pasivos, pero cada demo debe justificarlo. +Se ven casos correctos en varias paginas, pero hay que revisar que el README de +cada componente pasivo lo deje explicitamente cerrado. + +Watchlist: + +- `avatar` +- `breadcrumb` +- `field` +- `meter` +- `progress` +- `tooltip` +- `time-range-field` + +Accion: cada README debe explicar si el componente es pasivo, estructural o si +sus acciones pertenecen a otro componente compuesto. + +## Coherencia visual del ecosistema + +### Lo que esta bien + +- La shell de demo es consistente: header, meta pills, stage, trace y seis tabs. +- El lenguaje visual Eidos es reconocible: superficies limpias, bordes suaves, + tokens de color, foco morado/primary, estados discretos. +- Los componentes compound respetan en general la forma root + hijos attached. +- El trace strip ayuda a ver eventos y estado en componentes interactivos. +- La mayoria de componentes tienen controles suficientes para explorar size, + variant, color, estado y comportamiento. +- No hay rutas rotas ni errores de consola en desktop. + +### Lo que baja el nivel + +- El layout movil de docs esta roto. +- La auditoria canonica aun marca 12 componentes como no cerrados. +- Hay demos que no cumplen la plantilla obligatoria. +- Falta una politica cerrada para eventos compuestos/heredados. +- Algunos componentes grandes se ven mas como prueba tecnica que como demo + pedagogica de producto. +- La capa visual depende demasiado de que el usuario sepa interpretar trace y + controles; en varios casos el stage deberia explicar por si mismo el cambio. + +## Inventario de demos publicas auditadas + +Renderizan sin error y con stage: + +`accordion`, `alert-dialog`, `aspect-ratio`, `auto-grid`, `avatar`, `banner`, +`box`, `breadcrumb`, `button`, `calendar`, `carousel`, `checkbox`, `code`, +`code-block`, `collapsible`, `color-field`, `color-picker`, `combobox`, +`command`, `container`, `context-menu`, `date-field`, `date-picker`, +`date-range-field`, `date-range-picker`, `dialog`, `display`, `drawer`, +`dropdown-menu`, `editable`, `field`, `file-upload`, `flex`, `float`, `form`, +`grid`, `grid-list`, `group`, `heading`, `highlight`, `icon`, `kbd`, `link`, +`link-preview`, `listbox`, `mark`, `menubar`, `meter`, `month-grid`, +`navigation-menu`, `number-field`, `pagination`, `pin-input`, `popover`, +`progress`, `radio-group`, `range-calendar`, `rating-group`, `scroll-area`, +`search-field`, `section`, `select`, `separator`, `slider`, `splitter`, +`stack`, `stepper`, `switch`, `tabs`, `tag-group`, `tags-input`, `text`, +`time-field`, `time-picker`, `time-range-field`, `time-range-picker`, `toast`, +`toggle`, `toggle-group`, `toolbar`, `tooltip`, `wrap`, `year-grid`. + +## Componentes/contratos sin demo publica en `/uix/components` + +El auditor de contratos ve componentes que no tienen demo publica Eidos: + +- `announce` +- `clipboard` +- `drag-drop` +- `feed` +- `table` +- `tree-grid` +- `tree-view` +- `virtual-grid` +- `virtual-list` + +Esto puede ser correcto si son headless, internos, pendientes o no publicos, +pero debe constar explicitamente en el mapa de componentes de la web. + +Tambien existen piezas Eidos internas sin demo publica directa: + +- `_layout` +- `picker-shell` +- `svg` + +`svg` ya esta documentado como helper interno; `picker-shell` deberia quedar +marcado como interno en README/indice para evitar que parezca una omision. + +## Matriz de saneamiento recomendada + +### Fase 1 — Bloqueantes de contrato + +1. Corregir los 12 `NEEDS-WORK` del `component:audit`. +2. Añadir READMEs faltantes. +3. Añadir `somaSnippet` en las cinco demos incompletas. +4. Corregir `button` Sema verb y eventos `nav-step`. +5. Añadir `:focus-visible` en `command` y `search-field`. +6. Eliminar raw color y literales tipograficos no justificados. + +### Fase 2 — Shell de docs + +1. Hacer responsive `web/routes/uix`. +2. Repetir auditoria mobile. +3. Asegurar que tablas, snippets y stages se desplazan internamente sin romper + el viewport. + +### Fase 3 — Semantica y demos + +1. Normalizar `data-uix-play` y `uix.events.emit(...)`. +2. Documentar eventos heredados en componentes compuestos. +3. Revisar todos los componentes marcados como 0 eventos. +4. Convertir los controles no evidentes en cambios observables. + +### Fase 4 — Pickers/calendarios + +1. Tests E2E para DatePicker y DateRangePicker. +2. Tests E2E para Calendar y RangeCalendar. +3. Tests E2E para TimePicker y TimeRangePicker. +4. Casos obligatorios: uno/dos meses, modal/no-modal, min/max, minDays/maxDays, + clear, cancel, close, seleccion/deseleccion parcial, navegacion paged y + granularidad `date/month/year` o `hour/minute/second`. + +### Fase 5 — Visual QA repetible + +1. Mantener un script de capturas del stage por componente. +2. Generar hoja de contacto por batch. +3. Comparar desktop y mobile tras cada tanda. +4. No declarar cerrado un componente compuesto sin captura abierta de su + overlay/popup/menu. + +## Veredicto + +Eidos/UIX esta en una fase avanzada de cobertura, pero todavia no en una fase +cerrada de calidad. La base visual es coherente y la arquitectura por capas se +ve en las demos, pero los gaps actuales son de contrato, demo y semantica, no +solo de CSS. + +El siguiente trabajo correcto no es crear mas componentes: es cerrar los 12 +`NEEDS-WORK`, arreglar el shell mobile, normalizar Sema/playback y blindar los +pickers con pruebas visuales y funcionales especificas. diff --git a/src/uix/eidos/components/carousel/carousel-context.ts b/src/uix/eidos/components/carousel/carousel-context.ts index 2a9064fb7..09ba9a57c 100644 --- a/src/uix/eidos/components/carousel/carousel-context.ts +++ b/src/uix/eidos/components/carousel/carousel-context.ts @@ -1,15 +1,17 @@ import { getContext, setContext } from 'svelte'; import type { CarouselColor, CarouselSize, CarouselVariant } from './types'; +import type { Orientation } from '$soma/components/carousel'; /** * Eidos-only context: visual concerns shared from the Provider down to - * sub-parts (prev/next triggers consume `size`, indicators consume - * `size` + `color`). + * sub-parts (prev/next triggers consume `size` + `orientation` so their + * chevron rotates correctly; indicators consume `size` + `color`). */ export type CarouselEidosContext = { size: CarouselSize; variant: CarouselVariant; color: CarouselColor; + orientation: Orientation; }; const KEY = Symbol('eidos:carousel'); diff --git a/src/uix/eidos/components/carousel/carousel-next-trigger.svelte b/src/uix/eidos/components/carousel/carousel-next-trigger.svelte index fadfa9b51..fe77be667 100644 --- a/src/uix/eidos/components/carousel/carousel-next-trigger.svelte +++ b/src/uix/eidos/components/carousel/carousel-next-trigger.svelte @@ -24,10 +24,12 @@ const carousel = getCarouselEidosContext(); const resolvedSize = $derived(size ?? carousel?.size ?? 'md'); + // In vertical orientation `next` means "go down" — chevron mirrors. + const chevronDir = $derived(carousel?.orientation === 'vertical' ? 'down' : 'right'); {#snippet defaultIcon()} - + {/snippet} diff --git a/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte b/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte index c408e0d60..ad321858f 100644 --- a/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte +++ b/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte @@ -29,10 +29,12 @@ const carousel = getCarouselEidosContext(); const resolvedSize = $derived(size ?? carousel?.size ?? 'md'); + // In vertical orientation `prev` means "go up" — chevron mirrors. + const chevronDir = $derived(carousel?.orientation === 'vertical' ? 'up' : 'left'); {#snippet defaultIcon()} - + {/snippet} diff --git a/src/uix/eidos/components/carousel/carousel.svelte b/src/uix/eidos/components/carousel/carousel.svelte index 8e8633655..cc3b55e49 100644 --- a/src/uix/eidos/components/carousel/carousel.svelte +++ b/src/uix/eidos/components/carousel/carousel.svelte @@ -17,6 +17,7 @@ block = true, verticalBlockSize, value = $bindable(0), + orientation = 'horizontal', style, children: bodyContent, ...rest @@ -45,6 +46,9 @@ }, get color() { return color; + }, + get orientation() { + return orientation; } }); @@ -52,6 +56,7 @@