Full walk of combobox (popover + editable input + listbox):
- Morfo: validated. 10 parts (Provider/Input/Trigger/Content/Viewport/
Item/Group/GroupHeading/Separator/Arrow). Single + multiple via
`data-type` on Provider, `aria-multiselectable` conditional on
`prop:multiple`. Item declares `data-state` checked/unchecked,
`data-value`, `data-highlighted`, `data-disabled`. Keyboard: 6 keys
but only 2 mutate state (Enter→select, Escape→close-delegated).
- Decision documented: combobox does NOT emit emerge events for
open/close/typing/filtering/highlighting — these are navigation
mechanics, not commits. Escape close is delegated to the popover
layer's `close-dismiss` event. The 2 `commit-*` events cover the
actual user intent (choosing an item).
- `texts.label` added with catalog entry. The toggle key already
existed.
Audit script refinements:
- Extended focus-move action list to cover listbox/menu/tablist
navigation (`next-item`, `prev-item`, `first-item`, `last-item`,
`next-tab`, `prev-tab`, `first-tab`, `last-tab`) plus the popover/
dialog actions that are delegated to the containing overlay layer
(`open`, `close`, `dismiss`, `toggle`). A combobox / select / menu
that hosts Escape→close is not under-declared if the overlay layer
owns the sema event.
README rewritten with canonical sections:
- `## Baseline` summarizing air + soma + morfo coverage.
- `## Comparativa` (was `## Comparison`) — table preserved.
- `## Decisiones` documenting the no-emerge-events policy, focus-only
keys, Control composition rationale, multi-select aria propagation.
- `## Gaps` (was `## Out of scope`) rewritten with disposition tokens
(implementar / diferir / descartar) per row. ClearTrigger and
Validation state get `implementar`; Modal+footer gets `descartar`
(combobox is inline by design, not a confirm-style picker).
Audit: PASS 6 → 7. No regressions; the relaxed focus-move list
benefits other listbox/menu components too (will surface on their
audits).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Opening, closing, typing, filtering and highlighting are navigation mechanics,
Opening, closing, typing, filtering and highlighting are navigation mechanics,
not committed choices. They do not emit Sema events.
not committed choices. They do not emit Sema events.
## Out of scope (v2 roadmap)
## Decisiones
- `ClearTrigger`: Ark and React Aria expose clear behavior. Deferred to Soma
- **No se emiten eventos sema en open/close/typing/filter/highlight**. Son
because it mutates `value` and `inputValue`. Estimated cost: 80-140 lines
mecánicas de navegación, no compromisos del usuario. El sema sólo viaja
across Morfo/Soma/Eidos.
con `commit-select` y `commit-unselect` (la elección concreta).
- `ScrollUpButton` / `ScrollDownButton`: Air and Bits expose them. Deferred
- **Las teclas de navegación interna de la listbox son focus moves**:
to Soma because the part needs scroll behavior and viewport awareness.
ArrowDown/ArrowUp/Home/End mueven el highlight, no mutan el valor. El
Estimated cost: 120-180 lines.
audit las cuenta como focus-only — el único keystroke que mutea es
- `ContentStatic`: Air exposes a non-floating content variant. Deferred to
Enter (mapped a `select` → covered por `commit-select`).
Soma because it changes topology and dismissal behavior. Estimated cost:
- **Escape delega al popover**: la tecla cierra cerrando la layer
80-140 lines.
popover/dismissal; combobox no duplica el evento `close-dismiss` que ya
- `menuTrigger`, `autoHighlight`, `inlineAutocomplete`: Ark and React Aria
emite el popover.
cover these input behaviors. Deferred to Soma because they affect open,
- **`Combobox.Control` es composición Eidos-only**: agrupa Input + Trigger
highlighted and input value state. Estimated cost: 180-260 lines.
+ Indicator dentro de un único chrome. No tiene contraparte en
- Custom/freeform value: React Aria supports custom values. Deferred to
morfo/soma porque es puramente layout visual.
Soma/Form because it changes value semantics and submitted form value.
- **`ItemIndicator` es Eidos-only**: el estado del item llega vía
Estimated cost: 140-220 lines.
`data-state` que el provider sopla; ItemIndicator sólo decide qué
- Validation state: Ark and React Aria expose validation. Deferred to
glyph pintar en función de ese atributo.
Field/Soma so Combobox consumes real field state instead of visual-only
- **Single vs multiple lo decide el consumer via prop `type`**: el morfo
invalid selectors. Estimated cost: 120-200 lines.
expone `data-type` en Provider para que la receta pueda diferenciar.
- Async/virtualized collections: Ark and React Aria cover this class of
- **Multi-select aria-multiselectable** se aplica condicionalmente
behavior. Deferred to the collection/virtualization layer, not Eidos.
cuando `prop:multiple` es truthy.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| `ClearTrigger` (Ark, React Aria) | **implementar** | Mutates `value` + `inputValue`. Estimación 80-140 LOC across Morfo/Soma/Eidos. Útil para todos los pickers con field input. |
| Custom / freeform value (react-aria) | **diferir** | Cambia value semantics + form value submitted. 140-220 LOC. |
| Validation state | **implementar** | Combobox debe consumir field state real cuando esté dentro de un `<Field>`. 120-200 LOC. Bloqueante para integración Form. |
| Async / virtualized collections | **descartar** | Belongs in collection/virtualization layer, no Eidos. Out of scope. |
| Modal mode + footer pattern (como pickers) | **descartar** | Combobox es inline por diseño — no es un picker con confirmación explícita. |