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/src/uix/PENDIENTES.md

17 KiB

Pendientes UIX

Backlog vivo. Cada entrada lleva una disposición: implementar / diferir / descartar. Mantener priorizado por capa afectada y dependencias.

Pickers — estado consolidado 2026-05-21

El bloque de trabajo sobre date-picker y date-range-picker cerró en una pasada larga el mismo día. El contrato canónico es:

  • mode: 'inline' | 'modal' — modal bloquea outside-click + Escape.
  • kind: 'date' | 'month' | 'year' (Chakra-style) — controla segments del input + view del popover. Derivación vive en el DateFieldProvider (soma), no en el snippet del consumer.
  • Footer = composición pura — <Picker.Footer> contiene las parts que tú compongas (<Clear/>, <Cancel/>, <Close/>). Sin clearButton/cancelButton/closeButton props en root.
  • Provider helpers: commit() / cancel() (revierte al snapshot capturado en el OPEN edge vía watch(open)) / clear().
Item Disposición
Aplicar mode + Footer a date-picker (single) hecho
Aplicar kind (Chakra date/month/year) a date-picker hecho
<DatePicker.YearView> + <DatePicker.MonthView> hecho
Propagar kind a date-range-picker (ambos endpoints filtran segments) hecho
<DateRangePicker.YearView> + <DateRangePicker.MonthView> (range state machine: start → end → reset, swap automático) hecho
Promover Footer/Clear/Cancel/Close a parts canónicos Eidos (ambos pickers) hecho
Drop clearButton/cancelButton/closeButton root props → composición pura hecho
Morfo date-picker + date-range-picker: declarar parts Footer/Clear/Cancel/Close + arquetipo footer añadido al vocabulario hecho
MonthRangePicker / YearRangePicker como componentes nuevos descartar — cubierto por <DateRangePicker kind='month'> / kind='year'. No vale la pena duplicar superficie cuando un prop captura la variante.
MonthPicker / YearPicker (single) descartar — idem, <DatePicker kind='month'> / kind='year'.
Promover <DatePicker.YearView> / <DatePicker.MonthView> a componentes independientes <YearCalendar> / <MonthCalendar> con demos aislados diferir — actualmente acoplados al DatePickerProvider. Independizarlos requiere refactor del context-lookup. Mantener acoplados hasta que aparezca un caso de uso real fuera del picker.
Propagar el patrón modal+Footer a time-picker, time-range-picker, color-picker, combobox, select, popover cuando proceda implementar — decidir por componente; muchos no necesitan footer.
Tests browser del flujo completo (Playwright): inline/modal, kind chip, range state machine, snapshot/cancel, click-outside, Escape implementar — alta cobertura para flujos que ahora dependen de state machine.
Sema event al bloquear click cuando mode='modal' diferir — útil para screen reader feedback. No bloquea.

Soma / Popover — bloqueo detectado durante Words

Item Disposición
Auditar Popover como componente propio antes de usarlo para Words.ToolPopover implementar — el trigger emite present en la traza, pero el estado open no queda reflejado de forma fiable en DOM y Content puede no montarse. En la demo de Words, abrir el editor de link desde el BubbleMenu produce TypeError: Cannot read properties of undefined (reading 'wrapperProps') en src/uix/soma/components/popover/popover-provider.svelte.ts. No es una adaptación específica de Words; es deuda de Soma/Popover y debe resolverse con su propia demo, tests y audit visual.
Revisar Portal sólo si la auditoría de Popover lo confirma diferir — no modificar internal/Portal como efecto lateral de Words; aislar primero si el fallo está en trigger/provider/presence/portal.
Añadir test browser o harness Svelte para click real de Popover.Trigger → Content visible implementar — los tests unitarios del provider no cubren el flujo renderizado con Trigger, Portal, Content, bind:open y atributos morfo en DOM.

Tooltip (warnings pendientes del audit)

Item Disposición
A-3.6 evento open/close sin variante {verb}-X o {family}-X diferir — disclosure puro, el naming actual es semánticamente válido.
D-4.3 demo no emite uix.events.emit(...) para wirear Play buttons implementar cuando se haga la próxima pasada de demos.

Eidos theming — limpieza diferida

Item Disposición
20 tokens de color muertos (rol tertiary completo + {intent}-active × 8 + fulfill-hover/loss-hover/loss-element) en themes/base.ts + generated/base.css diferir — no rompen nada. Validar que tertiary no es un hook futuro reservado antes de borrarlo.
Afinar valores de los tokens xs/xl extrapolados durante el batch de tamaños diferir — la extrapolación proporcional (xs ≈ 75% de sm, xl ≈ 125% de lg) puede no proporcionarse bien en componentes concretos; revisar visualmente y reajustar caso por caso.
Range view-cell: differentiate visualmente start/end vs in-range (actualmente todos se ven solid primary) — pendiente afinar tinte de data-in-range para que sea más sutil que start/end implementar cuando se haga el browser-walk del range-picker.

Audit one-by-one (post-sesión)

Prioridad media

  • dialog (verificar visual)

Prioridad baja — sólo si aparece síntoma visual

Lista barrida en el audit script (component:audit 67/67 PASS). Cuando aparezca un disparate visual, se walka el componente con browser y se remedia. No se hace barrido proactivo de nada que ya esté PASS.

Audit infra

Item Disposición
Audit A-3.6 falla con eventos open/close válidos de emerge diferir — el regex pide {verb}-X pero muchos verbs son legítimos solos. Refinar regex para aceptar verbs canónicos.
Audit no verifica que el demo cierre el popover al hacer click-outside (cuando aplica) diferir — verificación visual queda al browser-walk.
Translations check: añadir warning cuando un componente declara texts.label pero su catálogo no tiene label implementar — pequeño, evita drift.
Audit R-2.6 — var(--color-X) referenciado sin estar declarado en generated/base.css hecho (scripts/component-audit.ts). Set declarado se calcula al inicio desde generated/base.css; cada componente CSS se chequea contra él.
Audit D-7.4 — el array de chips de cada control (size, variant, color) enumera el tipo completo declarado en types.ts hecho (scripts/component-audit.ts). Parsea {PascalName}{Prop} exacto, resuelve alias canónicos (ControlVariant, SelectionVariant, ChipVariant, MarkerVariant, TabsVariant, ColorRole+narrowings) vía SHARED_VARIANT_VOCAB.
Nuevo: audit que verifique que ninguna Part Eidos consulta provider.opts.{boolean}Button.current (composición pura) diferir — chequeo defensivo, low value.

Web · performance del docs site

Diagnóstico (2026-05-24): el usuario reporta carga lenta + Chrome marca [Violation] 'setTimeout' handler took 78ms. Profiling identifica 4 cuellos de botella reales, ordenados por impacto. Como UIX está en fase de desarrollo del framework, todos quedan como diferir hasta entrar en pasada de polish; documentados aquí para no perder el rastro.

Item Disposición
CSS layout 744 KB render-blocking: src/uix/eidos/index.css @import-ea 70+ recipes + generated/base.css (213 KB) — total 944 KB. Cada /uix/* descarga + parsea todo antes del first paint, la mayoría para componentes que la página no usa. diferir — fix arquitectónico: dejar foundation global (~250 KB: base.css + archetypes.css + events.css) y mover cada recipe XComponent.css a un import dentro del .svelte correspondiente para que Vite lo code-splittee con el JS. Esto requiere migrar la convención del foundation eidos.
ActiveEidos.create({ applyDom: true }) re-genera todo en runtime: apply() (src/uix/eidos/active-eidos.svelte.ts:361-389) corre renderStaticCss() + renderThemeCss() sincrónicamente, itera THEME_BASE_RECIPE_TOKENS (2.884 líneas) + color×scale×role×alpha (>1k declaraciones), inyecta 3 <style> tags con textContent = css. Es la causa más probable de la violación setTimeout 78ms (el $effect envolvente se programa vía la cola que Chrome reporta como setTimeout). Además duplica el CSS bundleado vía import '@/uix/eidos/index.css'. diferir + investigar trade-off — fix conservador (1 línea): applyDom: false en web/routes/uix/+layout@.svelte:302 y depender del CSS bundleado. Pero hay que confirmar primero si runtime theme switching depende de la inyección (theme editors live). Si depende, la solución es hacer apply() lazy: cachear el render por themeId y solo inyectar overrides cuando setCssVariables() se llame.
28 sema modules + 71 lang files eagerly imported en el layout: web/routes/uix/+layout@.svelte:10-38 (sema) + src/uix/langs/components/index.ts (langs). Añade ~30 KB al chunk del layout, bloquea tree-shaking, cada /uix/* registra todos aunque el usuario no abra esos componentes. diferir — fix arquitectónico: registración lazy por componente. Cada componente al montar registra su propio sema/langs pack en lugar de el central en boot. Requiere API nueva (uix.events.registerPack/uix.langs.lazy) + refactor del patrón de boot.
Sidebar con 100+ links data-sveltekit-preload-{code,data}="hover": web/routes/uix/+layout@.svelte:746-769. Mover el cursor por el rail dispara fetches masivos. Las rutas docs son prerenderizadas — el preload-data no aporta nada. diferir — fix barato (5 líneas): quitar data-sveltekit-preload-data de los links del rail; cambiar data-sveltekit-preload-code="hover" a viewport para que precargue al entrar en pantalla, no al hover. Mantener hover en topbar/brand.

Cuándo abordarlo: cuando la lib entre en pasada de optimización pre-release. El orden de ataque sugerido es el inverso del coste: quitar preload-data del rail (10 minutos, ganancia inmediata) → fijar applyDom: false con cache lazy (medio día, gana 50-80ms) → split CSS por componente (1-2 días, gana el grueso del transfer) → sema/langs lazy registration (sprint propio).

Doc debt

Item Disposición
READMEs/architecture docs siguen citando morfo.translations en muchos .md diferir — el código está migrado a texts, los docs lagging. Sweep separado.
src/uix/COMPONENT_COMPLETION_CHECKLIST.md actualizado con C-2.6 + D-7.4 + D-7.5 hecho
src/uix/eidos/README.md + web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md actualizados con N-6 (kind) + N-7 (composition) hecho

Normas implantadas

Resumen accionable de las decisiones adoptadas. Forman parte del contrato del componente y están reflejadas en los .md doctrinales.

N-1 · Cobertura de tamaños

Cada componente expone los valores de Size que su recipe declara. El sistema admite xxs · xs · sm · md · lg · xl · xxl · full. La elección por categoría:

Categoría Sizes Componentes afectados
Form controls táctiles xs · sm · md · lg · xl checkbox, switch, toggle, radio-group, rating-group, slider
Inputs de texto xs · sm · md · lg · xl search-field, number-field, date-field, editable, tags-input, combobox, select
Progress/meter (barra escalable) xs · sm · md · lg · xl progress, meter
Field / Form (layout) xs · sm · md · lg · xl field, form
Nav controls xs · sm · md · lg breadcrumb, pagination, tag-group, toolbar
Sin cambio (paneles compuestos donde sm/md/lg cubre) sm · md · lg calendar, date-picker, date-range-picker, file-upload, stepper, tooltip
Ya en rango ampliado xs · sm · md · lg · xl[+full] avatar, dialog, drawer, popover, tabs, icon

N-2 · Paridad de chips en demos

Toda variante / tamaño / color declarado en el tipo del componente debe aparecer como chip seleccionable en el demo. Las Extract<…> arbitrarias que truncaban la unión están eliminadas (field, toolbar ahora exponen los 3 valores de ControlVariant). Enforced por audit D-7.4.

N-3 · Tokens del contrato deben estar declarados

Cualquier var(--color-X) referenciado en recipes o en *.css debe estar declarado en generated/base.css. La sesión añadió content.muted y surface.muted al contrato y corrigió el typo --color-neutral-element-hover en form.css. Enforced por audit R-2.6.

N-4 · No raw colors en CSS de Eidos

hex / rgb / hsl / named están prohibidos en src/uix/eidos/**/*.css y en recipes/base.ts. Todo color va por color-mix(in srgb, var(--color-X) N%, transparent) o por token directo. Corregidos archetypes.css y events.css (eidos-commit-settle indigo → primary-solid).

N-5 · Scrollbars portaled

Las reglas ::-webkit-scrollbar* viven sin scope en web/routes/uix/uix.css para alcanzar overlays portaleados (Combobox listbox, Popover content, Dialog, Drawer). --uix-line está duplicado en :root + override en :root[data-mode='dark'] (atributo escrito por ActiveEidos.apply()).

N-6 · Picker kind = single source for input + view

Para los pickers, kind: 'date' | 'month' | 'year' (Chakra-style) es el único punto de configuración para variantes de granularidad. Drives:

  1. Segments del input: filtrado a nivel del DateFieldProvider (soma). El consumer renderiza segments tal cual viene — no filtra en el snippet. kind='year' → YYYY, kind='month' → MM/YYYY, kind='date' → MM/DD/YYYY. Literales colapsados automáticamente.
  2. View del popover: el consumer hace branching estructural ({#if kind === 'year'} <YearView/> {:else if 'month'} <MonthView/> {:else} <Calendar/> {/if}). Las views son partes propias: <DatePicker.YearView>, <DatePicker.MonthView>, equivalentes en DateRangePicker.

Implicación: no hay componentes separados MonthPicker, YearPicker, MonthRangePicker, YearRangePicker. Esos casos son <DatePicker kind='X'> / <DateRangePicker kind='X'>.

N-7 · Composición sobre props para visibilidad de parts

Las parts opcionales (Footer, Clear, Cancel, Close, etc.) NO exponen props *Button booleanos en el root del componente. La visibilidad se controla por composición: si quieres Clear, compones <X.Clear/> dentro de <X.Footer/>. Si no lo compones, no aparece. Si no quieres footer entero, omites <X.Footer/>.

Las parts renderizan siempre que se monten — sin checks internos contra props del provider. Esto se aplica a derivados: el patrón escala a cualquier componente con sub-parts opcionales (Header, Footer, ToolbarItem, etc.).

Demos: las parts se envuelven en {#if showX} con state local del demo para dar el control UI, pero las parts en sí no leen ese state.

N-8 · Reutilizar componentes ya definidos en componentes complejos

Cuando un componente complejo (picker, combobox, color-picker, etc.) necesita un sub-control que ya existe como componente independiente (Slider, Popover, Calendar, Field, etc.), debe componerlo en vez de reimplementarlo. Sólo se justifica un fork si reusarlo causaría una pérdida de características concreta y demostrable.

Beneficios:

  1. Una sola fuente de eventos sema. El sub-control emite sus eventos canónicos (slider:handle-pick, slider:commit-set, popover:close-dismiss, etc.) que el composite hereda automáticamente — sin reimplementar la dimensión perceptiva.
  2. Una sola implementación de pointer/keyboard/ARIA. Bugs corregidos en el componente raíz se propagan a todos los composites que lo usan. Sin duplicación de drag, focus trap, etc.
  3. Tokens del recipe unificados. --slider-track-size, --popover-content-padding, etc. se setean en un único recipe; todos los composites consumen los mismos.
  4. Superficie pública estable. La API del composite (parts + eventos) se reduce a su lógica diferenciadora; el resto cae del sub-control.

Caso aplicado 2026-05-21: ColorPicker.ChannelSlider deja de tener su propio ColorPickerChannelSliderProvider con pointer handlers duplicados; ahora compone SliderProvider por debajo. Channel-aware behavior queda en una sola función bridge (setChannel + gradient inline en --cp-channel-gradient). Resultado: −200 líneas en soma, eventos slider:handle-pick/drag/commit-set propagados, tokens unificados con time-picker / standalone Slider.

Segundo caso 2026-05-21 — PickerShell. El Footer + Clear/Cancel/ Close de los pickers eran cuatro archivos .svelte casi idénticos por picker (date-picker, time-picker, color-picker). Extracción a:

  • src/uix/soma/components/picker-shell/ — pickerShellContext + PickerShellHandle interface (getMode / commit / cancel / clear).
  • src/uix/eidos/components/picker-shell/ — parts compartidos <PickerShell.Footer/Clear/Cancel/Close> que leen el handle.
  • src/uix/eidos/components/picker-shell/picker-shell.css — CSS canónica [data-picker-footer/clear/cancel/close].

Cada provider registra su handle en el context via pickerShellContext.set(this.pickerShellHandle). El namespace de cada picker eidos re-exporta X.Footer/Clear/Cancel/Close apuntando a los componentes compartidos — la API pública no cambia. Aplicado al ColorPicker en este commit. Migración pendiente para date-picker y time-picker (issue separado).

Powered by TurnKey Linux.