Sexto del bloque F2-A, y el primero cuyo techo es DELIBERADO.
censo 0 % → 68 % · global 42 %
computed 2.813 valores en 7 estados: 0 diffs
**Este componente no puede acuñar su ritmo de fila, y esa es la regla de oro de
las capas compartidas.** Altura, padding inline y block, gap y tamaño de letra
los posee `lib/list-surface.css`, por talla, para TODAS las superficies de lista
—select, combobox, command y los menús—. Acuñar `--listbox-item-height` sería
el vocabulario paralelo que las reglas de esa capa prohíben, y encima ganaría a
la capa para todas las demás. Los cinco privados ADOPTAN la capa y se quedan
privados; un tema mueve ese ritmo por `--list-*`, que es donde vive.
Consecuencia honesta: el censo cuenta esos cinco como privados y el alcance se
queda en 68 % en vez de ~86 %. **La métrica penaliza hacer lo correcto** — el
mismo defecto de medición que D-TH.2-b arregló para los primitivos tipográficos
(`--style-*` pasó a `system`). Registrado en `next-features.md` §13; extenderlo
a las capas compartidas es decisión, no corrección al paso.
**Dos cosas medidas que NO se tocaron:**
- El `highlighted` pinta DOS veces: la receta pone un `--color-surface-overlay`
plano y encima el arquetipo `item` añade su velo del 8 %. El plano es el
duplicado que §38 deprecó, así que se dejó SIN token — bendecir con un nombre
público algo condenado a morir es el error que este eje ya evitó en el
codemod. Retirarlo mueve píxel.
- La tinta de la fila seleccionada era código MUERTO y se retiró: el arquetipo
la fija a (0,4,0) contra los (0,3,0) de la receta. Mismo hallazgo que en
`table`, verificado igual, 0 diffs al quitarlo.
Lo que sí es suyo y ahora es público: la superficie que sostiene las filas
(fondo, borde, radio, padding, gap, tipografía, alto máximo), la esquina y la
tinta de la fila, el glifo de selección y el grupo con su etiqueta.
audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados ·
suite: sólo el rojo conocido
Demo con tab Tokens: 21 filas, 0 sin computar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inline del wrapper): `--_listbox-palette-element`, `--_listbox-palette-solid`.
@ -90,7 +66,7 @@ Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inl
- **Consume la capa compartida `list-surface`.** Un eje que la capa posee se consume como `var(--_x, var(--x))`; el consumidor **no acuña**`--listbox-{eje}` para él — sería un vocabulario paralelo (README de `eidos/components`, «Capas compartidas» regla 2).
- **Consume la capa compartida `menu-indicator`.** Un eje que la capa posee se consume como `var(--_x, var(--x))`; el consumidor **no acuña**`--listbox-{eje}` para él — sería un vocabulario paralelo (README de `eidos/components`, «Capas compartidas» regla 2).
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (29)
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (7)
Valor **verbatim** del CSS de hoy: el default no se mueve, sólo cambia quién
puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla
@ -100,40 +76,16 @@ no distingue lo que debería — se marca `⚠`.
- **⚠ decisión: `padding` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `padding`.
- **⚠ decisión: `border` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `border`.
- **⚠ decisión: `100%` es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar** — 1: `inline-size`.
- **⚠ decisión: el privado que alimenta este knob no se declara en el CSS (viene de `base.ts` o de un estilo inline) — hay que resolverlo antes de nombrarlo** — 3: `background`, `color`.
- **`value` siempre `string[]`** (también en single): un solo tipo de dato
para las dos cardinalidades; `selectionMode` gobierna el gesto, no el tipo.
## Talla y tema
Contrato en `lib/recipes/base.ts > listbox` (21 claves). Alcance del censo:
**68 %**, y ese techo es DELIBERADO — no deuda.
### Lo que este componente NO puede acuñar
El ritmo de fila —altura, padding inline y block, gap y tamaño de letra— lo
posee `lib/list-surface.css`, por talla, para TODAS las superficies de lista
(select, combobox, command y los menús). La regla de las capas compartidas es
explícita: **un consumidor no acuña `--{componente}-{eje}` para un eje que la
capa ya posee** — sería un vocabulario paralelo, y además ganaría a la capa
para todas las demás superficies.
Así que los cinco privados `--_listbox-item-*`**adoptan** la capa y se quedan
privados. Un tema mueve ese ritmo por `--list-item-*` / `--list-font-size`, que
es donde vive. El censo los cuenta como privados y baja el alcance: la métrica
penaliza hacer lo correcto, y eso está registrado en `next-features.md` §13.
**Sin eje `size` propio**: nada estampa `data-size` para estos ejes; la talla
llega por el contexto de la capa.
### Lo que sí es suyo
La superficie que sostiene las filas (fondo, borde, radio, padding, gap,
tipografía, alto máximo), la esquina y la tinta de la fila, el tamaño del
glifo de selección, y el grupo con su etiqueta.
### Dos cosas medidas que NO se tocaron
- **El `highlighted` pinta DOS veces.** La receta pone
`background: var(--color-surface-overlay)` y encima el arquetipo `item` añade
su velo — medido: `bg` opaco + `background-image` con el gradiente del 8 %.
El plano es el duplicado que §38 deprecó, así que **no se le acuñó token**:
bendecir con un nombre público algo condenado a morir es el error que este
eje ya evitó en el codemod. Retirarlo mueve píxel ⇒ decisión aparte.
- **La tinta de la fila seleccionada era código muerto** y se retiró: el
arquetipo la fija a (0,4,0) contra los (0,3,0) de la receta. Mismo hallazgo
que en `table`, verificado igual y con 0 diffs al quitarlo.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| `data-readonly` declarado sin estilo (R-1.3) | **implementar** | Censo de familia de selección: tratamiento muted + cursor default cuando aterrice el pase readonly. |
| Selección por arrastre (drag-select de rango, estilo file manager) | **diferir** | Sin caso real; multiple + Shift/Ctrl cubre el uso actual. |
| Virtualización de listas largas | **descartar** | Pertenece a `VirtualList`/`s-text-virtual-list` — componer, no absorber. |
| Tests del wrapper eidos (soma con suite ✓) | **diferir** | Pasada SYS-2. |
| `data-readonly` declarado sin estilo (R-1.3) | **implementar** | Censo de familia de selección: tratamiento muted + cursor default cuando aterrice el pase readonly. |
| Selección por arrastre (drag-select de rango, estilo file manager) | **diferir**| Sin caso real; multiple + Shift/Ctrl cubre el uso actual. |
| Virtualización de listas largas | **descartar** | Pertenece a `VirtualList`/`s-text-virtual-list` — componer, no absorber. |
| Tests del wrapper eidos (soma con suite ✓) | **diferir**| Pasada SYS-2. |
<tr><tdclass="name">value <spandata-uix-tagdata-kind="bindable">bindable</span></td><tdclass="type">string[]</td><tdclass="default">[]</td><td>Current selection. Always string[]; single mode keeps at most one entry.</td></tr>
<tr><tdclass="name">value</td><tdclass="type">string</td><tdclass="default empty">required</td><td>Unique identifier in the listbox.</td></tr>
<tr><tdclass="name">disabled</td><tdclass="type">boolean</td><tdclass="default">false</td><td>Skip the item from keyboard nav + click selection.</td></tr>
<tr><tdclass="name">[data-listbox-item][data-selected]</td><td><spandata-uix-tagdata-kind="soma">morfo</span></td><td>Selected-state band (accent-soft fill).</td></tr>
<tr><tdclass="name">[data-listbox-item-indicator]</td><td><spandata-uix-tagdata-kind="soma">morfo</span></td><td>Hidden by default; revealed inside selected items.</td></tr>