docs(components): final lote 6 — the LAST five dossiers; full matrix GREEN (134/0/0)

color-swatch (the S7 passive exemplar gains its Baseline/Comparativa — the
primitive extracted in the ColorPicker redesign; React Aria is the only
headless ref shipping it) · onion-menu (nobody ships a headless radial menu;
Menu Button semantics + depth-tinted drill rings as the differentials; the
English "## Decisions" heading renamed to the canonical "## Decisiones") ·
radio-cards (the S11c delegation exemplar: reuses RadioGroup soma wholesale —
zero duplicated behaviour; multi-select variant DISCARDED, CardGroup+
ToggleGroup own cardinality per the 2026-06-27 decision) · scroll-frames
(+ the missing Passive justification: the frame is a pure function of scroll
progress — the gesture belongs to the page) · timeline (the two-axes
differential documented: data-status drives marker geometry, data-intent
drives valence — decoupled, unlike Ant/MUI/Flowbite; apg declared in C5
none-rationale form; the two 1em literals annotated — they inherit the
item-scaled font, the trf-separator precedent).

Machine: 129 -> **134 PASS / 0 NEEDS-WORK / 0 BROKEN** — the audit
programme runs the full catalogue green. contracts 37/37 · vocab exit 0 ·
type baseline 57.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
menubar-v4-safe
dev 3 months ago
parent 5f55c5dcc1
commit 7f2bcc2801

@ -63,3 +63,41 @@ control) when the colour conveys meaning.
`src/uix/morfo/components/color-swatch.ts` — single part, `scope: ['eidos']`,
passive (no events). Eidos-native, no soma (pure visual, like `Kbd` / `Icon`).
## Baseline
Sin baseline air: el primitivo se EXTRAJO durante el rediseño Untitled-UI de
ColorPicker (2026-06-28) para matar los chips ad-hoc — la muestra canónica de
color, reutilizada por `ColorPicker` / `ColorField` (preview del valor,
presets, dot del trigger). La única referencia headless que lo publica como
primitivo es React Aria (`ColorSwatch`).
## Comparativa
| Capacidad | UIX | React Aria ColorSwatch | Chakra/Radix | Chips ad-hoc |
| --- | --- | --- | --- | --- |
| Primitivo dedicado reutilizable | ✓ | ✓ | No | — |
| Checker de transparencia bajo alfa | ✓ | ✓ | — | Raro |
| Escala de tallas + `rounded`/`full` | ✓ | CSS externo | — | — |
| Ring inset (legibilidad sobre claros) | ✓ | No | — | No |
| Pasivo por contrato (0 eventos) | ✓ | ✓ | — | — |
## Decisiones
- **Una sola muestra canónica** (doctrina compose-first): cualquier color que
el sistema enseñe pasa por ColorSwatch — nunca un `<div>` con background
inline (los consumidores del picker lo prueban).
- **El checker es parte del primitivo**, no del consumidor: un color con alfa
SIEMPRE se lee contra el damero.
- **Ring inset sutil** para que una muestra clara no se funda con la
superficie clara — legibilidad, no decoración.
- **Pasivo por contrato** (S7, átomo ejemplar): mostrar un color no tiene
momento perceptivo propio; la interacción (elegir, copiar) pertenece al
consumidor que lo compone.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| Nombre accesible del color (aria-label con naming, "azul cielo") | **diferir** | Requiere lib de color-naming; hoy el consumidor pasa el label cuando el contexto lo pide. |
| Conciencia de roles de paleta (pintar `--color-primary-solid` por nombre) | **descartar** | El swatch enseña VALORES; los roles se resuelven antes (eidos.resolveToken). |

@ -98,7 +98,7 @@ elevation (`--shadow-raised` sectors, `--shadow-overlay` trigger — single-laye
drop straight into `drop-shadow()`), the label / icon typography, and the `+`→`×`
trigger glyph. All colours come through tokens; no raw hex in the recipe.
## Decisions
## Decisiones
- **Compositional, not data-driven** — parts register a node tree; the root paints. An
option's children nest *inside* the option (`DropdownMenu.Sub` shape).
@ -109,3 +109,32 @@ trigger glyph. All colours come through tokens; no raw hex in the recipe.
nav maths) the root drives, rather than a compound provider tree.
- **Focus on open transition, not mount** — a controlled `open=true` at mount does not
steal focus; user/programmatic open transitions move focus into the ring.
## Baseline
Sin baseline air y sin análogo headless publicado: ningún ecosistema
(Radix/Ark/Bits/React Aria) publica un menú radial. Las referencias del
patrón son los pie/radial menus de herramientas (Blender, juegos, marking
menus de Autodesk) — todos mouse-only y ninguno con drill de anillos
concéntricos temado por profundidad. Semánticamente ES un Menu Button por
APG (el morfo lo cita): trigger `aria-haspopup` → `role="menu"` de
`menuitem`s; la geometría radial y el color por profundidad salen de los
engines del framework.
## Comparativa
| Capacidad | UIX | Pie menus (Blender/juegos) | Marking menus | Radix/Ark/RAC |
| --- | --- | --- | --- | --- |
| Menú radial con drill concéntrico | ✓ | Anillo único | Jerárquico gestual | No publicado |
| Tema por rama + tintes por profundidad + trail muted | ✓ | No | No | — |
| Semántica Menu Button (haspopup/menu/menuitem) | ✓ | No (canvas) | No | — |
| Navegación radial por teclado | ✓ | No | No | — |
| Carácter perceptivo (pack radial S3b) | ✓ | — | — | — |
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| Gestos marking-menu (trazo rápido sin esperar el render) | **diferir** | El patrón experto de Autodesk; espera caso real. |
| Virtualización de anillos con muchas opciones | **descartar** | Un anillo con >12 opciones es un problema de diseño del consumidor, no del componente. |
| Touch: objetivo de 44px en arcos finos | **diferir** | Auditar los arcos bajo `pointer: coarse` cuando el censo touch llegue a los radiales. |

@ -102,3 +102,40 @@ The interactive contract (Provider/Item, events, keyboard, a11y) lives in
soma, no new sema (`commit-select` fires from RadioGroup's runtime + pack).
This mirrors `toggle-group ↔ toggle` and `css-field ↔ spin-field`: share the
machinery, layer a distinct visual.
## Baseline
El patrón visual es el **Radio Cards de Radix Themes** (tarjetas
single-select con contenido rico); Ark/Bits no lo publican y shadcn lo
compone a mano. La diferencia arquitectural de UIX está en la cabecera de
este README: **cero comportamiento duplicado** — RadioCards reusa el soma de
`RadioGroup` entero (selección, roving, `role=radio`, HiddenInput de form) y
solo añade la presentación de tarjeta.
## Comparativa
| Capacidad | UIX | Radix Themes | shadcn (manual) | Ark/Bits |
| --- | --- | --- | --- | --- |
| Tarjetas single-select con contenido rico | ✓ | ✓ | Compuesto a mano | No publicado |
| Reusa el soma del RadioGroup (cero duplicación) | **✓** | (interno) | No (re-cablea) | — |
| Radio de esquina siempre visible | ✓ | Opcional | Variable | — |
| Form participation (HiddenInput) | ✓ | ✓ | Manual | — |
| Roving + teclado del grupo | ✓ | ✓ | Depende | — |
## Decisiones
- **Delegación como arquitectura** (la cita canónica del veredicto S11c vive
en el header del morfo): RadioCards no declara eventos propios — el
`commit-select` del RadioGroup compuesto ES su semántica; el morfo solo
aporta la identidad de tarjeta.
- **El radio de esquina SIEMPRE presente**: la tarjeta entera es clicable,
pero el affordance de "esto es un radio" no se negocia (a11y + escaneo).
- **Contenido libre en la tarjeta** (icon · title · description como
children): la presentación no impone estructura de datos.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| Variante multi-select de tarjetas | **descartar** | Ya resuelto en otro sitio: `CardGroup` + `ToggleGroup` poseen la cardinalidad (decisión 2026-06-27). |
| Tarjetas con imagen de cabecera | **diferir** | Componible hoy (children); slot dedicado espera caso real. |

@ -76,3 +76,46 @@ selector is morfo-backed; no eidos-only, intent or variant selectors.
surrounding page, not the canvas/video.
- Scroll-linked: the user controls pace directly, so it never auto-animates. For a
reduced-motion path, render a single representative frame.
## Passive justification
Superficie display eidos-only de 0 eventos: el frame mostrado es una FUNCIÓN
PURA del progreso de scroll (0→1) — el gesto de scroll pertenece a la página,
no al componente (no hay superficie interactiva propia, ni foco, ni teclado).
Mismo criterio contract-level que SText / Image: observación, no acto.
## Baseline
El patrón es el scrollytelling de secuencia de imágenes estilo Apple
(AirPods/producto): canvas pegajoso + track alto + scrub por progreso. Las
referencias del campo son librerías JS (scrolly-video, GSAP ScrollTrigger) —
ninguna integrada a un sistema de tokens/disciplina DOM; la sección
"Adapted to the framework" de arriba documenta la adaptación.
## Comparativa
| Capacidad | UIX | scrolly-video | GSAP ScrollTrigger | Ad-hoc |
| --- | --- | --- | --- | --- |
| Modo frames (canvas, cover-fit, HiDPI) | ✓ | No (solo video) | Manual | Variable |
| Modo video con easing (`smooth`) | ✓ | ✓ | Manual | — |
| Track alto + viewport sticky integrados | ✓ | ✓ | Manual | — |
| Disciplina del framework (ActiveDom/tokens) | ✓ | — | — | — |
| Dependencia externa | Ninguna | Dependencia | Dependencia | — |
## Decisiones
- **Dos modos mutuamente excluyentes** (`frames` XOR `video`): mezclar ambos
en una API única invitaría a estados imposibles.
- **Frame = función pura del progreso**: sin estado interno de reproducción —
scrubbing determinista, resistente a saltos de scroll.
- **Canvas con cover-fit HiDPI** para el modo frames: nitidez a cualquier DPR
sin CLS.
- **`smooth` solo en video**: el easing del `currentTime` evita el stutter
del seek frame-a-frame; los frames de canvas no lo necesitan.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| Carga perezosa/progresiva de la secuencia de frames | **diferir** | Hoy el consumidor pasa las URLs; un prefetch por ventana de progreso espera caso real. |
| Eventos sema de scrub | **descartar** | Display pasivo por contrato; sonorizar el scroll de la página sería ruido (misma razón que link-preview). |

@ -92,3 +92,42 @@ Tokens: `src/uix/eidos/lib/recipes/base.ts` (`timeline`). Selectors:
- `R-1.5 exception:` no focusable part of its own — items are display (`item` / `title` / `description`); anything focusable inside is consumer content that brings its own treatment.
- `A-1.4 exception:` the APG defines no timeline pattern; the component is a display list — anything interactive inside is consumer content with its own contract.
## Baseline
Sin baseline air. Referencias del patrón: Ant Design Timeline, MUI Lab
Timeline y Flowbite — todos con UN eje de color (el estado tiñe). El
diferencial UIX es la sección "Two color axes" de arriba: **estado**
(`data-status` done/current/upcoming — la forma/relleno del marker) e
**intent** (`data-intent` — la valencia del evento) DESACOPLADOS, más el
feed vivo (`emerge-reveal` en soma) que ninguna de las referencias modela.
## Comparativa
| Capacidad | UIX | Ant Timeline | MUI Lab | Flowbite |
| --- | --- | --- | --- | --- |
| Ejes estado × intent desacoplados | **✓** | No (un color) | No | No |
| Feed vivo con revelado perceptivo (`emerge-reveal` + pack) | ✓ | No | No | No |
| Orientación + layout alternado | ✓ | ✓ | ✓ | Parcial |
| Markers/rail/connector como partes themables | ✓ | Parcial | ✓ | CSS |
| Iconos por evento | ✓ | ✓ | ✓ | ✓ |
## Decisiones
- **Dos ejes, dos vocabularios**: `data-status` gobierna la GEOMETRÍA del
marker (hecho/actual/futuro) y `data-intent` la VALENCIA (los tokens
intent→color del sistema) — un evento "fallo" pasado pinta rojo sin fingir
que no ocurrió. Es la doctrina data-color≠intent aplicada a un display.
- **El modelo de estado vive en soma** (derivación de `active`, el feed y
`emerge-reveal`) — este layer solo pinta rail/markers/connectors.
- **Tipografía del item en `1em` anotado** (`literal:`): título y descripción
heredan la fuente escalada del item (reset del UA size del heading), no
imponen tamaño propio.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| Agrupación por fecha (cabeceras de día/mes) | **diferir** | Componible por el consumidor; slot dedicado espera caso real. |
| Colapso de tramos largos ("ver 12 más") | **diferir** | Idem — composición con Collapsible cubre hoy. |
| Zoom temporal (escala proporcional al tiempo) | **descartar** | Eso es un chart (eje temporal real) — pertenece a `$libs/plots`, no al display secuencial. |

@ -434,7 +434,7 @@
[data-timeline-title] {
margin: 0;
font-size: 1em;
font-size: 1em; /* literal: inherits the item's size-scaled font (resets the heading UA size) */
font-weight: var(--timeline-title-font-weight);
color: var(--timeline-title-color);
line-height: var(--timeline-line-height);
@ -442,7 +442,7 @@
[data-timeline-description] {
margin: 0;
font-size: 1em;
font-size: 1em; /* literal: inherits the item's size-scaled font */
color: var(--timeline-description-color);
line-height: var(--timeline-line-height);
}

@ -37,6 +37,7 @@ export const timelineMorfo = {
name: 'Timeline',
kebab: 'timeline',
scope: ['soma', 'sema', 'eidos'],
apg: 'none — chronological display list with no APG pattern; interactive content inside items (links, actions) carries its own patterns (checkpoint C5 form)',
expression: 'pack',
texts: {
label: '#?components.timeline.label|Timeline'

Loading…
Cancel
Save

Powered by TurnKey Linux.