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/form.md

168 lines
13 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.

# form — 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-23 · **Alcance**: **86%** — 43 de 50 knobs por token público
- **Knobs de apariencia**: 51 — público 43 · privado 7 · global 0 · literal 0 · sistema 1 · excepción 1 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 64 pública(s) — `gap-xs`, `gap-sm`, `gap-md`, `gap-lg`, `gap-xl`, `font-family`, `fg`, `radius`, `border-width`, `panel-padding`, `panel-border`, `panel-bg`, `panel-shadow`, `grid-min`, `grid-column-gap`, `action-height-xs`, `action-height-sm`, `action-height-md`, `action-height-lg`, `action-height-xl`, `action-padding-inline-xs`, `action-padding-inline-sm`, `action-padding-inline-md`, `action-padding-inline-lg`, `action-padding-inline-xl`, `action-font-size-xs`, `action-font-size-sm`, `action-font-size-md`, `action-font-size-lg`, `action-font-size-xl`, `action-font-weight`, `action-line-height`, `action-gap`, `action-radius`, `action-border-width`, `error-summary-padding`, `error-summary-border-width`, `error-summary-radius`, `error-summary-font-size`, `error-summary-line-height`, `error-summary-bg`, `error-summary-fg`, `error-summary-border`, `invalid-accent`, `error-summary-list-indent`, `link-underline-fg`, `link-underline-offset`, `auto-fields-gap`, `auto-fields-array-padding`, `auto-fields-border-width`, `auto-fields-radius`, `auto-fields-array-bg`, `auto-fields-item-bg`, `auto-fields-border`, `auto-fields-item-gap`, `auto-fields-item-padding`, `widget-padding-inline`, `widget-bg`, `widget-border`, `widget-radius`, `widget-border-width`, `transition-duration`, `transition-ease`, `disabled-opacity` · 4 privada(s) forward — `_palette-solid`, `_palette-solid-hover`, `_palette-border`, `_palette-contrast`
- **Eje `size`**: sí · **ficheros**: `form.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (0)
_Ninguno._
### 1.2 A través de un privado (7)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `form.css:16` | `[data-form]` | `padding` | `var(--_form-padding)` |
| 2 | `form.css:19` | `[data-form]` | `background` | `var(--_form-bg)` |
| 3 | `form.css:20` | `[data-form]` | `box-shadow` | `var(--_form-shadow)` |
| 4 | `form.css:103` | `[data-form-submit], [data-form-reset], [data-form-auto-fields-array-add], [data-form-auto-fields-array-remove]` | `background` | `var(--_form-action-bg)` |
| 5 | `form.css:104` | `[data-form-submit], [data-form-reset], [data-form-auto-fields-array-add], [data-form-auto-fields-array-remove]` | `box-shadow` | `var(--_form-action-shadow)` |
| 6 | `form.css:105` | `[data-form-submit], [data-form-reset], [data-form-auto-fields-array-add], [data-form-auto-fields-array-remove]` | `color` | `var(--_form-action-color)` |
| 7 | `form.css:173` | `[data-form-submit]:not(:disabled):hover, [data-form-reset]:not(:disabled):hover, [data-form-auto-fields-array-add]:not(:disabled):hover, [data-form-auto-fields-array-remove]:not(:disabled):hover` | `background` | `var(--_form-action-bg-hover)` |
### 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 | `form.css:14` | `[data-form]` | `inline-size` | `100%` |
## 2. Sistema transversal (1) — informativo, fuera del ratio
Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2).
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `form.css:180` | `[data-form-submit]:focus-visible, [data-form-reset]:focus-visible, [data-form-auto-fields-array-add]:focus-visible, [data-form-auto-fields-array-remove]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
## 3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_form-gap` | 5 | `var(--form-gap-md)`, `var(--form-gap-xs)`, `var(--form-gap-sm)`, `var(--form-gap-lg)`, `var(--form-gap-xl)` | public | **sí** |
| `--_form-padding` | 2 | `0`, `var(--form-panel-padding)` | literal, public | no |
| `--_form-border` | 2 | `transparent`, `var(--form-panel-border)` | literal, public | no |
| `--_form-bg` | 2 | `transparent`, `var(--form-panel-bg)` | literal, public | no |
| `--_form-shadow` | 2 | `none`, `var(--form-panel-shadow)` | literal, public | no |
| `--_form-action-height` | 8 | `var(--form-action-height-md)`, `var(--form-action-height-xs)`, `var(--form-action-height-sm)`, `var(--form-action-height-lg)`, `var(--form-action-height-xl)` | public | **sí** |
| `--_form-action-padding-inline` | 8 | `var(--form-action-padding-inline-md)`, `var(--form-action-padding-inline-xs)`, `var(--form-action-padding-inline-sm)`, `var(--form-action-padding-inline-lg)`, `var(--form-action-padding-inline-xl)` | public | **sí** |
| `--_form-action-font-size` | 8 | `var(--form-action-font-size-md)`, `var(--form-action-font-size-xs)`, `var(--form-action-font-size-sm)`, `var(--form-action-font-size-lg)`, `var(--form-action-font-size-xl)` | public | **sí** |
| `--_form-invalid-accent` | 1 | `var(--form-invalid-accent)` | public | **sí** |
| `--_form-action-bg` | 4 | `var(--color-neutral-element)`, `var(--_form-palette-solid)`, `transparent` | global, literal, private | no |
| `--_form-action-bg-hover` | 4 | `var(--color-neutral-hover)`, `var(--_form-palette-solid-hover)`, `color-mix(in srgb, var(--_form-action-border) 10%, transparent)`, `color-mix(in srgb, var(--color-neutral-track) 70%, transparent)` | global, private | no |
| `--_form-action-border` | 3 | `var(--color-neutral-border)`, `var(--_form-palette-border)`, `transparent` | global, literal, private | no |
| `--_form-action-color` | 4 | `var(--color-neutral-text)`, `var(--_form-palette-contrast)`, `var(--_form-action-border)`, `var(--color-content-secondary)` | global, private | no |
| `--_form-action-shadow` | 1 | `none` | literal | no |
Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inline del wrapper): `--_form-palette-border`, `--_form-palette-contrast`, `--_form-palette-solid`, `--_form-palette-solid-hover`.
## 4. Propuesta de corrección
- **Tiene eje `size`**: los tokens dimensionales van por talla (`{part}-{eje}-{k}`) apuntando al bundle `--size-{k}-*`, nunca al primitivo crudo (theming §5; el guard `recipe-css-contract` prohíbe el primitivo).
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (6)
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 (`--form-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `submit-bg` | `root` | ⚠ `var(--color-neutral-element)` / `var(--_form-palette-solid)` / `transparent` | 4 |
| `submit-fg` | `root` | ⚠ `var(--color-neutral-text)` / `var(--_form-palette-contrast)` / `var(--_form-action-border)` / `var(--color-content-secondary)` | 4 |
| `hover-submit-bg` | `root` | ⚠ `var(--color-neutral-hover)` / `var(--_form-palette-solid-hover)` / `color-mix(in srgb, var(--_form-action-border) 10%, transparent)` / `color-mix(in srgb, var(--color-neutral-track) 70%, transparent)` | 4 |
| `bg` | `root` | ⚠ `transparent` / `var(--form-panel-bg)` | 2 |
| `shadow` | `root` | ⚠ `none` / `var(--form-panel-shadow)` | 2 |
| `submit-shadow` | `root` | `none` | 1 |
### 4.2 Sin nombre mecánico (2)
- **⚠ 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: `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`.
### 4.3 Avisos sobre los tokens propuestos (6)
- **el privado `--_form-bg` debe pasar a leer este público (o desaparecer)** — `--form-bg`
- **el privado `--_form-shadow` debe pasar a leer este público (o desaparecer)** — `--form-shadow`
- **el privado `--_form-action-bg` debe pasar a leer este público (o desaparecer)** — `--form-submit-bg`
- **el privado `--_form-action-shadow` debe pasar a leer este público (o desaparecer)** — `--form-submit-shadow`
- **el privado `--_form-action-color` debe pasar a leer este público (o desaparecer)** — `--form-submit-fg`
- **el privado `--_form-action-bg-hover` debe pasar a leer este público (o desaparecer)** — `--form-hover-submit-bg`
### 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 -->
**EJECUTADO 2026-08-23 — 71 % → 86 %.** Diez claves nuevas (54 → 64), un literal
firmado, veinte adjudicaciones medidas **y un hallazgo que espera firma**. Diff
de computed **0 sobre 832 valores en 7 estados**.
**Las diez iban a los primitivos a pelo**: el resumen de errores
(`error-summary-{bg,fg,border}` — es el señalizador de nivel de página y su
superficie, su tinta y su borde SON el tono risk), el acento de formulario
inválido (`invalid-accent`, un privado con UNA sola fuente, no un conmutador),
las tres superficies del árbol de AutoFields, las dos del widget y el subrayado a
media tinta de los enlaces del resumen (`link-underline-fg`, el par del
`-offset` que ya existía).
⚠ **R-5.3 cazó mi nombre en el acto**: lo acuñé como `link-underline-color` y la
tinta es `fg` (theming §6.7 r7, firmado el 2026-08-20). Renombrado antes de
commitear. El guard de nombres funciona — es el vocabulario DIMENSIONAL el que
no cubre (ver `badge`, hoy mismo).
⚠⚠ **VEINTICUATRO claves del contrato NO PINTAN, y es una cascada, no un valor.**
`[data-form-submit]`, `[data-form-reset]` y los dos botones del array llevan
también `data-button` porque COMPONEN el `Button` canónico, y `[data-button]`
casa con la MISMA especificidad (0,1,0) pero carga DESPUÉS: gana `button.css`.
Medido propiedad a propiedad sobre el nodo real —altura, `padding-inline`,
tamaño y peso de letra, interlineado, hueco, radio, grosor de borde, el par de
transición y la opacidad deshabilitada—: **ninguna se mueve**. Es el defecto que
`gradient-picker` documentó (36 de sus 45 claves) y que `emoji-picker` encontró
hoy en su trigger. Allí la respuesta fue RETIRAR las declaraciones muertas; aquí
son **24 claves públicas**, y retirar eso es una decisión del autor, no del que
ejecuta. Quedan **adjudicadas por PATRÓN** en el ledger (una razón
arquitectónica escrita una vez) y anotadas para firma.
**Las adjudicaciones restantes son ramas que la demo no monta**: el layout
`grid` (forzado alcanza — y ojo, su `grid-template-columns` sólo CAMBIA si el
valor altera el número de columnas: con 90px pasa de una columna de 502px a
cuatro de 110,5), el resumen de errores VACÍO (sin `<ul>` que indentar ni `<a>`
que subrayar) y toda la rama de ARRAY de AutoFields — el modo `auto` de la demo
monta `group` y `field`, nunca `array`, `item` ni `widget`.
**Lo que queda fuera por doctrina**: los tres privados del panel son un
CONMUTADOR (variante `plain` contra `panel`) y los cuatro `--_form-action-*`
leen el forward de paleta THM-2.
**Verificación**: sonda antes/después **0 diffs** (832 valores · 7 estados) ·
R-5.4 **22/64** con las 20 + el patrón adjudicados, exit 0 · `component:audit`
PASS (tras el renombrado) · `--names` 0 desviadas · censo 86 % · `eidos-lint` 36
morfo-backed / **0 invalid, 0 class-hooks** · capturas 2×.
<!-- veredicto:end -->

Powered by TurnKey Linux.