You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/audit/theming/fab.md

143 lines
7.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# fab — alcance de tema: análisis y propuesta
> Generado por `node --import tsx/esm scripts/theming-census.ts --report`.
> Lo **medido** y la **propuesta** se regeneran; el **Veredicto** (§5) se conserva.
> Vista de conjunto: [README](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
- **Medido**: 2026-08-24 · **Alcance**: **100%** — 16 de 16 knobs por token público
- **Knobs de apariencia**: 16 — público 16 · privado 0 · global 0 · literal 0 · sistema 0 · excepción 1 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 12 pública(s) — `size-xs`, `size-sm`, `size-md`, `size-lg`, `icon-xs`, `icon-sm`, `icon-md`, `icon-lg`, `shadow`, `lift`, `padding-inline-extended`, `gap-extended`
- **Eje `size`**: no · **ficheros**: `fab.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (0)
_Ninguno._
### 1.2 A través de un privado (0)
_Ninguno._
### 1.3 Literales (0)
_Ninguno._
### 1.4 Excepciones firmadas (1) — fuera del ratio
Literales que llevan su anotación `/* literal: <razón> */` en la propia
declaración: la válvula de recipe-contract §3, la misma que honra
`component-audit`. **Una desviación firmada no es deuda** — se listan para que la
razón se lea, no para acuñarlas.
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `fab.css:104` | `[data-fab] [data-button-icon]` | `font-size` | `1em` |
## 2. Sistema transversal (0) — informativo, fuera del ratio
Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2).
_Ninguno._
## 3. Privados de la receta — ¿de dónde sale su valor?
_La receta no declara privados propios en su CSS._
## 4. Propuesta de corrección
- **Consume la capa compartida `list-surface`.** Un eje que la capa posee se consume como `var(--_x, var(--x))`; el consumidor **no acuña** `--fab-{eje}` para él — sería un vocabulario paralelo (README de `eidos/components`, «Capas compartidas» regla 2).
- **Consume la capa compartida `viewport-placement`.** Un eje que la capa posee se consume como `var(--_x, var(--x))`; el consumidor **no acuña** `--fab-{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` (1)
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
al final) y theming §6.7 (slots de color, modificador delante). Un token con
DOS valores distintos es una colisión de nombre: son dos knobs, o el nombre
no distingue lo que debería — se marca `⚠`.
| token (`--fab-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `font-size` | `root` | `1em` | 1 |
### 4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)
- [ ] **Privado que no deriva de un público** — §3 lo marca; el privado debe leer el público o desaparecer.
- [ ] **Velo o acento en el nodo equivocado** (`archetype: 'item'` en un envoltorio, un `background` en shorthand que mata la capa de estado) — se mide desde el píxel hacia arriba.
- [ ] **Doble animación** al mover un sello a una superficie con animación propia — registro de `animationstart`/`animationend`.
- [ ] **Diff de computed = 0** en reposo · hover · abierto · disabled · foco, por talla, antes y después.
- [ ] **Centinela por token nuevo**: valor imposible en el root → el nodo lo sigue. Si no, el token miente.
## 5. Veredicto
<!-- veredicto:start -->
**Medido y CERRADO al 100 % el 2026-08-24** (88 % → 100 %, 10 → 12 claves de
contrato, centinela **11/12** con 1 adjudicada).
**Lo que faltaba eran DOS knobs, y los dos del pill extendido.** El FAB
circular no declara ni `padding-inline` ni `gap`; la regla
`[data-button][data-fab][data-extended]` sí, y leía `var(--space-5)` /
`var(--space-2)` A PELO. Es la COSTURA del PLAN §2-A: el valor sigue siendo del
sistema, el knob pasa a ser del componente —
`--fab-padding-inline-extended` / `--fab-gap-extended`, defaults verbatim.
`global` a CERO.
**El nombre**: el cualificador va DETRÁS. `extended` es un MODO del FAB, no un
estado interactivo (el vocabulario cerrado es hover · active · selected ·
disabled · checked · open · focus · invalid · current), así que cae en la otra
mitad de la frase firmada en D-TH.6 — «detrás lo dimensional y contextual»,
igual que `sidebar.width-icon` y `radio-group.gap-vertical`. Y un
`--fab-padding-inline` a secas MENTIRÍA: prometería a todo FAB un padding que
sólo tiene el pill.
**Lo que NO se acuña**, y por qué el 100 % no lleva las tres claves que
proponía la §4:
- El `font-size: 1em` del glifo es **identidad de contexto** y ya lleva su
anotación `/* literal: */` — fuera del ratio por la válvula de
recipe-contract §3.
- La colocación flotante es de la capa compartida `viewport-placement`. Fab
escribe su **ranura de override** (`--_viewport-placement-z`) y no acuña
vocabulario paralelo: `--fab-offset` y `--fab-z` ya se retiraron por eso
(2026-08-15).
**La composición NO le quita nada.** El aviso valía la pena comprobarlo: el
mismo `<button>` lleva `data-button` **y** `data-fab`, que es la forma exacta
del hallazgo de `gradient-picker` (36 claves muertas bajo `popover.css`). Aquí
no ocurre, y por construcción: las reglas dimensionales del FAB casan
`[data-button][data-fab][data-fab-size]` (0,3,0) contra los (0,2,0) de
`[data-button][data-size]`, así que ganan sea cual sea el orden de carga de los
chunks — lo que su propia cabecera de receta ya declaraba, ahora medido
(padding computado 20 px = `--space-5`, no el del Button). Tampoco lleva
`data-depth`, así que §12.9 no le aplica.
**Lo que el instrumento no ve** — `lift`, la única adjudicada. La receta lo
consume con la propiedad **`translate`** (no `transform`, para no pisar el
press-squeeze del Button) dentro de una regla `:hover`. El guard ni fotografía
`translate` — la misma laguna ya adjudicada tres veces sobre `transform`
(background, rating-group, card) — ni pasa el ratón en su pasada estática.
Medido a mano con puntero real: `--fab-lift: 1234px` escrito ANTES de entrar
da `translate: 0px -1234px` a los 300 ms → **alcanza**. Y trae una trampa
nueva que conviene tener escrita: **el propio centinela se auto-cancela**, un
lift de ese tamaño se lleva el nodo de debajo del cursor, `:hover` cae y el
valor vuelve a `none` hacia t+900 ms. Añadirle una pasada de hover al guard NO
lo mediría.
**Diff de computed = 0** en las dos formas: 416 valores × 7 estados en el
escenario por defecto (circular) y 188 valores × 4 tallas + hover en el pill
extendido, medido con una sonda de un solo uso porque la demo arranca
circular. Capturas 2× antes/después **byte a byte idénticas** en las dos
formas.
**El instrumento aprendió dos cosas de este componente**: un FAB es UN nodo
(la sonda medía 1 — la bandera de «cuenta los nodos»), así que su segunda
superficie pintada, el hueco de icono del Button compuesto, entra por
`EXTRA_NODES`; y su eje de talla es `data-fab-size`, **no** `data-size`, así
que el barrido genérico del guard no sellaba nada y los seis pasos xs/sm/lg
leían muertos. Con el barrido cartesiano de `data-fab-size` × `data-extended`
el guard pasa de **3/12 a 11/12** sin adjudicar una sola clave de más.
<!-- veredicto:end -->

Powered by TurnKey Linux.