parent
2dbf471b3f
commit
3abf2686d8
@ -0,0 +1,58 @@
|
||||
---
|
||||
title: UIX — auditoría Sema de selección
|
||||
type: notes
|
||||
audience: human + agent
|
||||
authority: process — evaluación, no contrato de componente
|
||||
status: reviewed
|
||||
---
|
||||
|
||||
# Sema de Combobox, Select, Listbox y TagGroup
|
||||
|
||||
Fecha: 2026-09-23. Se releyeron las cuatro guías obligatorias de componente y
|
||||
la arquitectura Sema. El alcance autorizado por el usuario es deduplicación
|
||||
interna sin modificar comportamiento; `web/` queda excluido.
|
||||
|
||||
## Pre-flight
|
||||
|
||||
| Característica | Combobox | Select | Listbox | TagGroup | Decisión |
|
||||
| ------------------------- | --------------------------- | --------------------- | --------------------- | -------------------------------------------------------- | ------------------------------------------ |
|
||||
| Selección confirmada | `commit-select` en `item` | Igual | Igual | Igual | Compartir la construcción de la regla Sema |
|
||||
| Deselección confirmada | `commit-unselect` en `item` | Igual | Igual | Igual | Compartir la construcción de la regla Sema |
|
||||
| Firma de ambas reglas | `tap` | `tap` | `tap` | `tap` | Mantener la firma exacta |
|
||||
| Reglas adicionales | Ninguna | Ninguna | Ninguna | `commit-remove` en `item` y `commit-reset` en `provider` | Mantenerlas locales y en su orden actual |
|
||||
| Navegación, foco y estado | Propios de Soma/Morfo | Propios de Soma/Morfo | Propios de Soma/Morfo | Propios de Soma/Morfo | Fuera del cambio |
|
||||
|
||||
| Referencia oficial | Equivalente cercano | Diferencia frente a UIX | Consecuencia |
|
||||
| ------------------------------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------ | ------------------------------------------------ |
|
||||
| [WAI-ARIA APG Listbox](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/) | Selección simple o múltiple de opciones | Distingue foco y selección; no prescribe háptica | No unificar navegación con selección |
|
||||
| [Ark UI Combobox](https://ark-ui.com/docs/components/combobox) | Selección y resaltado de ítems, modo múltiple | Gestiona estado en otra arquitectura | Mantener Soma independiente |
|
||||
| [Radix Primitives Select](https://www.radix-ui.com/primitives/docs/components/select) | Ítem seleccionado y valor controlado | Select simple con composición propia | No alterar partes, props ni Morfo |
|
||||
| [Bits UI Select](https://bits-ui.com/docs/components/select) | Ítems seleccionables, opción múltiple | Implementación Svelte con contrato propio | Compartir sólo la proyección perceptiva idéntica |
|
||||
|
||||
Morfo conserva partes, eventos, ARIA y teclado; Soma conserva selección,
|
||||
deselección, foco y emisiones; Sema posee sólo estas dos reglas hápticas;
|
||||
Eidos no cambia. Los selectores se construyen con `semaSelector` y el Morfo de
|
||||
cada componente. No se añaden props, tamaños, variantes, colores, canales ni
|
||||
eventos. La extracción es privada de Sema.
|
||||
|
||||
## Hipótesis y prueba
|
||||
|
||||
Los cuatro packs repiten las dos reglas `commit-select` y `commit-unselect`
|
||||
con `haptic: { kind: 'tap' }`. Un constructor privado debe aceptar el selector
|
||||
tipado del `item` y devolver esas dos reglas en el mismo orden. TagGroup debe
|
||||
conservar sus otras dos reglas después de ellas. Una prueba de caracterización
|
||||
fijará los cuatro arrays completos antes de modificar producción. La misma
|
||||
prueba, el censo Sema, resolver, engine y la auditoría de los cuatro componentes
|
||||
deben pasar después. Si el tipado o la salida cambia, se abandona la extracción.
|
||||
|
||||
## Resultado
|
||||
|
||||
Se extrajo únicamente el par de reglas a `selection-toggle-cascade.ts`.
|
||||
Combobox, Select y Listbox llaman al constructor con su `onItem` tipado;
|
||||
TagGroup lo extiende con sus reglas locales de retirada y reset. La prueba
|
||||
de caracterización pasó 172/172 junto con censo, resolver y engine antes y
|
||||
después. `component:audit` terminó en PASS para los cuatro componentes.
|
||||
`check:gate` terminó sin errores nuevos en `src/` ni `scripts/` (los 89
|
||||
errores registrados siguen en `web/`). No se modificaron Morfo, Soma, Eidos,
|
||||
API, DOM, CSS, ARIA ni temporización. No se hizo comparación visual manual
|
||||
porque esta extracción sólo construye datos de Sema.
|
||||
@ -0,0 +1,17 @@
|
||||
import type { Sema } from '../sema-map';
|
||||
|
||||
type OnItem = (matchers: { eventName: 'commit-select' | 'commit-unselect' }) => string;
|
||||
|
||||
/** Shared perceptual rules for committed item selection. */
|
||||
export function selectionToggleCascade(onItem: OnItem): Sema['cascade'] {
|
||||
return [
|
||||
{
|
||||
selector: onItem({ eventName: 'commit-select' }),
|
||||
haptic: { kind: 'tap' }
|
||||
},
|
||||
{
|
||||
selector: onItem({ eventName: 'commit-unselect' }),
|
||||
haptic: { kind: 'tap' }
|
||||
}
|
||||
];
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { semaSelector } from '$uix/morfo';
|
||||
import { comboboxMorfo } from '$uix/morfo/components/combobox';
|
||||
import { listboxMorfo } from '$uix/morfo/components/listbox';
|
||||
import { selectMorfo } from '$uix/morfo/components/select';
|
||||
import { tagGroupMorfo } from '$uix/morfo/components/tag-group';
|
||||
import { comboboxSema } from './components/combobox';
|
||||
import { listboxSema } from './components/listbox';
|
||||
import { selectSema } from './components/select';
|
||||
import { tagGroupSema } from './components/tag-group';
|
||||
|
||||
describe('selection perceptual packs', () => {
|
||||
it.each([
|
||||
['Combobox', comboboxMorfo, comboboxSema],
|
||||
['Select', selectMorfo, selectSema],
|
||||
['Listbox', listboxMorfo, listboxSema],
|
||||
['TagGroup', tagGroupMorfo, tagGroupSema]
|
||||
] as const)('keeps %s item selection signatures and rule order', (_name, morfo, pack) => {
|
||||
expect(pack.cascade.slice(0, 2)).toEqual([
|
||||
{
|
||||
selector: semaSelector(morfo, 'item', { eventName: 'commit-select' }),
|
||||
haptic: { kind: 'tap' }
|
||||
},
|
||||
{
|
||||
selector: semaSelector(morfo, 'item', { eventName: 'commit-unselect' }),
|
||||
haptic: { kind: 'tap' }
|
||||
}
|
||||
]);
|
||||
expect(pack.cascade).toHaveLength(pack === tagGroupSema ? 4 : 2);
|
||||
});
|
||||
|
||||
it('keeps TagGroup removal on the item and reset on the provider', () => {
|
||||
expect(tagGroupSema.cascade.slice(2)).toEqual([
|
||||
{
|
||||
selector: semaSelector(tagGroupMorfo, 'item', { eventName: 'commit-remove' }),
|
||||
haptic: { kind: 'tap' }
|
||||
},
|
||||
{
|
||||
selector: semaSelector(tagGroupMorfo, 'provider', { eventName: 'commit-reset' }),
|
||||
haptic: { kind: 'tap' }
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in new issue