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

153 lines
9.6 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.

# textarea — 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-21 · **Alcance**: **80%** — 20 de 25 knobs por token público
- **Knobs de apariencia**: 28 — público 20 · privado 2 · global 0 · literal 3 · sistema 3 _(fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 37 pública(s) — `input-font-size-xs`, `input-font-size-sm`, `input-font-size-md`, `input-font-size-lg`, `input-font-size-xl`, `input-padding-inline-xs`, `input-padding-inline-sm`, `input-padding-inline-md`, `input-padding-inline-lg`, `input-padding-inline-xl`, `input-padding-block-xs`, `input-padding-block-sm`, `input-padding-block-md`, `input-padding-block-lg`, `input-padding-block-xl`, `input-font-size`, `input-padding-inline`, `input-padding-block`, `gap`, `input-radius`, `input-border-width`, `input-border`, `hover-input-border`, `focus-input-border`, `invalid-input-border`, `input-bg`, `input-fg`, `input-placeholder-fg`, `input-font-family`, `input-font-weight`, `input-line-height`, `count-font-size`, `count-gap`, `count-fg`, `count-font-family`, `overflow-count-fg`, `overflow-count-font-weight` · 1 privada(s) forward — `_palette-solid`
- **Eje `size`**: no · **ficheros**: `textarea.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (0)
_Ninguno._
### 1.2 A través de un privado (2)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `textarea.css:71` | `[data-textarea][data-focused] [data-textarea-input]` | `border-color` | `var(--_textarea-border-focus)` |
| 2 | `textarea.css:91` | `[data-textarea][data-variant='ghost'][data-focused] [data-textarea-input]` | `border-color` | `var(--_textarea-border-focus)` |
### 1.3 Literales (3)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `textarea.css:19` | `[data-textarea]` | `inline-size` | `100%` |
| 2 | `textarea.css:47` | `[data-textarea-input]` | `inline-size` | `100%` |
| 3 | `textarea.css:113` | `[data-textarea-count]` | `line-height` | `1` |
## 2. Sistema transversal (3) — 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 | `textarea.css:74` | `[data-textarea][data-focused] [data-textarea-input]` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
| 2 | `textarea.css:96` | `[data-textarea-input][data-disabled]` | `opacity` | `var(--opacity-disabled)` |
| 3 | `textarea.css:122` | `[data-textarea-count-sep]` | `opacity` | `var(--opacity-muted)` |
## 3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_textarea-border-focus` | 2 | `var(--textarea-focus-input-border)`, `var(--_textarea-palette-solid)` | private, public | no |
| `--_textarea-resize` | 4 | `vertical`, `none`, `horizontal`, `both` | literal | no |
Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inline del wrapper): `--_textarea-palette-solid`.
## 4. Propuesta de corrección
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (2)
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 (`--textarea-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `input-border` _(ya existe)_ | `root` | ⚠ `var(--textarea-focus-input-border)` / `var(--_textarea-palette-solid)` | 2 |
| `ghost-input-border` | `root` | ⚠ `var(--textarea-focus-input-border)` / `var(--_textarea-palette-solid)` | 2 |
### 4.2 Sin nombre mecánico (3)
- **⚠ 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** — 2: `inline-size`.
- **⚠ decisión: `1` 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: `line-height`.
### 4.3 Avisos sobre los tokens propuestos (1)
- **el privado `--_textarea-border-focus` debe pasar a leer este público (o desaparecer)** — `--textarea-input-border`, `--textarea-ghost-input-border`
### 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 2026-08-21** (sonda ×2 sobre el mismo código = 0 diffs en 1.247
valores · 8 estados). La §4 propone 35 tokens y **cuatro de ellos son
colisiones que hay que partir o retirar**, más un error que cambiaría el
default. Corregido queda en 37 claves.
1. **`count-font-size-{k}` × 5 BORRARÍA el factor 0.85 — es el error grave de
la propuesta.** El CSS calcula `calc(var(--_textarea-font-size) * 0.85)`
(con su anotación `/* literal: */`), y la §4 propone cinco tokens con el
font-size del INPUT crudo: el contador crecería un 18 % en las cinco
tallas. D-TH.5 lo prohíbe. La corrección: **UN** token
`count-font-size` que conserva el `calc` sobre el público del input, así
sigue la talla sin repetir la escala. Mismo reparto que `tree-grid.guide-fg`
— el knob es el valor, la construcción se queda en la receta.
2. **`input-fg` ⚠ son DOS knobs**: la tinta del texto
(`--color-content-primary`) y la del placeholder
(`--color-content-muted`). El clasificador las fundió por caer ambas sobre
la parte `input`. → `input-fg` + `input-placeholder-fg` (precedente
exacto: `command.input-fg` / `command.input-placeholder-fg`).
3. **`count-fg` ⚠ son DOS knobs**: reposo (`content-muted`) y rebasado
(`threat-text`). → `count-fg` + `overflow-count-fg`; `overflow` es valor
de `data-overflow`, declarado en el morfo (`textarea.ts:163`), así que
entra como modificador delante.
4. **`input-border` ⚠ NO son dos knobs, y su nombre está mal.** Los dos
valores son UNA variable (`--_textarea-border-focus`) con su swap de
paleta: `--focus-ring-color` de base y `--_textarea-palette-solid` cuando
hay `data-color`. El swap es el forward THM-2 y **se queda privado**. Y el
knob es el borde de FOCO, no el de reposo → `focus-input-border`. El de
reposo (`--color-neutral-border`) es otro token, que la §4 ni listó porque
viaja dentro del atajo `border:`.
5. **`ghost-input-border` ⚠ se RETIRA de la propuesta**: la regla ghost lee
exactamente la misma `--_textarea-border-focus` que la regla base. Un token
propio sería un duplicado con dos nombres para un valor.
6. **`border` shorthand se parte** en `input-border-width` + `input-border`
(color) — molde `command.input-border` / `input-border-width`.
7. **Qué casa con el bundle, medido** (`generated/base.css:409-450`):
- `font-size` casa **1:1 en las cinco** (`font-size-{k}` ES
`--size-{k}-font-size`) → van al bundle.
- `padding-inline` casa en sm/md/lg/xl pero **NO en xs**: el textarea pone
`--space-2` (8px) donde el bundle dice `--space-1-5` (6px).
- `padding-block` **no casa en ninguna salvo xs**: sm 6px vs 4px, md 8px vs
6px, lg 12px vs 8px. El campo multi-línea respira más que un control de
una línea, y es correcto.
Los dos ejes de spacing van **verbatim en `--space-*`**, con la desviación
escrita: el guard del bundle gobierna control-height / font-size /
icon-size, no el spacing (precedente `table.cell-padding-*` y
`tree-grid.row-padding-*`). Los resueltos **sin `parts`** — `data-size` se
estampa en `[data-textarea]` y el input hereda; molde `command`.
8. **Fuera del contrato, a propósito**: los dos `inline-size: 100%` y el
`line-height: 1` del count (identidad, D-TH.2); `--_textarea-resize`, que
no es apariencia sino el enum de comportamiento que el morfo conduce; y el
forward de paleta.
9. **Alcance final 80 %** (20 de 25) — mi propia predicción de «≈100 %» era
errónea y la medición la corrigió. **Cero globales** y cero privados de
valor: los 16 de la propuesta leen ya su público. Lo que queda son las
DOS declaraciones que consumen `--_textarea-border-focus` (base y ghost),
que el censo cuenta como `private` porque el privado sobrevive **a
propósito** — es el conmutador de una variable con dos fuentes (el token
público y el forward de paleta), y aplanarlo exigiría duplicar la regla
por color. Es el mismo techo de `listbox` (68 % por consumir bien su capa)
y el mismo que §13 registra para los forwards THM-2: la métrica penaliza
hacer lo correcto. Más los tres literales de identidad (dos `100%` y el
`line-height: 1` del contador), fuera del perímetro por D-TH.2.
<!-- veredicto:end -->

Powered by TurnKey Linux.