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

154 lines
10 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.

# calendar — 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**: **89%** — 57 de 64 knobs por token público
- **Knobs de apariencia**: 67 — público 57 · privado 7 · global 0 · literal 0 · sistema 3 · excepción 4 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 74 pública(s) — `gap`, `padding-xs`, `padding-sm`, `padding-md`, `padding-lg`, `radius`, `border-width`, `border`, `invalid-border`, `bg`, `outline-bg`, `outline-shadow`, `fg`, `shadow`, `font-family`, `font-size-xs`, `font-size-sm`, `font-size-md`, `font-size-lg`, `line-height`, `header-gap`, `heading-fg`, `heading-font-size`, `heading-font-weight`, `control-size-xs`, `control-size-sm`, `control-size-md`, `control-size-lg`, `control-radius`, `control-border-width`, `control-border`, `hover-control-border`, `control-bg`, `control-fg`, `hover-control-fg`, `select-min-width`, `select-padding-inline`, `months-gap`, `grid-gap`, `weekday-size`, `weekday-fg`, `weekday-font-size`, `weekday-font-weight`, `day-size-xs`, `day-size-sm`, `day-size-md`, `day-size-lg`, `day-radius`, `day-border-width`, `day-border`, `hover-day-border`, `day-bg`, `day-fg`, `hover-day-fg`, `day-font-weight`, `day-selected-fg`, `range-start-solid`, `range-start-solid-hover`, `range-start-border`, `range-start-text`, `range-end-solid`, `range-end-solid-hover`, `range-end-border`, `range-end-text`, `day-today-border`, `day-today-fg`, `day-today-font-weight`, `day-outside-fg`, `day-outside-opacity`, `day-weekend-fg`, `day-unavailable-decoration`, `transition-duration`, `transition-ease`, `disabled-opacity` · 5 privada(s) forward — `_palette-solid`, `_palette-solid-hover`, `_palette-track`, `_palette-border`, `_palette-text`
- **Eje `size`**: no · **ficheros**: `calendar-select.css`, `calendar.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 | `calendar.css:175` | `[data-calendar-day][data-selected]` | `border-color` | `var(--_calendar-palette-solid)` |
| 2 | `calendar.css:176` | `[data-calendar-day][data-selected]` | `background` | `var(--_calendar-palette-solid)` |
| 3 | `calendar.css:181` | `[data-calendar-day][data-selected]:hover` | `border-color` | `var(--_calendar-palette-solid-hover)` |
| 4 | `calendar.css:182` | `[data-calendar-day][data-selected]:hover` | `background` | `var(--_calendar-palette-solid-hover)` |
| 5 | `calendar.css:186` | `[data-calendar-day][data-focused]:not([data-selected])` | `border-color` | `var(--_calendar-palette-border)` |
| 6 | `calendar.css:187` | `[data-calendar-day][data-focused]:not([data-selected])` | `background` | `var(--_calendar-palette-track)` |
| 7 | `calendar.css:188` | `[data-calendar-day][data-focused]:not([data-selected])` | `color` | `var(--_calendar-palette-text)` |
### 1.3 Literales (0)
_Ninguno._
### 1.4 Excepciones firmadas (4) — 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 | `calendar.css:12` | `[data-calendar]` | `inline-size` | `max-content` |
| 2 | `calendar.css:47` | `[data-calendar-header]` | `inline-size` | `100%` |
| 3 | `calendar.css:88` | `[data-calendar-month-panel]` | `min-inline-size` | `max-content` |
| 4 | `calendar.css:112` | `[data-calendar-grid]` | `inline-size` | `max-content` |
## 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 | `calendar-select.css:31` | `[data-calendar-select-chevron]` | `opacity` | `var(--opacity-muted)` |
| 2 | `calendar.css:102` | `[data-calendar-day]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
| 3 | `calendar.css:170` | `[data-calendar-day]:hover` | `background-image` | `linear-gradient(var(--state-hover), var(--state-hover))` |
## 3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_calendar-surface-accent` | 1 | `var(--_calendar-palette-border)` | private | no |
Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inline del wrapper): `--_calendar-palette-border`, `--_calendar-palette-solid`, `--_calendar-palette-solid-hover`, `--_calendar-palette-text`, `--_calendar-palette-track`.
## 4. Propuesta de corrección
- **Consume la capa compartida `calendar-surface`.** Un eje que la capa posee se consume como `var(--_x, var(--x))`; el consumidor **no acuña** `--calendar-{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` (3)
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 (`--calendar-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `width` | `root` | `max-content` | 1 |
| `month-panel-width` | `root` | `max-content` | 1 |
| `grid-width` | `root` | `max-content` | 1 |
### 4.2 Sin nombre mecánico (8)
- **⚠ 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** — 7: `border-color`, `background`, `color`.
### 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-24 — 84 % → 89 %.** **CERO claves acuñadas**: el censo no
tenía nada que coser (`global` ya era 0 tras la capa `calendar-surface` del
2026-08-21). Lo único fuera de alcance eran cuatro literales de IDENTIDAD, ahora
firmados. El trabajo real fue **MEDIR**: el guard R-5.4 pasó de **45/74 a
68/74** sin tocar una línea de CSS.
**Los cuatro literales firmados** (§1.3 → §1.4, fuera del ratio): el
`inline-size: max-content` del panel y de la tabla (su anchura ES `day-size` × 7
más el espaciado — precedente `progress`), el `min-inline-size: max-content` del
panel de mes y el `inline-size: 100%` de la cabecera.
**Lo que queda fuera (7 privados, techo del componente):** los forwards de
paleta THM-2 (`--_calendar-palette-{solid,solid-hover,track,border,text}`) que
pintan el día seleccionado y el enfocado. No se acuñan. **CERRADO en su 89 %.**
**La §4 generada proponía `width` / `month-panel-width` / `grid-width` para los
tres `max-content`**: sería acuñar una anchura para una caja cuya anchura es su
contenido, y un tema que la moviera rompería la rejilla. Se firman como
identidad, que es lo que son.
### Lo que enseñó — una entrada de FAMILIA no se juzga en la ruta de UN componente
1. **23 de sus 29 «tokens muertos» eran el instrumento.** Esta entrada de
`recipes/base.ts` es la vocabulario de la FAMILIA (lo dice
`lib/calendar-surface.css`): `month-grid`, `year-grid` y `range-calendar`
consumen `--calendar-*` y no acuñan nada — de ahí su 0 % HONESTO. Sus partes
llevan `data-month-grid-*` / `data-range-calendar-*`, invisibles al filtro
`data-calendar`. Con `urls` a las tres rutas de la familia + `extraNodes` +
barrido de `variant`: **45/74 → 68/74**. Ninguno de los tres consumidores se
tocó ni cambió de cifra.
2. **Y la propia demo tapa tres claves más**: su cabecera monta SELECTORES de mes
/ año donde iría el `heading`, así que `heading-{fg,font-size,font-weight}` no
tienen nodo en esta ruta — los tiene `month-grid`.
3. **⚠ HALLAZGO: el tamaño de letra de los selectores de mes / año es NO
DETERMINISTA.** La sonda dio 36 diffs contra un cambio que era SÓLO
comentarios; corrida dos veces sobre el MISMO código dio 24. Causa medida:
`[data-calendar-month-select][data-button]` (calendar-select.css) y
`[data-popover-trigger]:not([data-archetype='field-trigger'])` (popover.css)
empatan a **(0,2,0)** y gana el módulo que Vite inyecte el ÚLTIMO — cuatro
cargas dieron 14px / 16px / 14px / 14px, con el orden de las hojas invertido
en la que dio 16. La regla que existe *precisamente* para fijar la letra del
Button a la del calendario pierde la mitad de las veces. Es la clase del
empate por orden de carga de `tree-grid` (§12); **arreglarlo mueve píxel** →
`next-features` §13.
**Regla que confirma**: ante un diff inesperado, corre la sonda dos veces
sobre el mismo código ANTES de sospechar de tu cambio.
4. **`select-min-width` no tiene nodo en NINGUNA página del repo**: su único
consumidor es `[data-range-calendar-month-select]` / `-year-select`, y ninguna
demo monta esas partes (la de range-calendar renderiza un heading de texto; el
DateRangePicker importa los selectores del CALENDARIO, que llevan
`data-calendar-month-select`). Hueco de demo, registrado.
<!-- veredicto:end -->

Powered by TurnKey Linux.