# 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** — `` contiene las parts que tú compongas (``, ``, ``). 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** | | `` + `` | **hecho** | | Propagar `kind` a `date-range-picker` (ambos endpoints filtran segments) | **hecho** | | `` + `` (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 `` / `kind='year'`. No vale la pena duplicar superficie cuando un prop captura la variante. | | `MonthPicker` / `YearPicker` (single) | **descartar** — idem, `` / `kind='year'`. | | Promover `` / `` a componentes independientes `` / `` 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. | ## 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. | ## 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'} {:else if 'month'} {:else} {/if}`). Las views son partes propias: ``, ``, equivalentes en `DateRangePicker`. Implicación: **no hay** componentes separados `MonthPicker`, `YearPicker`, `MonthRangePicker`, `YearRangePicker`. Esos casos son `` / ``. ### 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 `` dentro de ``. Si no lo compones, no aparece. Si no quieres footer entero, omites ``. 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.