# Continue Fecha de corte: 2026-05-19. Rama: `active-uix`. ## Guia vigente: migracion de componentes Soma -> Eidos Objetivo: migrar componentes uno a uno desde Soma a Eidos sin crear una API inferior a Air ni a las librerias de referencia, y sin romper fronteras de capa. Esta es la guia que debe leerse antes de tocar cualquier componente. ### Flujo obligatorio por componente 1. Leer Air en la rama anterior: `git show morfo-runtime:src/uix/air/components/{name}/...` cuando exista. Air es la primera baseline visual local. 2. Leer Morfo/Soma actuales del componente: - `src/uix/morfo/components/{name}.ts` - `src/uix/soma/components/{name}/...` - README y tests de Soma si existen. 3. Auditar Morfo/Sema antes de tocar Eidos: - Clasificar el componente como pasivo, interactivo o mixto. - Justificar explicitamente cualquier `0 events`. No se acepta por omision. - Para cada accion de usuario real definir si debe existir evento semantico: `family`, `verb`, `sequence`, `intent`, `target`, `prewrite` y `commit`. - Verificar que Soma usa `runtime.trigger(...)` para esas acciones, no solo callbacks locales (`onValueChange`, `onValueCommit`, etc.). - No emitir eventos continuos por cada frame/pixel si el evento semantico es el inicio, el commit o un cambio discreto. 4. Comparar con referentes externos oficiales relevantes: Radix/Radix Themes, Ark UI, Bits UI, shadcn-svelte, React Aria, Base UI, Vaul u otros solo si aplican al componente. 5. Crear o actualizar `src/uix/eidos/components/{name}/README.md` antes de cerrar el componente. Debe incluir: - baseline Air, - tabla Soma/Morfo, - tabla Morfo/Sema con eventos, targets y decisiones, - tabla comparativa externa, - decisiones explicitas, - gaps con decision: implementar, diferir a Soma/Morfo, diferir a v2 o descartar por no pertenecer a Eidos. 6. Solo despues tocar wrapper, recipe, tokens o contrato. ### Fronteras de capa - Morfo declara partes, `data-*`, ARIA, eventos y translations. - Soma posee comportamiento, estado, teclado, foco, formularios, portal, floating, timers, imagenes, validacion y escrituras DOM headless via `ActiveDom`. - Sema/events posee ocurrencias perceptivas; no decide CSS ni tokens. - Eidos posee wrapper visual, props visuales, recipe CSS, tokens y documentacion visual. - Morfo no se da por correcto por existir: cada componente nuevo o revisado debe auditar si sus `events` representan bien la capa semantica. Componentes pasivos como `progress`/`meter` pueden tener `0 events`; componentes interactivos como `slider`, `pagination`, `rating-group`, `number-field` o `search-field` requieren decision semantica explicita. - Si una funcionalidad nueva necesita estado, ARIA, DOM imperative o lifecycle, no se mete en Eidos: se define primero en Morfo/Soma. - Si una parte publica aparece en Eidos, debe estar respaldada por Morfo/Soma salvo que sea puramente visual y se documente como excepcion deliberada. ### API Eidos canonica - Opcion C: root visual + partes attached en el namespace: `import { Component } from '$uix/eidos/components/component'`. - Sin `Provider` publico en Eidos. - Sin APIs flat con snippets como alternativa paralela. - Sin alias duplicados para compatibilidad: no hay compatibilidad hacia atras. - Un solo entry mental por componente. No crear dos ficheros root para lo mismo. - El root vive en `{name}.svelte`; partes en `{name}-{part}.svelte`. - `index.ts` exporta named namespace y default del mismo namespace. - Para single-part, el default/root es el componente completo y no se inventan partes vacias. - Dentro de wrappers Eidos, las partes de Soma se importan como namespace con el nombre real del componente: `import * as Collapsible from '$soma/components/collapsible'`, y se usan como ``, ``, etc. - Prohibido en wrappers Eidos: `Parts`, `Base`, `SomaXxxProvider`, tags sueltas ``/``/`` y cualquier alias `Root`. ### Naming y contratos - No prefijar tipos con `Eidos` dentro del modulo del componente: usar `FieldProps`, `FieldSize`, `FieldVariant`, etc. - No usar nombres legacy `danger/success/warning/info`; el sistema usa intents canonicos cuando aplica. - No usar `--eidos-*`, `--soma-*`, `data-soma-*` ni marcadores privados de otra capa en CSS Eidos. - Los `data-*` publicos deben venir de Morfo o de props visuales Eidos documentadas (`data-size`, `data-variant`, `data-color`, etc.). - Si el CSS necesita un selector nuevo de estado/comportamiento, primero mirar si debe declararse en Morfo/Soma. - Los sizes son canonicos y responsive mediante `ResponsiveProp` + `ActiveEidos.resolve(...)`. No inventar escalas locales sin razon. - Las props visuales comunes deben mantenerse pequenas: normalmente `size`, `variant`, `color`, `radius`, `orientation` solo cuando el componente lo justifica. ### CSS y tokens - Cada componente tiene `components/{name}/{name}.css` e import explicito en `src/uix/eidos/index.css`. - Los valores authorables viven en `THEME_BASE_RECIPE_TOKENS` y se publican en `src/uix/eidos/generated/base.css` mediante `npm run generate:eidos-css`. - No introducir colores raw, `font-size` literal en px/rem ni magic numbers si deben ser tokens. - El CSS de componente consume `var(--{component}-...)`; los valores salen del config generado. - No tocar `web/routes` ni demos salvo orden explicita. ### Decisions fijadas durante esta tanda - `Popover.side="auto"` se descarta. Soma Floating usa `side` como preferencia (`top/right/bottom/left`) y `avoidCollisions`/flip/shift resuelven el ajuste. - `Field.RequiredIndicator` se define en Morfo/Soma antes de Eidos porque tiene contrato publico y `aria-hidden`; Eidos solo renderiza el `*` por defecto. - Air `Field.Error` se migra como `Field.ErrorText`, alineado con Soma/Morfo y Ark UI. No se crea alias `Error`. - Los comportamientos compartidos de imagen deben modelarse como `ImageProvider`/provider headless reutilizable en Soma, no como helper suelto en Eidos ni dentro de `layers`. - Los tipos/utilidades de color compartidos pertenecen a `src/libs/color` si tambien los consumen SIUM u otras capas; Soma no debe ser la libreria de colores transversal. - `Switch` conserva `Switch.Thumb` como parte publica, pero el root de Eidos monta un thumb visual por defecto cuando no recibe children. Motivo: `` es el uso minimo documentado en la demo y no puede renderizar un track vacio. No es una API flat paralela: el compound sigue siendo la forma avanzada para sustituir el thumb o sus iconos. ### Verificacion minima antes de cerrar un componente - Regenerar CSS si se tocan recipe tokens: `npm run generate:eidos-css`. - Ejecutar tests focales del componente Soma si se toca Morfo/Soma. - Ejecutar: - `node --import tsx/esm scripts/eidos-lint-all.ts` - `npm run check` - Ejecutar vitest focal: `npx vitest run src/uix/eidos src/uix/morfo/compile.test.ts src/uix/morfo/schema.test.ts` y anadir tests Soma concretos si hubo cambios de comportamiento. - `npm run lint` no es fiable como validacion global ahora mismo: el repo tiene deuda de formato previa y snippets legacy no parseables. Formatear solo los archivos tocados con `npx prettier --write ...`. ### Estado actual de la tanda Eidos - Ultimo componente corregido/verificado: `FileUpload` demo. - Correccion/demo 2026-05-19: - Anadio ruta `web/routes/uix/components/file-upload/+page.svelte` siguiendo `web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md`. - La demo incluye tabs `Live`, `API`, `Morfo`, `Sema`, `Recipe`, `A11y`, traza por `MutationObserver`, botones Play de Sema y pasos `data-perm-step` para `remove -> clear`. - No se instrumenta el boton que abre el picker nativo porque bloquearia las pruebas automaticas; el evento `trigger-picker` queda cubierto en el tab Sema mediante Play. - `web/routes/uix/+layout@.svelte` registra `fileUploadSema` y anade la entrada de navegacion `File upload`. - Bug real corregido en `Eidos FileUpload`: el root ahora declara `files = $bindable([])` y reenvia `bind:files` a Soma. - Bug real corregido en `Eidos FileUpload.Item`: el snippet argumentado ya no usa `children` como nombre local; usa `bodyContent`. - Bug real corregido en `Eidos FileUpload.ItemName` e `ItemSize`: si el consumidor no pasa children, el wrapper ya no inyecta un snippet vacio que anulaba el fallback de Soma (`file.name` y `formatBytes(file.size)`). - Bug de contrato corregido en `Morfo FileUpload`: `ItemPreview.data-type` pasa a ser opcional porque la prop `type` de Soma es un filtro opcional y no se emite cuando no se usa. - Validado despues de `FileUpload` demo: - `npm run check` -> 0 errores, 0 warnings. - `SMOKE_SCOPE=/uix/components/file-upload npm run smoke` -> ruta OK. - `npm run morfo:check` -> `file-upload` PASS; 29 rutas validadas, 38/67 morfos sin demo. - `npm run perm:check` -> `file-upload` PASS; baseline elimina y limpia; disabled queda pasivo; 17 demos instrumentadas OK. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> `file-upload` invalid 0. Persisten solo hotspots conocidos de `progress`/`meter` por `data-shape='circular'`. - Navegador integrado: ruta carga sin errores de consola, monta root, dropzone, trigger, list, dos items, dos progress bars, seis tabs y Sema muestra cinco botones Play. - Todos los componentes presentes hoy en `src/uix/eidos/components` salvo `svg` tienen ruta demo en `web/routes/uix/components`. - Ultimo componente corregido/verificado antes de esta demo: `TagsInput` demo. - Correccion/demo 2026-05-19: - Anadio ruta `web/routes/uix/components/tags-input/+page.svelte` siguiendo `web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md`. - La demo incluye tabs `Live`, `API`, `Morfo`, `Sema`, `Recipe`, `A11y`, traza por `MutationObserver`, botones Play de Sema y pasos `data-perm-step` para `type delimiter -> remove -> clear`. - `web/routes/uix/+layout@.svelte` registra `tagsInputSema` y anade la entrada de navegacion `Tags input`. - Bug real corregido en `Eidos TagsInput`: el root ahora declara `value = $bindable([])` e `inputValue = $bindable('')`, reenviando ambos estados bindables a Soma. - Validado despues de `TagsInput` demo: - `npm run check` -> 0 errores, 0 warnings. - `SMOKE_SCOPE=/uix/components/tags-input npm run smoke` -> ruta OK. - `npm run morfo:check` -> `tags-input` PASS; 28 rutas validadas, 39/67 morfos sin demo. - `npm run perm:check` -> `tags-input` PASS; baseline e invalid escriben, eliminan y limpian; disabled/readonly quedan pasivos; 16 demos instrumentadas OK. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> `tags-input` invalid 0. - Navegador integrado: tags visibles, input presente, Sema con cuatro eventos y sin errores de consola. - Ultimo componente corregido/verificado antes de esta demo: `Editable` demo. - Correccion/demo 2026-05-19: - Correccion/demo 2026-05-19: - Anadio ruta `web/routes/uix/components/editable/+page.svelte` siguiendo `web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md`. - La demo incluye tabs `Live`, `API`, `Morfo`, `Sema`, `Recipe`, `A11y`, traza por `MutationObserver`, botones Play de Sema y pasos `data-perm-step` para `Edit -> type draft -> Save`. - `web/routes/uix/+layout@.svelte` registra `editableSema` y anade la entrada de navegacion `Editable`. - Bug real corregido en `Eidos Editable`: el root ahora declara `value = $bindable('')` y `editing = $bindable(false)`, reenviando ambos estados bindables a Soma. - Bug real corregido en `Eidos Editable.Preview`: si el consumidor no pasa children, el wrapper ya no inyecta un snippet vacio que anulaba el fallback `state.displayValue` de Soma. - Correccion posterior de arquitectura: `Editable` no debe parecer un `Field/Input` permanente. La baseline real de la rama anterior esta en `src/uix/terra/editable` (no en Air components) y plantea contenido inline editable. - `Morfo/Soma Editable` anade `Control` para agrupar acciones. Los triggers ya no fuerzan `hidden`; Soma expone `data-editing`, `data-disabled` y `data-readonly`, y Eidos decide visualmente si muestra `Edit` o `Save/Cancel`. - La receta Eidos de `Editable` vuelve a preview inline: caja sutil solo en hover/focus o al entrar en edicion. Si se quiere una caja permanente debe usarse `Field`/`Input`. - Validado despues de `Editable` demo: - `npm run check` -> 0 errores, 0 warnings. - `SMOKE_SCOPE=/uix/components/editable npm run smoke` -> ruta OK. - `npm run morfo:check` -> `editable` PASS; 27 rutas validadas, 40/67 morfos sin demo. - `npm run perm:check` -> `editable` PASS; baseline edita, escribe y guarda; disabled/readonly quedan pasivos; 15 demos instrumentadas OK. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> `editable` invalid 0. - Navegador integrado: preview muestra el valor inicial, input oculto en preview y sin errores de consola. - Ultimo componente corregido/verificado antes de esta demo: `Stepper` demo. - Correccion/demo 2026-05-19: - Correccion/demo 2026-05-19: - Anadio ruta `web/routes/uix/components/stepper/+page.svelte` siguiendo `web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md`. - La demo incluye tabs `Live`, `API`, `Morfo`, `Sema`, `Recipe`, `A11y`, traza por `MutationObserver`, botones Play de Sema y pasos `data-perm-step` que avanzan hasta `commit-complete`. - `web/routes/uix/+layout@.svelte` registra `stepperSema` y anade la entrada de navegacion `Stepper`. - Bug real corregido en `Eidos Stepper`: el root ahora declara `value = $bindable(0)` y reenvia `bind:value` a Soma, tal como prometia su API documentada. - Bug real corregido en `Eidos Stepper.Item` y `Stepper.Indicator`: los snippets argumentados `{ state }` ya no usan `children` como nombre local, evitando la recursividad/`undefined is not a function` vista en SSR. - Validado despues de `Stepper` demo: - `npm run check` -> 0 errores, 0 warnings. - `SMOKE_SCOPE=/uix/components/stepper npm run smoke` -> ruta OK. - `npm run morfo:check` -> `stepper` PASS; 26 rutas validadas, 41/67 morfos sin demo. - `npm run perm:check` -> `stepper` PASS; baseline, RTL y vertical avanzan los tres pasos hasta completar; 14 demos instrumentadas OK. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> `stepper` invalid 0. - Navegador integrado: ruta carga sin errores de consola, seis tabs y Sema muestra dos eventos con Play. - Ultimo componente corregido/verificado antes de esta demo: `TagGroup` demo. - Correccion/demo 2026-05-19: - Anadio ruta `web/routes/uix/components/tag-group/+page.svelte` siguiendo `web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md`. - La demo incluye tabs `Live`, `API`, `Morfo`, `Sema`, `Recipe`, `A11y`, traza por `MutationObserver`, botones Play de Sema y pasos `data-perm-step` para seleccionar y eliminar un tag. - `web/routes/uix/+layout@.svelte` registra `tagGroupSema` en el shell de docs y anade la entrada de navegacion `Tag group`. - Bug real corregido en `Eidos TagGroup`: el root ahora declara `value = $bindable([])` y reenvia `bind:value` a Soma, tal como prometia su API documentada. - Bug real corregido en `Eidos TagGroup.Item`: el snippet argumentado ya no usa `children` como nombre local; usa `bodyContent` para evitar la recursividad/`undefined is not a function` vista en SSR. - Validado despues de `TagGroup` demo: - `npm run check` -> 0 errores, 0 warnings. - `SMOKE_SCOPE=/uix/components/tag-group npm run smoke` -> ruta OK. - `npm run morfo:check` -> `tag-group` PASS; 25 rutas validadas, 42/67 morfos sin demo. - `npm run perm:check` -> `tag-group` PASS; baseline selecciona y elimina, variante disabled queda pasiva; 13 demos instrumentadas OK. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> `tag-group` invalid 0. - Navegador integrado: ruta carga sin errores de consola, seis tabs, Sema muestra cuatro eventos y Recipe lista selectors morfo/eidos esperados. - Ultimo componente corregido/verificado antes de esta demo: `Switch`. - Correccion 2026-05-19: - `Soma SwitchThumb` expone `{ checked }` al snippet del thumb. - `Eidos Switch` monta `SwitchThumb` por defecto si el root no recibe children. - `Eidos SwitchThumb` pinta `SvgCheck` por defecto cuando `checked=true`. - Bug corregido: recursividad accidental de snippets en `switch-thumb.svelte`, que provocaba `500` en `/uix/components/switch`. - Token anadido: `--switch-thumb-icon-color`, publicado desde `THEME_BASE_RECIPE_TOKENS` y regenerado en `generated/base.css`. - Validado despues de la correccion de `Switch`: - `npx vitest run src/uix/soma/components/switch/switch-provider.svelte.test.ts src/uix/eidos/component-visual-attrs.test.ts src/uix/eidos/recipe-css-contract.test.ts` -> 3 archivos, 12 tests OK. - `npm run check` -> 0 errores, 0 warnings. - Navegador `/uix/components/switch`: status 200; el switch monta thumb, cambia a `checked` y renderiza `svg[data-svg="check"]` dentro del thumb. - Ultimo componente cerrado antes de esta correccion: `Field`. - `Field` anadido en Eidos con `Label`, `RequiredIndicator`, `Control`, `Input`, `HelperText`, `ErrorText`, `Prefix` y `Suffix`. - `RequiredIndicator` anadido a Morfo/Soma y cubierto por test del provider. - Validado despues de `Field`: - `npx vitest run src/uix/soma/components/field/field-provider.svelte.test.ts src/uix/morfo/compile.test.ts src/uix/morfo/schema.test.ts src/uix/eidos` -> 11 archivos, 129 tests OK. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid. - `npm run check` -> 0 errores, 0 warnings. - Siguiente componente recomendado: iniciar la tabla previa de uno de los componentes grandes aun no migrados a Eidos (`select`, `combobox`, `calendar`, `date-field`, `date-picker`, `date-range-picker`, `time-field`, `time-picker`). Antes de tocar codigo, comparar Air si existe, Soma/Morfo y referencias externas, y decidir gaps reales. ### Archivos temporales - No commitear logs temporales: `.codex-vite-*.log`, `.codex-vite-*.err.log`, `.codex-taggroup-dev.*.log`, `debug.log`, `md`. ## Corte para continuar manana - Rama `active-uix` queda con la tanda Soma -> Eidos commitada por fases. - No se tocaron demos ni rutas; el trabajo fue en `src/uix/eidos/components`, `src/uix/eidos/lib/recipes/base.ts`, `src/uix/eidos/index.css`, CSS generado y documentacion. - Validacion de la ultima tanda: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Regla nueva para continuar Eidos componente por componente: - La primera referencia es Air en la rama anterior (`morfo-runtime:src/uix/air/components/{name}`) cuando exista. - Despues se compara con Soma/Morfo actuales y con referentes externos relevantes (Radix/Radix Themes, Ark UI, Bits UI, shadcn-svelte y React Aria si aplica). - Cada componente Eidos debe tener tabla en `components/{name}/README.md` con gaps y decisiones antes de tocar wrapper/recipe/tokens. - Objetivo: no dejar Eidos por debajo de Air ni de las plataformas de referencia en funcionalidades reales. - Primer componente auditado con el nuevo protocolo: - `Dialog`: comparado contra Air, Radix, Ark UI, Bits UI y shadcn-svelte. - Decision: no se crea `Dialog.Positioner`; `Content.position` cubre esa responsabilidad visual sobre la grid canonica 3x3. - Decision: se anaden overrides visuales `width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight` en `Dialog.Content`, serializados como variables privadas del recipe. Soma sigue siendo dueno de comportamiento. - Segundo componente auditado con el nuevo protocolo: - `Drawer`: comparado contra Air (`morfo-runtime`), Soma/Morfo actuales, Vaul, shadcn-svelte y Ark UI Dialog como referencia de dialog/layer. - Decision: no se crea `Drawer.Positioner`; la geometria edge-anchored vive en `data-side` + `data-variant` y en la receta. - Decision: no se implementa `shouldScaleBackground` de Vaul en Drawer local; es un efecto global sobre el wrapper de app y requiere contrato de shell. - Decision: se anaden overrides visuales `width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight` en `Drawer.Content`, serializados como variables privadas del recipe. El size canonico `sm/md/lg/full` sigue como preset principal. - Tercer componente auditado con el nuevo protocolo: - `Popover`: Air no tenia equivalente en `morfo-runtime`, por tanto la referencia local pasa a ser Soma/Morfo y la comparativa externa Radix, Ark UI, Bits UI y shadcn-svelte. - Decision: no se crea `Popover.Positioner`; la posicion pertenece a Soma Floating y Eidos solo consume `data-side`, `data-align` y variables CSS. - Decision: no se crean `Popover.Title`/`Description` hasta que exista caso real; Popover suele contener UI arbitraria y el etiquetado puede vivir en contenido consumidor. - Decision: se anaden `matchAnchorWidth`, `width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight` en `Popover.Content`, serializados como variables privadas. La receta usa transform-origin y available-height de Soma Floating. - Cuarto componente auditado con el nuevo protocolo: - `Tooltip`: Air no tenia equivalente en `morfo-runtime`; referencia local Soma/Morfo, comparativa externa Radix, Ark UI, Bits UI y shadcn-svelte. - Decision: no se crea `Tooltip.Positioner` ni `Tooltip.ArrowTip`; Soma Floating y Soma Arrow son los duenos de esa geometria. - Decision: se anaden `matchAnchorWidth`, `width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight` en `Tooltip.Content`, serializados como variables privadas. La receta usa transform-origin y available-height de Soma Floating. - Decision: se alinea Soma con Radix/Bits: el tooltip cierra al activar/clicar el trigger por defecto. `disableCloseOnTriggerClick` queda como escape hatch en `Tooltip.Group` y `Tooltip`. - Componentes Eidos nuevos desde Soma: - `meter` - `progress` - `slider` - `pagination` - `rating-group` - `search-field` - `number-field` - `breadcrumb` - Siguiente decision antes de seguir migrando: - Continuar con componentes de riesgo bajo/medio (`field`, `toolbar`, `tag-group`) o parar a definir una tabla de migracion por componente para los grandes (`select`, `combobox`, `calendar`, `date-field`). - Para cada componente nuevo conviene escribir primero: partes Soma, props visuales Eidos, `data-*` que estampa el wrapper, tokens de recipe y attrs morfo-backed que consumira el CSS. Actualizacion Eidos component migration 2026-05-17: - Inicio de la migracion Soma -> Eidos siguiendo `soma/COMPONENT_GUIDE.md` y `eidos/components/README.md`. - Componentes migrados: - `Progress`: root visual `progress.svelte`, `Progress.Indicator`, `progress.css`, `types.ts` e `index.ts` con disciplined option C. - `Meter`: root visual `meter.svelte`, `Meter.Indicator`, `meter.css`, `types.ts` e `index.ts` con disciplined option C. - Decisiones aplicadas: - Eidos no crea comportamiento: ambos wrappers envuelven `Provider` e `Indicator` publicos de Soma. - La unica prop visual anadida es `size?: ResponsiveProp<'sm' | 'md' | 'lg'>`, resuelta con `ActiveEidos.resolve(...)` y proyectada como `data-size`. - `Progress` usa el `data-state` de Soma (`indeterminate`, `loading`, `loaded`) para cargar/terminar/indeterminado. - `Meter` usa el `data-state` de Soma (`below`, `optimum`, `above`) para zonas visuales; no se anade intent ni color en Eidos. - Los tokens base viven en `THEME_BASE_RECIPE_TOKENS` y se regenero `src/uix/eidos/generated/base.css`. - Guardias actualizadas: - `component-visual-attrs.test.ts` protege `data-size` en `Progress` y `Meter`. - `scripts/eidos-lint-all.ts` reconoce `data-floating-wrapper` como marcador publico actual y retira el sufijo legacy `flat`. - `components/README.md` refleja `meter` y `progress` como migrados. - Validado: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Segunda tanda del mismo bloque: - `Slider`: root visual `slider.svelte`, partes `Range`, `Thumb`, `Tick`, `slider.css`, `types.ts` e `index.ts` con disciplined option C. - La receta usa las posiciones inline calculadas por Soma y solo define track, range, thumb, ticks, foco, disabled y size visual. - `component-visual-attrs.test.ts`, `components/README.md`, `THEME_BASE_RECIPE_TOKENS`, `index.css` y `generated/base.css` quedan actualizados. - Validado despues de `Slider`: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Tercera tanda del mismo bloque: - `Pagination`: root visual `pagination.svelte`, partes `PrevTrigger`, `NextTrigger`, `Item`, `Ellipsis`, `pagination.css`, `types.ts` e `index.ts`. - El root conserva el snippet de Soma con `{ pages, totalPages }` y solo anade `size` visual resuelto por `ActiveEidos`. - La receta cubre controles, estado selected, disabled, ellipsis y focus. - Validado despues de `Pagination`: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Cuarta tanda del mismo bloque: - `RatingGroup`: root visual `rating-group.svelte`, parte `Item`, `rating-group.css`, `types.ts` e `index.ts`. - No se inventa icono/star por defecto ni API nueva; el wrapper conserva los snippets de Soma (`items` en root y `state` en item) y la receta estiliza `active`, `partial`, `inactive`, foco, vertical/horizontal y disabled. - Validado despues de `RatingGroup`: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Quinta tanda del mismo bloque: - `SearchField`: root visual `search-field.svelte`, partes `Input`, `ClearTrigger`, `search-field.css`, `types.ts` e `index.ts`. - El wrapper conserva el snippet de Soma (`value`, `isEmpty`, `isFocused`, `clear`) y solo anade `size`. - La receta cubre contenedor, input, clear trigger, focused, invalid, empty y disabled. - Validado despues de `SearchField`: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Sexta tanda del mismo bloque: - `NumberField`: root visual `number-field.svelte`, partes `Input`, `IncrementTrigger`, `DecrementTrigger`, `Scrubber`, `number-field.css`, `types.ts` e `index.ts`. - El wrapper conserva formato/parseo/spinbutton/scrub de Soma y solo anade `size`. - La receta cubre contenedor, input, triggers, scrubber, focused, scrubbing, invalid y disabled. - Validado despues de `NumberField`: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Septima tanda del mismo bloque: - `Breadcrumb`: root visual `breadcrumb.svelte`, partes `List`, `Item`, `Link`, `Separator`, `Ellipsis`, `breadcrumb.css`, `types.ts` e `index.ts`. - El wrapper conserva semantica, current item/link, ellipsis interactivo y ARIA de Soma; Eidos solo anade `size`. - La receta consume `data-current` y `data-interactive` declarados por Morfo y define tokens para gaps, tipografia, links, separador, ellipsis, foco y transiciones. - Validado despues de `Breadcrumb`: - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK. - `npm run check` -> 0 errores, 0 warnings. - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift hotspots. - Siguiente bloque sugerido: - Migrar otro grupo de bajo riesgo desde Soma a Eidos: candidatos reales por morfo/soma existentes son `field`, `toolbar` o `tag-group`. - Antes de tocar componentes grandes (`select`, `combobox`, `calendar`, `date-field`) conviene fijar una tabla por componente: partes Soma, props visuales Eidos, recipe tokens y attrs esperados. Actualizacion Eidos components audit 2026-05-17: - Se acometieron los hallazgos autorizados sobre `src/uix/eidos/components` sin tocar demos ni rutas `web/routes/uix`: - `Tabs` instala su contexto visual de forma sincronica durante init, no en `$effect`; los hijos `Tabs.Content` ya no pueden inicializar sin contexto. - `Tabs.Indicator` deja de observarse a si mismo con `ResizeObserver`, para evitar loops de medida provocados por sus propias escrituras inline. - `Avatar.Image` ya no arranca oculto cuando hay `src`; la visibilidad queda derivada de `src` y de la ultima URL fallida. - `Accordion.Trigger` ya no contiene `