uix(date-range-picker): la vista de década es suya y pasa a tokens; el calendario y el campo esperan su firma

Séptimo del eje theme-reach. Este componente es un híbrido de tres familias y el
contrato lo dice ahora explícitamente: la vista de década/mes es invención suya y
pasa a contrato público — separación, ancho, cabecera, navegación, rejilla y
celdas, con los estados del rango separados por nombre en vez de amontonados en
uno solo. Más el acento.

Lo que NO se toca tiene dueño y esperando firma: la mitad de calendario lee
`--calendar-*` y su corrección es la decisión de familia calendar que la
auditoría del sistema dejó registrada; la entrada segmentada lee `--field-*` y le
toca el mandato de composición de Field. Duplicar cualquiera de las dos bajo
prefijo propio habría sido justo el alias que la purga de 2026-07 mató.

Y el mismo defecto de prefijo que sus hermanos, aquí por partida doble: 44
referencias `--_date-field-*` y 9 `--_calendar-font-size` declaradas en ESTE CSS
con el nombre de otro componente. Con un DateField o un Calendar anidados se
habrían pisado. Renombradas, con el diff de computed en cero.

Verificación: diff de computed vacío sobre 493 valores en ocho estados ·
component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alpha-0.1-background
dev 2 months ago
parent ecb23d6a48
commit 07778b597a

@ -10,9 +10,9 @@
- **Medido**: 2026-08-20 · **162 recetas** con CSS + **8 componentes sin receta** = 170 fichas, el árbol entero de `eidos/components/`
- **La pregunta**: ¿cuánto de la apariencia de cada componente puede cambiar un tema **sin tocar el sistema ni la receta**?
- **Alcance global**: **37%** — 1819 de 4971 knobs pasan por un token público del componente
- **Reparto**: público 1819 · privado 885 · global 1663 · literal 604 · sistema transversal 232 _(fuera del ratio)_
- **Sin token público propio**: 57 · **alcance < 20 %**: 56 · **alcance 100 %**: 6 · **con eje `size`**: 79
- **Alcance global**: **37%** — 1841 de 4971 knobs pasan por un token público del componente
- **Reparto**: público 1841 · privado 894 · global 1633 · literal 603 · sistema transversal 232 _(fuera del ratio)_
- **Sin token público propio**: 56 · **alcance < 20 %**: 55 · **alcance 100 %**: 6 · **con eje `size`**: 79
## Cómo se lee
@ -79,24 +79,24 @@ theming §6.7 lo pone delante (`hover-bg`). Las fichas proponen la forma
| 7 | [time-range-picker](./time-range-picker.md) | 68 | 19% | 88 | 22 |
| 8 | [month-grid](./month-grid.md) | 58 | 0% | 61 | 0 |
| 9 | [year-grid](./year-grid.md) | 58 | 0% | 61 | 0 |
| 10 | [date-range-picker](./date-range-picker.md) | 52 | 0% | 55 | 0 |
| 11 | [command](./command.md) | 50 | 0% | 52 | 0 |
| 12 | [time-picker](./time-picker.md) | 47 | 18% | 59 | 16 |
| 13 | [media-player](./media-player.md) | 45 | 0% | 45 | 2 |
| 14 | [color-picker](./color-picker.md) | 43 | 46% | 82 | 54 |
| 15 | [table](./table.md) | 42 | 0% | 46 | 0 |
| 16 | [field-langs](./field-langs.md) | 39 | 0% | 41 | 0 |
| 17 | [tree-grid](./tree-grid.md) | 39 | 0% | 42 | 0 |
| 18 | [heading](./heading.md) | 36 | 0% | 36 | 0 |
| 19 | [gradient-picker](./gradient-picker.md) | 35 | 0% | 38 | 0 |
| 20 | [listbox](./listbox.md) | 35 | 0% | 38 | 0 |
| 10 | [command](./command.md) | 50 | 0% | 52 | 0 |
| 11 | [time-picker](./time-picker.md) | 47 | 18% | 59 | 16 |
| 12 | [media-player](./media-player.md) | 45 | 0% | 45 | 2 |
| 13 | [color-picker](./color-picker.md) | 43 | 46% | 82 | 54 |
| 14 | [table](./table.md) | 42 | 0% | 46 | 0 |
| 15 | [field-langs](./field-langs.md) | 39 | 0% | 41 | 0 |
| 16 | [tree-grid](./tree-grid.md) | 39 | 0% | 42 | 0 |
| 17 | [heading](./heading.md) | 36 | 0% | 36 | 0 |
| 18 | [gradient-picker](./gradient-picker.md) | 35 | 0% | 38 | 0 |
| 19 | [listbox](./listbox.md) | 35 | 0% | 38 | 0 |
| 20 | [field](./field.md) | 33 | 51% | 73 | 60 |
## Sin ningún token público propio (57)
## Sin ningún token público propio (56)
Ni una clave pública en `lib/recipes/base.ts` — alguno tiene privados forward
(`_palette-*`), que no son contrato: un tema no puede nombrarlos.
[`alert-dialog`](./alert-dialog.md) · [`announce`](./announce.md) · [`aspect-ratio`](./aspect-ratio.md) · [`auto-grid`](./auto-grid.md) · [`avatar`](./avatar.md) · [`card-group`](./card-group.md) · [`carousel`](./carousel.md) · [`cascade`](./cascade.md) · [`clipboard`](./clipboard.md) · [`code`](./code.md) · [`code-block`](./code-block.md) · [`command`](./command.md) · [`css-field`](./css-field.md) · [`date-picker`](./date-picker.md) · [`date-range-picker`](./date-range-picker.md) · [`display`](./display.md) · [`feed`](./feed.md) · [`field-langs`](./field-langs.md) · [`gradient-picker`](./gradient-picker.md) · [`grid-list`](./grid-list.md) · [`heading`](./heading.md) · [`highlight`](./highlight.md) · [`kbd`](./kbd.md) · [`knob`](./knob.md) · [`label`](./label.md) · [`link`](./link.md) · [`link-preview`](./link-preview.md) · [`listbox`](./listbox.md) · [`mark`](./mark.md) · [`mask-field`](./mask-field.md) · [`menu-dial`](./menu-dial.md) · [`mockup`](./mockup.md) · [`month-grid`](./month-grid.md) · [`motion`](./motion.md) · [`number-field`](./number-field.md) · [`palabras`](./palabras.md) · [`picker-shell`](./picker-shell.md) · [`range-calendar`](./range-calendar.md) · [`scroll-frames`](./scroll-frames.md) · [`skeleton`](./skeleton.md) · [`skin-media-player`](./skin-media-player.md) · [`spinner`](./spinner.md) · [`stack`](./stack.md) · [`table`](./table.md) · [`text`](./text.md) · [`text-blur`](./text-blur.md) · [`text-circular`](./text-circular.md) · [`text-focus`](./text-focus.md) · [`text-gradient`](./text-gradient.md) · [`text-scramble`](./text-scramble.md) · [`textarea`](./textarea.md) · [`tree-grid`](./tree-grid.md) · [`tree-view`](./tree-view.md) · [`virtual-grid`](./virtual-grid.md) · [`virtual-list`](./virtual-list.md) · [`wrap`](./wrap.md) · [`year-grid`](./year-grid.md)
[`alert-dialog`](./alert-dialog.md) · [`announce`](./announce.md) · [`aspect-ratio`](./aspect-ratio.md) · [`auto-grid`](./auto-grid.md) · [`avatar`](./avatar.md) · [`card-group`](./card-group.md) · [`carousel`](./carousel.md) · [`cascade`](./cascade.md) · [`clipboard`](./clipboard.md) · [`code`](./code.md) · [`code-block`](./code-block.md) · [`command`](./command.md) · [`css-field`](./css-field.md) · [`date-picker`](./date-picker.md) · [`display`](./display.md) · [`feed`](./feed.md) · [`field-langs`](./field-langs.md) · [`gradient-picker`](./gradient-picker.md) · [`grid-list`](./grid-list.md) · [`heading`](./heading.md) · [`highlight`](./highlight.md) · [`kbd`](./kbd.md) · [`knob`](./knob.md) · [`label`](./label.md) · [`link`](./link.md) · [`link-preview`](./link-preview.md) · [`listbox`](./listbox.md) · [`mark`](./mark.md) · [`mask-field`](./mask-field.md) · [`menu-dial`](./menu-dial.md) · [`mockup`](./mockup.md) · [`month-grid`](./month-grid.md) · [`motion`](./motion.md) · [`number-field`](./number-field.md) · [`palabras`](./palabras.md) · [`picker-shell`](./picker-shell.md) · [`range-calendar`](./range-calendar.md) · [`scroll-frames`](./scroll-frames.md) · [`skeleton`](./skeleton.md) · [`skin-media-player`](./skin-media-player.md) · [`spinner`](./spinner.md) · [`stack`](./stack.md) · [`table`](./table.md) · [`text`](./text.md) · [`text-blur`](./text-blur.md) · [`text-circular`](./text-circular.md) · [`text-focus`](./text-focus.md) · [`text-gradient`](./text-gradient.md) · [`text-scramble`](./text-scramble.md) · [`textarea`](./textarea.md) · [`tree-grid`](./tree-grid.md) · [`tree-view`](./tree-view.md) · [`virtual-grid`](./virtual-grid.md) · [`virtual-list`](./virtual-list.md) · [`wrap`](./wrap.md) · [`year-grid`](./year-grid.md)
## Tabla completa (162 recetas, por alcance ascendente)
@ -107,7 +107,6 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component
| [range-calendar](./range-calendar.md) | 0% | 98 | 0 | 7 | 84 | 4 | 3 | 0 | y |
| [month-grid](./month-grid.md) | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
| [year-grid](./year-grid.md) | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
| [date-range-picker](./date-range-picker.md) | 0% | 55 | 0 | 0 | 49 | 3 | 3 | 0 | y |
| [command](./command.md) | 0% | 52 | 0 | 9 | 35 | 6 | 2 | 0 | y |
| [table](./table.md) | 0% | 46 | 0 | 23 | 14 | 5 | 4 | 0 | y |
| [media-player](./media-player.md) | 0% | 45 | 0 | 0 | 37 | 8 | 0 | 2 | y |
@ -184,6 +183,7 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component
| [button-group](./button-group.md) | 40% | 5 | 2 | 0 | 0 | 3 | 0 | 1 | – |
| [badge](./badge.md) | 41% | 22 | 9 | 10 | 1 | 2 | 0 | 65 | y |
| [popover](./popover.md) | 42% | 51 | 20 | 6 | 22 | 0 | 3 | 36 | y |
| [date-range-picker](./date-range-picker.md) | 42% | 55 | 22 | 9 | 19 | 2 | 3 | 24 | y |
| [qr-code](./qr-code.md) | 43% | 7 | 3 | 0 | 0 | 4 | 0 | 10 | – |
| [navigation-menu](./navigation-menu.md) | 44% | 38 | 15 | 1 | 13 | 5 | 4 | 26 | y |
| [waveform](./waveform.md) | 45% | 11 | 5 | 1 | 1 | 4 | 0 | 10 | y |

@ -5,78 +5,57 @@
> Vista de conjunto: [README](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
- **Medido**: 2026-08-20 · **Alcance**: **0%** — 0 de 52 knobs por token público
- **Knobs de apariencia**: 55 — público 0 · privado 0 · global 49 · literal 3 · sistema 3 _(fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): **sin entrada en `base.ts`**
- **Medido**: 2026-08-20 · **Alcance**: **42%** — 22 de 52 knobs por token público
- **Knobs de apariencia**: 55 — público 22 · privado 9 · global 19 · literal 2 · sistema 3 _(fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 24 pública(s) — `accent-border`, `accent-track`, `accent-text`, `overview-gap`, `overview-width`, `overview-header-gap`, `overview-heading-fg`, `overview-heading-font-weight`, `overview-nav-size`, `overview-nav-radius`, `overview-nav-fg`, `overview-nav-font-size`, `hover-overview-nav-bg`, `overview-grid-gap`, `overview-cell-height`, `overview-cell-radius`, `overview-cell-fg`, `overview-cell-font-size`, `hover-overview-cell-bg`, `in-range-overview-cell-bg`, `in-range-overview-cell-fg`, `endpoint-overview-cell-bg`, `endpoint-overview-cell-fg`, `endpoint-overview-cell-border`
- **Eje `size`**: sí · **ficheros**: `date-range-picker-time.css`, `date-range-picker.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (49)
### 1.1 Directo a primitivo global (19)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `date-range-picker-time.css:11` | `.range-time` | `gap` | `calc(var(--space-8) + var(--space-1))` |
| 2 | `date-range-picker-time.css:12` | `.range-time` | `padding-block-start` | `var(--space-2)` |
| 3 | `date-range-picker-time.css:13` | `.range-time` | `border-block-start` | `var(--border-width, 1px) solid var(--color-neutral-border)` |
| 4 | `date-range-picker.css:26` | `[data-date-range-picker]` | `gap` | `var(--space-1-5) var(--_date-field-gap)` |
| 5 | `date-range-picker.css:29` | `[data-date-range-picker]` | `font-size` | `var(--_date-field-font-size)` |
| 6 | `date-range-picker.css:166` | `[data-date-range-picker][data-invalid] [data-field-control]` | `border-color` | `var(--field-control-border-invalid)` ⤴ prestado de `field` |
| 7 | `date-range-picker.css:186` | `[data-date-range-picker-trigger]` | `inline-size` | `var(--_date-field-height)` |
| 8 | `date-range-picker.css:187` | `[data-date-range-picker-trigger]` | `block-size` | `var(--_date-field-height)` |
| 9 | `date-range-picker.css:189` | `[data-date-range-picker-trigger]` | `border` | `var(--field-control-border-width) solid var(--field-control-border)` ⤴ prestado de `field` |
| 10 | `date-range-picker.css:190` | `[data-date-range-picker-trigger]` | `border-radius` | `var(--field-control-radius)` ⤴ prestado de `field` |
| 11 | `date-range-picker.css:191` | `[data-date-range-picker-trigger]` | `background` | `var(--field-control-bg)` ⤴ prestado de `field` |
| 12 | `date-range-picker.css:202` | `[data-date-range-picker-trigger]:hover` | `border-color` | `var(--_date-field-accent-border)` |
| 13 | `date-range-picker.css:203` | `[data-date-range-picker-trigger]:hover` | `background` | `var(--_date-field-accent-track)` |
| 14 | `date-range-picker.css:204` | `[data-date-range-picker-trigger]:hover` | `color` | `var(--_date-field-accent-text)` |
| 15 | `date-range-picker.css:208` | `[data-date-range-picker-trigger]:focus-visible` | `border-color` | `var(--_date-field-accent-border)` |
| 16 | `date-range-picker.css:217` | `[data-date-range-picker-trigger][data-disabled], [data-date-range-picker-trigger]:disabled` | `opacity` | `var(--field-disabled-opacity)` ⤴ prestado de `field` |
| 17 | `date-range-picker.css:232` | `[data-date-range-field-input] [data-date-range-picker-trigger]` | `inline-size` | `var(--field-segment-height)` ⤴ prestado de `field` |
| 18 | `date-range-picker.css:233` | `[data-date-range-field-input] [data-date-range-picker-trigger]` | `block-size` | `var(--field-segment-height)` ⤴ prestado de `field` |
| 19 | `date-range-picker.css:237` | `[data-date-range-field-input] [data-date-range-picker-trigger]` | `border-radius` | `var(--radius-sm)` |
| 20 | `date-range-picker.css:248` | `[data-date-range-field-input] [data-date-range-picker-trigger]:hover, [data-date-range-field-input] [data-date-range-picker-trigger]:focus-visible` | `background` | `var(--field-segment-active-bg)` ⤴ prestado de `field` |
| 21 | `date-range-picker.css:249` | `[data-date-range-field-input] [data-date-range-picker-trigger]:hover, [data-date-range-field-input] [data-date-range-picker-trigger]:focus-visible` | `color` | `var(--field-segment-active-text)` ⤴ prestado de `field` |
| 22 | `date-range-picker.css:271` | `[data-date-range-picker-calendar][data-range-calendar]` | `gap` | `var(--calendar-gap)` ⤴ prestado de `calendar` |
| 23 | `date-range-picker.css:279` | `[data-date-range-picker-calendar][data-range-calendar]` | `color` | `var(--calendar-color)` ⤴ prestado de `calendar` |
| 24 | `date-range-picker.css:280` | `[data-date-range-picker-calendar][data-range-calendar]` | `font-family` | `var(--calendar-font-family)` ⤴ prestado de `calendar` |
| 25 | `date-range-picker.css:281` | `[data-date-range-picker-calendar][data-range-calendar]` | `font-size` | `var(--_calendar-font-size)` |
| 26 | `date-range-picker.css:282` | `[data-date-range-picker-calendar][data-range-calendar]` | `line-height` | `var(--calendar-line-height)` ⤴ prestado de `calendar` |
| 27 | `date-range-picker.css:383` | `[data-date-range-picker-year-view], [data-date-range-picker-month-view]` | `gap` | `var(--space-3)` |
| 28 | `date-range-picker.css:392` | `[data-date-range-picker-year-view-header], [data-date-range-picker-month-view-header]` | `gap` | `var(--space-2)` |
| 29 | `date-range-picker.css:397` | `[data-date-range-picker-year-view-heading], [data-date-range-picker-month-view-heading]` | `font-weight` | `var(--font-weight-semibold)` |
| 30 | `date-range-picker.css:398` | `[data-date-range-picker-year-view-heading], [data-date-range-picker-month-view-heading]` | `color` | `var(--color-content-primary)` |
| 31 | `date-range-picker.css:405` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `min-block-size` | `var(--control-height-sm)` |
| 32 | `date-range-picker.css:406` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `min-inline-size` | `var(--control-height-sm)` |
| 33 | `date-range-picker.css:407` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `border-radius` | `var(--radius-md)` |
| 34 | `date-range-picker.css:408` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `border` | `var(--border-width) solid transparent` |
| 35 | `date-range-picker.css:410` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `color` | `var(--color-content-primary)` |
| 36 | `date-range-picker.css:413` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `font-size` | `var(--font-size-md)` |
| 37 | `date-range-picker.css:420` | `[data-date-range-picker-year-view-prev]:hover, [data-date-range-picker-year-view-next]:hover, [data-date-range-picker-month-view-prev]:hover, [data-date-range-picker-month-view-next]:hover` | `background` | `var(--color-surface-overlay)` |
| 38 | `date-range-picker.css:427` | `[data-date-range-picker-year-view-grid], [data-date-range-picker-month-view-grid]` | `gap` | `var(--space-2)` |
| 39 | `date-range-picker.css:432` | `[data-date-range-picker-year-view-cell], [data-date-range-picker-month-view-cell]` | `min-block-size` | `var(--control-height-md)` |
| 40 | `date-range-picker.css:433` | `[data-date-range-picker-year-view-cell], [data-date-range-picker-month-view-cell]` | `border-radius` | `var(--radius-md)` |
| 41 | `date-range-picker.css:434` | `[data-date-range-picker-year-view-cell], [data-date-range-picker-month-view-cell]` | `border` | `var(--border-width) solid transparent` |
| 42 | `date-range-picker.css:436` | `[data-date-range-picker-year-view-cell], [data-date-range-picker-month-view-cell]` | `color` | `var(--color-content-primary)` |
| 43 | `date-range-picker.css:439` | `[data-date-range-picker-year-view-cell], [data-date-range-picker-month-view-cell]` | `font-size` | `var(--font-size-sm)` |
| 44 | `date-range-picker.css:447` | `[data-date-range-picker-year-view-cell]:hover, [data-date-range-picker-month-view-cell]:hover` | `background` | `var(--color-surface-overlay)` |
| 45 | `date-range-picker.css:462` | `[data-date-range-picker-year-view-cell][data-in-range], [data-date-range-picker-month-view-cell][data-in-range]` | `background` | `var(--color-primary-track)` |
| 46 | `date-range-picker.css:463` | `[data-date-range-picker-year-view-cell][data-in-range], [data-date-range-picker-month-view-cell][data-in-range]` | `color` | `var(--color-primary-text)` |
| 47 | `date-range-picker.css:471` | `[data-date-range-picker-year-view-cell][data-range-start], [data-date-range-picker-year-view-cell][data-range-end], [data-date-range-picker-month-view-cell][data-range-start], [data-date-range-picker-month-view-cell][data-range-end]` | `background` | `var(--color-primary-solid)` |
| 48 | `date-range-picker.css:472` | `[data-date-range-picker-year-view-cell][data-range-start], [data-date-range-picker-year-view-cell][data-range-end], [data-date-range-picker-month-view-cell][data-range-start], [data-date-range-picker-month-view-cell][data-range-end]` | `color` | `var(--color-content-on-solid)` |
| 49 | `date-range-picker.css:473` | `[data-date-range-picker-year-view-cell][data-range-start], [data-date-range-picker-year-view-cell][data-range-end], [data-date-range-picker-month-view-cell][data-range-start], [data-date-range-picker-month-view-cell][data-range-end]` | `border-color` | `var(--color-primary-border)` |
### 1.2 A través de un privado (0)
_Ninguno._
### 1.3 Literales (3)
| 4 | `date-range-picker.css:166` | `[data-date-range-picker][data-invalid] [data-field-control]` | `border-color` | `var(--field-control-border-invalid)` ⤴ prestado de `field` |
| 5 | `date-range-picker.css:189` | `[data-date-range-picker-trigger]` | `border` | `var(--field-control-border-width) solid var(--field-control-border)` ⤴ prestado de `field` |
| 6 | `date-range-picker.css:190` | `[data-date-range-picker-trigger]` | `border-radius` | `var(--field-control-radius)` ⤴ prestado de `field` |
| 7 | `date-range-picker.css:191` | `[data-date-range-picker-trigger]` | `background` | `var(--field-control-bg)` ⤴ prestado de `field` |
| 8 | `date-range-picker.css:217` | `[data-date-range-picker-trigger][data-disabled], [data-date-range-picker-trigger]:disabled` | `opacity` | `var(--field-disabled-opacity)` ⤴ prestado de `field` |
| 9 | `date-range-picker.css:232` | `[data-date-range-field-input] [data-date-range-picker-trigger]` | `inline-size` | `var(--field-segment-height)` ⤴ prestado de `field` |
| 10 | `date-range-picker.css:233` | `[data-date-range-field-input] [data-date-range-picker-trigger]` | `block-size` | `var(--field-segment-height)` ⤴ prestado de `field` |
| 11 | `date-range-picker.css:237` | `[data-date-range-field-input] [data-date-range-picker-trigger]` | `border-radius` | `var(--radius-sm)` |
| 12 | `date-range-picker.css:248` | `[data-date-range-field-input] [data-date-range-picker-trigger]:hover, [data-date-range-field-input] [data-date-range-picker-trigger]:focus-visible` | `background` | `var(--field-segment-active-bg)` ⤴ prestado de `field` |
| 13 | `date-range-picker.css:249` | `[data-date-range-field-input] [data-date-range-picker-trigger]:hover, [data-date-range-field-input] [data-date-range-picker-trigger]:focus-visible` | `color` | `var(--field-segment-active-text)` ⤴ prestado de `field` |
| 14 | `date-range-picker.css:271` | `[data-date-range-picker-calendar][data-range-calendar]` | `gap` | `var(--calendar-gap)` ⤴ prestado de `calendar` |
| 15 | `date-range-picker.css:279` | `[data-date-range-picker-calendar][data-range-calendar]` | `color` | `var(--calendar-color)` ⤴ prestado de `calendar` |
| 16 | `date-range-picker.css:280` | `[data-date-range-picker-calendar][data-range-calendar]` | `font-family` | `var(--calendar-font-family)` ⤴ prestado de `calendar` |
| 17 | `date-range-picker.css:282` | `[data-date-range-picker-calendar][data-range-calendar]` | `line-height` | `var(--calendar-line-height)` ⤴ prestado de `calendar` |
| 18 | `date-range-picker.css:407` | `[data-date-range-picker-year-view-prev], [data-date-range-picker-year-view-next], [data-date-range-picker-month-view-prev], [data-date-range-picker-month-view-next]` | `border` | `var(--border-width) solid transparent` |
| 19 | `date-range-picker.css:433` | `[data-date-range-picker-year-view-cell], [data-date-range-picker-month-view-cell]` | `border` | `var(--border-width) solid transparent` |
### 1.2 A través de un privado (9)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `date-range-picker.css:26` | `[data-date-range-picker]` | `gap` | `var(--space-1-5) var(--_date-range-picker-field-gap)` |
| 2 | `date-range-picker.css:29` | `[data-date-range-picker]` | `font-size` | `var(--_date-range-picker-field-font-size)` |
| 3 | `date-range-picker.css:186` | `[data-date-range-picker-trigger]` | `inline-size` | `var(--_date-range-picker-field-height)` |
| 4 | `date-range-picker.css:187` | `[data-date-range-picker-trigger]` | `block-size` | `var(--_date-range-picker-field-height)` |
| 5 | `date-range-picker.css:202` | `[data-date-range-picker-trigger]:hover` | `border-color` | `var(--_date-range-picker-field-accent-border)` |
| 6 | `date-range-picker.css:203` | `[data-date-range-picker-trigger]:hover` | `background` | `var(--_date-range-picker-field-accent-track)` |
| 7 | `date-range-picker.css:204` | `[data-date-range-picker-trigger]:hover` | `color` | `var(--_date-range-picker-field-accent-text)` |
| 8 | `date-range-picker.css:208` | `[data-date-range-picker-trigger]:focus-visible` | `border-color` | `var(--_date-range-picker-field-accent-border)` |
| 9 | `date-range-picker.css:281` | `[data-date-range-picker-calendar][data-range-calendar]` | `font-size` | `var(--_date-range-picker-calendar-font-size)` |
### 1.3 Literales (2)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `date-range-picker.css:27` | `[data-date-range-picker]` | `inline-size` | `100%` |
| 2 | `date-range-picker.css:272` | `[data-date-range-picker-calendar][data-range-calendar]` | `inline-size` | `max-content` |
| 3 | `date-range-picker.css:384` | `[data-date-range-picker-year-view], [data-date-range-picker-month-view]` | `inline-size` | `min(20rem, 100%)` |
## 2. Sistema transversal (3) — informativo, fuera del ratio
@ -86,11 +65,19 @@ Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2).
| ---: | --- | --- | --- | --- |
| 1 | `date-range-picker.css:170` | `[data-date-range-picker][data-disabled]` | `opacity` | `var(--opacity-disabled)` |
| 2 | `date-range-picker.css:210` | `[data-date-range-picker-trigger]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
| 3 | `date-range-picker.css:491` | `[data-date-range-picker-year-view-cell]:focus-visible, [data-date-range-picker-month-view-cell]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--color-primary-border)` |
| 3 | `date-range-picker.css:490` | `[data-date-range-picker-year-view-cell]:focus-visible, [data-date-range-picker-month-view-cell]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--color-primary-border)` |
## 3. Privados de la receta — ¿de dónde sale su valor?
_La receta no declara privados propios en su CSS._
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_date-range-picker-field-height` | 4 | `var(--field-control-height-md)`, `var(--field-control-height-xs)`, `var(--field-control-height-sm)`, `var(--field-control-height-lg)` | global | no |
| `--_date-range-picker-field-gap` | 4 | `var(--space-1)`, `var(--space-0-5)`, `var(--space-1-5)` | global | no |
| `--_date-range-picker-field-font-size` | 4 | `var(--field-control-font-size-md)`, `var(--field-control-font-size-xs)`, `var(--field-control-font-size-sm)`, `var(--field-control-font-size-lg)` | global | no |
| `--_date-range-picker-field-accent-border` | 8 | `var(--date-range-picker-accent-border)`, `var(--color-secondary-border)`, `var(--color-neutral-border)`, `var(--color-affirm-border)`, `var(--color-fulfill-border)`, `var(--color-risk-border)` …(+2) | global, public | no |
| `--_date-range-picker-field-accent-track` | 8 | `var(--date-range-picker-accent-track)`, `var(--color-secondary-track)`, `var(--color-neutral-track)`, `var(--color-affirm-track)`, `var(--color-fulfill-track)`, `var(--color-risk-track)` …(+2) | global, public | no |
| `--_date-range-picker-field-accent-text` | 8 | `var(--date-range-picker-accent-text)`, `var(--color-secondary-text)`, `var(--color-neutral-text)`, `var(--color-affirm-text)`, `var(--color-fulfill-text)`, `var(--color-risk-text)` …(+2) | global, public | no |
| `--_date-range-picker-calendar-font-size` | 8 | `var(--calendar-font-size-md)`, `var(--calendar-font-size-xs)`, `var(--calendar-font-size-sm)`, `var(--calendar-font-size-lg)` | global | no |
## 4. Propuesta de corrección
@ -99,7 +86,7 @@ _La receta no declara privados propios en su CSS._
- **Consume tokens públicos de `calendar`, `field`.** Un token prestado importa la semántica de su dueño: la corrección no es duplicarlo con prefijo propio, sino la decisión de familia que la auditoría de fase 1 dejó registrada (`theming-audit.md` §B, familia calendar).
- **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` (38)
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (37)
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
@ -109,44 +96,43 @@ no distingue lo que debería — se marca `⚠`.
| token (`--date-range-picker-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `year-view-cell-fg` | `root` | ⚠ `var(--color-content-primary)` / `var(--color-primary-text)` / `var(--color-content-on-solid)` | 3 |
| `gap` | `root` | ⚠ `calc(var(--space-8) + var(--space-1))` / `var(--space-1-5) var(--_date-field-gap)` | 2 |
| `trigger-width` | `root` | ⚠ `var(--_date-field-height)` / `var(--field-segment-height)` | 2 |
| `trigger-height` | `root` | ⚠ `var(--_date-field-height)` / `var(--field-segment-height)` | 2 |
| `hover-trigger-bg` | `root` | ⚠ `var(--date-range-picker-accent-track)` / `var(--color-secondary-track)` / `var(--color-neutral-track)` / `var(--color-affirm-track)` / `var(--color-fulfill-track)` / `var(--color-risk-track)` / `var(--color-threat-track)` / `var(--color-loss-track)` / `var(--field-segment-active-bg)` | 9 |
| `hover-trigger-fg` | `root` | ⚠ `var(--date-range-picker-accent-text)` / `var(--color-secondary-text)` / `var(--color-neutral-text)` / `var(--color-affirm-text)` / `var(--color-fulfill-text)` / `var(--color-risk-text)` / `var(--color-threat-text)` / `var(--color-loss-text)` / `var(--field-segment-active-text)` | 9 |
| `hover-trigger-border` | `root` | ⚠ `var(--date-range-picker-accent-border)` / `var(--color-secondary-border)` / `var(--color-neutral-border)` / `var(--color-affirm-border)` / `var(--color-fulfill-border)` / `var(--color-risk-border)` / `var(--color-threat-border)` / `var(--color-loss-border)` | 8 |
| `trigger-border` | `root` | ⚠ `var(--date-range-picker-accent-border)` / `var(--color-secondary-border)` / `var(--color-neutral-border)` / `var(--color-affirm-border)` / `var(--color-fulfill-border)` / `var(--color-risk-border)` / `var(--color-threat-border)` / `var(--color-loss-border)` | 8 |
| `trigger-radius` | `root` | ⚠ `var(--field-control-radius)` / `var(--radius-sm)` | 2 |
| `hover-trigger-bg` | `root` | ⚠ `var(--_date-field-accent-track)` / `var(--field-segment-active-bg)` | 2 |
| `hover-trigger-fg` | `root` | ⚠ `var(--_date-field-accent-text)` / `var(--field-segment-active-text)` | 2 |
| `year-view-cell-bg` | `root` | ⚠ `var(--color-primary-track)` / `var(--color-primary-solid)` | 2 |
| `calendar-font-size-md` | `size:md` | `var(--calendar-font-size-md)` | 2 |
| `calendar-font-size-xs` | `size:xs` | `var(--calendar-font-size-xs)` | 2 |
| `calendar-font-size-sm` | `size:sm` | `var(--calendar-font-size-sm)` | 2 |
| `calendar-font-size-lg` | `size:lg` | `var(--calendar-font-size-lg)` | 2 |
| `gap` | `root` | `calc(var(--space-8) + var(--space-1))` | 1 |
| `padding-block` | `root` | `var(--space-2)` | 1 |
| `font-size` | `root` | `var(--_date-field-font-size)` | 1 |
| `gap-md` | `size:md` | `var(--space-1)` | 1 |
| `gap-xs` | `size:xs` | `var(--space-0-5)` | 1 |
| `gap-sm` | `size:sm` | `var(--space-0-5)` | 1 |
| `gap-lg` | `size:lg` | `var(--space-1-5)` | 1 |
| `font-size-md` | `size:md` | `var(--field-control-font-size-md)` | 1 |
| `font-size-xs` | `size:xs` | `var(--field-control-font-size-xs)` | 1 |
| `font-size-sm` | `size:sm` | `var(--field-control-font-size-sm)` | 1 |
| `font-size-lg` | `size:lg` | `var(--field-control-font-size-lg)` | 1 |
| `invalid-border` | `root` | `var(--field-control-border-invalid)` | 1 |
| `trigger-width-md` | `size:md` | `var(--field-control-height-md)` | 1 |
| `trigger-width-xs` | `size:xs` | `var(--field-control-height-xs)` | 1 |
| `trigger-width-sm` | `size:sm` | `var(--field-control-height-sm)` | 1 |
| `trigger-width-lg` | `size:lg` | `var(--field-control-height-lg)` | 1 |
| `trigger-height-md` | `size:md` | `var(--field-control-height-md)` | 1 |
| `trigger-height-xs` | `size:xs` | `var(--field-control-height-xs)` | 1 |
| `trigger-height-sm` | `size:sm` | `var(--field-control-height-sm)` | 1 |
| `trigger-height-lg` | `size:lg` | `var(--field-control-height-lg)` | 1 |
| `trigger-bg` | `root` | `var(--field-control-bg)` | 1 |
| `hover-trigger-border` | `root` | `var(--_date-field-accent-border)` | 1 |
| `trigger-border` | `root` | `var(--_date-field-accent-border)` | 1 |
| `disabled-trigger-opacity` | `root` | `var(--field-disabled-opacity)` | 1 |
| `trigger-width` | `root` | `var(--field-segment-height)` | 1 |
| `trigger-height` | `root` | `var(--field-segment-height)` | 1 |
| `calendar-gap` | `root` | `var(--calendar-gap)` | 1 |
| `calendar-width` | `root` | `max-content` | 1 |
| `calendar-fg` | `root` | `var(--calendar-color)` | 1 |
| `calendar-font-family` | `root` | `var(--calendar-font-family)` | 1 |
| `calendar-font-size` | `root` | `var(--_calendar-font-size)` | 1 |
| `calendar-line-height` | `root` | `var(--calendar-line-height)` | 1 |
| `year-view-gap` | `root` | `var(--space-3)` | 1 |
| `year-view-width` | `root` | `min(20rem, 100%)` | 1 |
| `year-view-header-gap` | `root` | `var(--space-2)` | 1 |
| `year-view-heading-font-weight` | `root` | `var(--font-weight-semibold)` | 1 |
| `year-view-heading-fg` | `root` | `var(--color-content-primary)` | 1 |
| `year-view-prev-height` | `root` | `var(--control-height-sm)` | 1 |
| `year-view-prev-width` | `root` | `var(--control-height-sm)` | 1 |
| `year-view-prev-radius` | `root` | `var(--radius-md)` | 1 |
| `year-view-prev-fg` | `root` | `var(--color-content-primary)` | 1 |
| `year-view-prev-font-size` | `root` | `var(--font-size-md)` | 1 |
| `hover-year-view-prev-bg` | `root` | `var(--color-surface-overlay)` | 1 |
| `year-view-grid-gap` | `root` | `var(--space-2)` | 1 |
| `year-view-cell-height` | `root` | `var(--control-height-md)` | 1 |
| `year-view-cell-radius` | `root` | `var(--radius-md)` | 1 |
| `year-view-cell-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `hover-year-view-cell-bg` | `root` | `var(--color-surface-overlay)` | 1 |
| `year-view-cell-border` | `root` | `var(--color-primary-border)` | 1 |
### 4.2 Sin nombre mecánico (5)
@ -154,9 +140,16 @@ no distingue lo que debería — se marca `⚠`.
- **⚠ 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: `border` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 3: `border`.
### 4.3 Avisos sobre los tokens propuestos (1)
### 4.3 Avisos sobre los tokens propuestos (8)
- **⚠ decisión: el valor es una expresión — el token puede llevar la expresión entera o sólo su término variable** — `--date-range-picker-gap`, `--date-range-picker-year-view-width`
- **⚠ decisión: el valor es una expresión — el token puede llevar la expresión entera o sólo su término variable** — `--date-range-picker-gap`
- **el privado `--_date-range-picker-field-gap` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-gap-md`, `--date-range-picker-gap-xs`, `--date-range-picker-gap-sm`, `--date-range-picker-gap-lg`
- **el privado `--_date-range-picker-field-font-size` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-font-size-md`, `--date-range-picker-font-size-xs`, `--date-range-picker-font-size-sm`, `--date-range-picker-font-size-lg`
- **el privado `--_date-range-picker-field-height` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-trigger-width-md`, `--date-range-picker-trigger-width-xs`, `--date-range-picker-trigger-width-sm`, `--date-range-picker-trigger-width-lg`, `--date-range-picker-trigger-height-md`, `--date-range-picker-trigger-height-xs`, `--date-range-picker-trigger-height-sm`, `--date-range-picker-trigger-height-lg`
- **el privado `--_date-range-picker-field-accent-border` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-hover-trigger-border`, `--date-range-picker-trigger-border`
- **el privado `--_date-range-picker-field-accent-track` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-hover-trigger-bg`
- **el privado `--_date-range-picker-field-accent-text` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-hover-trigger-fg`
- **el privado `--_date-range-picker-calendar-font-size` debe pasar a leer este público (o desaparecer)** — `--date-range-picker-calendar-font-size-md`, `--date-range-picker-calendar-font-size-xs`, `--date-range-picker-calendar-font-size-sm`, `--date-range-picker-calendar-font-size-lg`
### 4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)
@ -210,4 +203,28 @@ hereda los defectos de ambas:
field-composition · D-TH.4 (B7). Sin esas dos firmas, aquí sólo procede el
renombrado de privados + `year-view-*`.
---
**EJECUTADO 2026-08-20 (exactamente lo que no dependía de otra firma).** Alcance
**0 % → 42 %** · contrato **0 → 22 claves públicas**.
Hecho, los dos puntos que la revisión marcó como accionables:
1. **Renombrado de privados con prefijo ajeno**: 44 `--_date-field-*` y 9
`--_calendar-font-size` que este CSS declaraba con el nombre de OTRO
componente — se habrían cruzado con un DateField o un Calendar anidados.
Ahora `--_date-range-picker-*`.
2. **La vista de década / mes a contrato**: `overview-*` (separación, ancho,
cabecera, navegación, rejilla, celdas) con los estados del rango separados
por nombre (`in-range-overview-cell-*`, `endpoint-overview-cell-*`), que es
justo la colisión que la propuesta automática tenía en `year-view-cell-fg`.
Y el acento a público.
No hecho, con dueño: la mitad de calendario espera la **decisión de familia
calendar** (§B) y la de campo el **mandato de composición de Field** (§5.3-3).
Verificación: **diff de computed = 0** sobre 493 valores en 8 estados ·
`component:audit` PASS · suite eidos sin rojos nuevos · `rtl:check` 0 ·
`docs:check` 0.
<!-- veredicto:end -->

@ -37,19 +37,19 @@ Incidencia 2026-05-20 (parcialmente atendida):
## Comparativa
| Aspecto | UIX DateRangePicker | React Aria | Bits UI | Ark UI |
| --- | --- | --- | --- | --- |
| Composición | Field + Popover + RangeCalendar | Field + Popover + RangeCalendar | Field + Popover + RangeCalendar | Field + Popover + RangeCalendar |
| `minDays` / `maxDays` | ✓ | ✗ | ✗ | ✗ |
| `allowSingleDay` | ✓ | ✗ | ✗ | ✗ |
| `isDateHoliday` | ✓ | ✗ | ✗ | ✗ |
| Segmentos `readonly` por endpoint | ✓ | ✗ | parcial | ✗ |
| Eventos sema declarativos | ✓ (`commit-reset` propio + `emerge-*` del Popover) | n/a | n/a | n/a |
| `data-last-action` para tinte de salida | ✓ | ✗ | ✗ | ✗ |
| Modos modal/no-modal | ✓ | ✓ | ✗ | ✗ |
| Auto-page al seleccionar en mes final | ✗ (deliberado) | ✗ | ✓ | ✓ |
| Limpieza por endpoint individual | ✓ | parcial | ✗ | ✗ |
| Distinción visual start/end | ✓ (stripe + swap) | ✓ | parcial | parcial |
| Aspecto | UIX DateRangePicker | React Aria | Bits UI | Ark UI |
| --------------------------------------- | -------------------------------------------------- | ------------------------------- | ------------------------------- | ------------------------------- |
| Composición | Field + Popover + RangeCalendar | Field + Popover + RangeCalendar | Field + Popover + RangeCalendar | Field + Popover + RangeCalendar |
| `minDays` / `maxDays` | ✓ | ✗ | ✗ | ✗ |
| `allowSingleDay` | ✓ | ✗ | ✗ | ✗ |
| `isDateHoliday` | ✓ | ✗ | ✗ | ✗ |
| Segmentos `readonly` por endpoint | ✓ | ✗ | parcial | ✗ |
| Eventos sema declarativos | ✓ (`commit-reset` propio + `emerge-*` del Popover) | n/a | n/a | n/a |
| `data-last-action` para tinte de salida | ✓ | ✗ | ✗ | ✗ |
| Modos modal/no-modal | ✓ | ✓ | ✗ | ✗ |
| Auto-page al seleccionar en mes final | ✗ (deliberado) | ✗ | ✓ | ✓ |
| Limpieza por endpoint individual | ✓ | parcial | ✗ | ✗ |
| Distinción visual start/end | ✓ (stripe + swap) | ✓ | parcial | parcial |
## Decisiones
@ -77,11 +77,31 @@ Incidencia 2026-05-20 (parcialmente atendida):
`commit-select-range`, `commit-reset`, `shift-navigate`) los emite
`range-calendar`; el picker no los duplica.
## Talla y tema (theme-reach 2026-08-20)
El componente es un híbrido de tres familias, y el contrato lo refleja:
- **Suyo** — la vista de década / mes (`overview-*`: separación, ancho, cabecera,
navegación, rejilla y celdas, con `in-range-` y `endpoint-` para los estados
del rango) y el acento (`accent-border` / `-track` / `-text`). Eso es lo que
pasa a contrato público `--date-range-picker-*`.
- **Del calendario** — la mitad de arriba lee `--calendar-*`. No se duplica: la
corrección es la decisión de familia calendar registrada en
`docs/audit/theming-audit.md` §B (formalizar `calendar` como capa compartida),
que sigue sin firmar.
- **Del campo** — la entrada segmentada lee `--field-*`. Igual: el mandato de
composición de Field (§5.3-3).
Corregido de paso: 44 referencias `--_date-field-*` y 9 `--_calendar-font-size`
que este CSS declaraba con el prefijo de OTRO componente (y que se cruzarían con
un DateField o un Calendar anidados) pasan a `--_date-range-picker-*`, con el
diff de computed en cero.
## Gaps
| ID | Disposición | Detalle |
| --- | --- | --- |
| Demo: `start segments` / `end segments` / `paged nav` | **diferir** | Mover a sección API-only del README; quitar de los controles interactivos del demo si no mejoran el preview. |
| `data-disabled-reason` en celdas para min/maxDays | **diferir** | El cell ya emite `data-disabled`; el "porqué" (out-of-bounds vs range-length) puede añadirse vía `data-disabled-reason` para que el screen reader explique. No bloqueante. |
| Tests browser-level del flujo completo | **implementar** | Falta cobertura visual (Playwright) del flujo abrir → seleccionar start → seleccionar end → commit/dismiss. |
| El botón `Clear` es MUDO | **implementar** | El morfo declara `commit-reset`, pero `clear()` en el provider sólo hace `value.current = undefined` — nunca llama a `runtime.trigger('commit-reset')`. Afecta por igual a date-picker, time-picker, time-range-picker y color-picker: o se cablea el trigger en los cinco, o el evento sale del morfo. Medido 2026-08-11. |
| ID | Disposición | Detalle |
| ----------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Demo: `start segments` / `end segments` / `paged nav` | **diferir** | Mover a sección API-only del README; quitar de los controles interactivos del demo si no mejoran el preview. |
| `data-disabled-reason` en celdas para min/maxDays | **diferir** | El cell ya emite `data-disabled`; el "porqué" (out-of-bounds vs range-length) puede añadirse vía `data-disabled-reason` para que el screen reader explique. No bloqueante. |
| Tests browser-level del flujo completo | **implementar** | Falta cobertura visual (Playwright) del flujo abrir → seleccionar start → seleccionar end → commit/dismiss. |
| El botón `Clear` es MUDO | **implementar** | El morfo declara `commit-reset`, pero `clear()` en el provider sólo hace `value.current = undefined` — nunca llama a `runtime.trigger('commit-reset')`. Afecta por igual a date-picker, time-picker, time-range-picker y color-picker: o se cablea el trigger en los cinco, o el evento sale del morfo. Medido 2026-08-11. |

@ -1,9 +1,5 @@
import { getContext, setContext } from 'svelte';
import type {
DateRangePickerColor,
DateRangePickerSize,
DateRangePickerVariant
} from './types';
import type { DateRangePickerColor, DateRangePickerSize, DateRangePickerVariant } from './types';
import type { Granularity, TimeValue } from '$libs/days';
const DATE_RANGE_PICKER_VISUAL_CONTEXT = Symbol('uix.eidos.date-range-picker.visual');

@ -4,13 +4,16 @@
import { composeInlineStyle } from '$uix/eidos/lib/style';
import { resolveComponentColor } from '$uix/eidos/lib/component-color';
import { getDateRangePickerVisualContext } from './context.svelte';
import type {
DateRangePickerCalendarProps,
DateRangePickerCalendarSnippetProps
} from './types';
import type { DateRangePickerCalendarProps, DateRangePickerCalendarSnippetProps } from './types';
let { size, variant, color, style, children: bodyContent, ...rest }: DateRangePickerCalendarProps =
$props();
let {
size,
variant,
color,
style,
children: bodyContent,
...rest
}: DateRangePickerCalendarProps = $props();
const eidos = ActiveEidos.require();
const visual = getDateRangePickerVisualContext();

@ -16,7 +16,9 @@
}: DateRangePickerPrevButtonProps = $props();
const eidos = ActiveEidos.require();
const label = $derived(ariaLabel ?? eidos.langs.ts('#?common.calendar.prev-month|Previous month'));
const label = $derived(
ariaLabel ?? eidos.langs.ts('#?common.calendar.prev-month|Previous month')
);
</script>
<DateRangePicker.PrevButton {...rest}>

@ -10,10 +10,7 @@
import PickerTimeRow from '$uix/eidos/components/picker-shell/picker-time-row.svelte';
import { granularityHasTime } from '$uix/eidos/components/picker-shell/picker-time';
import './date-range-picker-time.css';
import {
getDateRangePickerVisualContext,
getDateRangePickerTimeBridge
} from './context.svelte';
import { getDateRangePickerVisualContext, getDateRangePickerTimeBridge } from './context.svelte';
import type { DateRangePickerTimeProps } from './types';
let { startLabel, endLabel }: DateRangePickerTimeProps = $props();

@ -4,16 +4,16 @@
gap/font need field-shaped dims. These privates SOURCE from the FIELD FAMILY
public tokens (`--field-control-*`), never a sibling date-field recipe token.
The wrap column-gap keeps the tighter segment-gap rhythm (`--space-1`). */
--_date-field-height: var(--field-control-height-md);
--_date-field-gap: var(--space-1);
--_date-field-font-size: var(--field-control-font-size-md);
--_date-field-accent-border: var(--color-primary-border);
--_date-field-accent-track: var(--color-primary-track);
--_date-field-accent-text: var(--color-primary-text);
--_date-range-picker-field-height: var(--field-control-height-md);
--_date-range-picker-field-gap: var(--space-1);
--_date-range-picker-field-font-size: var(--field-control-font-size-md);
--_date-range-picker-field-accent-border: var(--date-range-picker-accent-border);
--_date-range-picker-field-accent-track: var(--date-range-picker-accent-track);
--_date-range-picker-field-accent-text: var(--date-range-picker-accent-text);
--_calendar-padding: var(--calendar-padding-md);
--_calendar-control-size: var(--calendar-control-size-md);
--_calendar-day-size: var(--calendar-day-size-md);
--_calendar-font-size: var(--calendar-font-size-md);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-md);
--_calendar-accent-solid: var(--color-primary-solid);
--_calendar-accent-solid-hover: var(--color-primary-solid-hover);
--_calendar-accent-track: var(--color-primary-track);
@ -23,46 +23,46 @@
display: flex;
flex-wrap: wrap;
align-items: end;
gap: var(--space-1-5) var(--_date-field-gap);
gap: var(--space-1-5) var(--_date-range-picker-field-gap);
inline-size: 100%;
min-inline-size: 0;
font-size: var(--_date-field-font-size);
font-size: var(--_date-range-picker-field-font-size);
}
[data-date-range-picker][data-size='xs'] {
--_date-field-height: var(--field-control-height-xs);
--_date-field-gap: var(--space-0-5);
--_date-field-font-size: var(--field-control-font-size-xs);
--_date-range-picker-field-height: var(--field-control-height-xs);
--_date-range-picker-field-gap: var(--space-0-5);
--_date-range-picker-field-font-size: var(--field-control-font-size-xs);
--_calendar-padding: var(--calendar-padding-xs);
--_calendar-control-size: var(--calendar-control-size-xs);
--_calendar-day-size: var(--calendar-day-size-xs);
--_calendar-font-size: var(--calendar-font-size-xs);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-xs);
}
[data-date-range-picker][data-size='sm'] {
--_date-field-height: var(--field-control-height-sm);
--_date-field-gap: var(--space-0-5);
--_date-field-font-size: var(--field-control-font-size-sm);
--_date-range-picker-field-height: var(--field-control-height-sm);
--_date-range-picker-field-gap: var(--space-0-5);
--_date-range-picker-field-font-size: var(--field-control-font-size-sm);
--_calendar-padding: var(--calendar-padding-sm);
--_calendar-control-size: var(--calendar-control-size-sm);
--_calendar-day-size: var(--calendar-day-size-sm);
--_calendar-font-size: var(--calendar-font-size-sm);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-sm);
}
[data-date-range-picker][data-size='lg'] {
--_date-field-height: var(--field-control-height-lg);
--_date-field-gap: var(--space-1-5);
--_date-field-font-size: var(--field-control-font-size-lg);
--_date-range-picker-field-height: var(--field-control-height-lg);
--_date-range-picker-field-gap: var(--space-1-5);
--_date-range-picker-field-font-size: var(--field-control-font-size-lg);
--_calendar-padding: var(--calendar-padding-lg);
--_calendar-control-size: var(--calendar-control-size-lg);
--_calendar-day-size: var(--calendar-day-size-lg);
--_calendar-font-size: var(--calendar-font-size-lg);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-lg);
}
[data-date-range-picker][data-color='secondary'] {
--_date-field-accent-border: var(--color-secondary-border);
--_date-field-accent-track: var(--color-secondary-track);
--_date-field-accent-text: var(--color-secondary-text);
--_date-range-picker-field-accent-border: var(--color-secondary-border);
--_date-range-picker-field-accent-track: var(--color-secondary-track);
--_date-range-picker-field-accent-text: var(--color-secondary-text);
--_calendar-accent-solid: var(--color-secondary-solid);
--_calendar-accent-solid-hover: var(--color-secondary-solid-hover);
--_calendar-accent-track: var(--color-secondary-track);
@ -71,9 +71,9 @@
}
[data-date-range-picker][data-color='neutral'] {
--_date-field-accent-border: var(--color-neutral-border);
--_date-field-accent-track: var(--color-neutral-track);
--_date-field-accent-text: var(--color-neutral-text);
--_date-range-picker-field-accent-border: var(--color-neutral-border);
--_date-range-picker-field-accent-track: var(--color-neutral-track);
--_date-range-picker-field-accent-text: var(--color-neutral-text);
--_calendar-accent-solid: var(--color-neutral-solid);
--_calendar-accent-solid-hover: var(--color-neutral-solid-hover);
--_calendar-accent-track: var(--color-neutral-track);
@ -82,9 +82,9 @@
}
[data-date-range-picker][data-color='affirm'] {
--_date-field-accent-border: var(--color-affirm-border);
--_date-field-accent-track: var(--color-affirm-track);
--_date-field-accent-text: var(--color-affirm-text);
--_date-range-picker-field-accent-border: var(--color-affirm-border);
--_date-range-picker-field-accent-track: var(--color-affirm-track);
--_date-range-picker-field-accent-text: var(--color-affirm-text);
--_calendar-accent-solid: var(--color-affirm-solid);
--_calendar-accent-solid-hover: var(--color-affirm-solid-hover);
--_calendar-accent-track: var(--color-affirm-track);
@ -93,9 +93,9 @@
}
[data-date-range-picker][data-color='fulfill'] {
--_date-field-accent-border: var(--color-fulfill-border);
--_date-field-accent-track: var(--color-fulfill-track);
--_date-field-accent-text: var(--color-fulfill-text);
--_date-range-picker-field-accent-border: var(--color-fulfill-border);
--_date-range-picker-field-accent-track: var(--color-fulfill-track);
--_date-range-picker-field-accent-text: var(--color-fulfill-text);
--_calendar-accent-solid: var(--color-fulfill-solid);
--_calendar-accent-solid-hover: var(--color-fulfill-solid-hover);
--_calendar-accent-track: var(--color-fulfill-track);
@ -104,9 +104,9 @@
}
[data-date-range-picker][data-color='risk'] {
--_date-field-accent-border: var(--color-risk-border);
--_date-field-accent-track: var(--color-risk-track);
--_date-field-accent-text: var(--color-risk-text);
--_date-range-picker-field-accent-border: var(--color-risk-border);
--_date-range-picker-field-accent-track: var(--color-risk-track);
--_date-range-picker-field-accent-text: var(--color-risk-text);
--_calendar-accent-solid: var(--color-risk-solid);
--_calendar-accent-solid-hover: var(--color-risk-solid-hover);
--_calendar-accent-track: var(--color-risk-track);
@ -115,9 +115,9 @@
}
[data-date-range-picker][data-color='threat'] {
--_date-field-accent-border: var(--color-threat-border);
--_date-field-accent-track: var(--color-threat-track);
--_date-field-accent-text: var(--color-threat-text);
--_date-range-picker-field-accent-border: var(--color-threat-border);
--_date-range-picker-field-accent-track: var(--color-threat-track);
--_date-range-picker-field-accent-text: var(--color-threat-text);
--_calendar-accent-solid: var(--color-threat-solid);
--_calendar-accent-solid-hover: var(--color-threat-solid-hover);
--_calendar-accent-track: var(--color-threat-track);
@ -126,9 +126,9 @@
}
[data-date-range-picker][data-color='loss'] {
--_date-field-accent-border: var(--color-loss-border);
--_date-field-accent-track: var(--color-loss-track);
--_date-field-accent-text: var(--color-loss-text);
--_date-range-picker-field-accent-border: var(--color-loss-border);
--_date-range-picker-field-accent-track: var(--color-loss-track);
--_date-range-picker-field-accent-text: var(--color-loss-text);
--_calendar-accent-solid: var(--color-loss-solid);
--_calendar-accent-solid-hover: var(--color-loss-solid-hover);
--_calendar-accent-track: var(--color-loss-track);
@ -183,8 +183,8 @@
align-items: center;
justify-content: center;
flex: 0 0 auto;
inline-size: var(--_date-field-height);
block-size: var(--_date-field-height);
inline-size: var(--_date-range-picker-field-height);
block-size: var(--_date-range-picker-field-height);
padding: 0;
border: var(--field-control-border-width) solid var(--field-control-border);
border-radius: var(--field-control-radius);
@ -199,13 +199,13 @@
}
[data-date-range-picker-trigger]:hover {
border-color: var(--_date-field-accent-border);
background: var(--_date-field-accent-track);
color: var(--_date-field-accent-text);
border-color: var(--_date-range-picker-field-accent-border);
background: var(--_date-range-picker-field-accent-track);
color: var(--_date-range-picker-field-accent-text);
}
[data-date-range-picker-trigger]:focus-visible {
border-color: var(--_date-field-accent-border);
border-color: var(--_date-range-picker-field-accent-border);
/* Focus ring as a flush outline (no offset → no gap) — survives forced-colors. */
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: 0;
@ -259,7 +259,7 @@
--_calendar-padding: var(--calendar-padding-md);
--_calendar-control-size: var(--calendar-control-size-md);
--_calendar-day-size: var(--calendar-day-size-md);
--_calendar-font-size: var(--calendar-font-size-md);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-md);
--_calendar-accent-solid: var(--color-primary-solid);
--_calendar-accent-solid-hover: var(--color-primary-solid-hover);
--_calendar-accent-track: var(--color-primary-track);
@ -278,7 +278,7 @@
box-shadow: none;
color: var(--calendar-color);
font-family: var(--calendar-font-family);
font-size: var(--_calendar-font-size);
font-size: var(--_date-range-picker-calendar-font-size);
line-height: var(--calendar-line-height);
}
@ -286,21 +286,21 @@
--_calendar-padding: var(--calendar-padding-xs);
--_calendar-control-size: var(--calendar-control-size-xs);
--_calendar-day-size: var(--calendar-day-size-xs);
--_calendar-font-size: var(--calendar-font-size-xs);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-xs);
}
[data-date-range-picker-calendar][data-range-calendar][data-size='sm'] {
--_calendar-padding: var(--calendar-padding-sm);
--_calendar-control-size: var(--calendar-control-size-sm);
--_calendar-day-size: var(--calendar-day-size-sm);
--_calendar-font-size: var(--calendar-font-size-sm);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-sm);
}
[data-date-range-picker-calendar][data-range-calendar][data-size='lg'] {
--_calendar-padding: var(--calendar-padding-lg);
--_calendar-control-size: var(--calendar-control-size-lg);
--_calendar-day-size: var(--calendar-day-size-lg);
--_calendar-font-size: var(--calendar-font-size-lg);
--_date-range-picker-calendar-font-size: var(--calendar-font-size-lg);
}
[data-date-range-picker-calendar][data-range-calendar][data-color='secondary'] {
@ -363,7 +363,6 @@
border-color: transparent;
}
@media (max-width: 42rem) {
[data-date-range-field-input] {
flex-basis: 100%;
@ -380,8 +379,8 @@
[data-date-range-picker-month-view] {
display: flex;
flex-direction: column;
gap: var(--space-3);
inline-size: min(20rem, 100%);
gap: var(--date-range-picker-overview-gap);
inline-size: var(--date-range-picker-overview-width);
}
[data-date-range-picker-year-view-header],
@ -389,54 +388,54 @@
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
gap: var(--date-range-picker-overview-header-gap);
}
[data-date-range-picker-year-view-heading],
[data-date-range-picker-month-view-heading] {
font-weight: var(--font-weight-semibold);
color: var(--color-content-primary);
font-weight: var(--date-range-picker-overview-heading-font-weight);
color: var(--date-range-picker-overview-heading-fg);
}
[data-date-range-picker-year-view-prev],
[data-date-range-picker-year-view-next],
[data-date-range-picker-month-view-prev],
[data-date-range-picker-month-view-next] {
min-block-size: var(--control-height-sm);
min-inline-size: var(--control-height-sm);
border-radius: var(--radius-md);
min-block-size: var(--date-range-picker-overview-nav-size);
min-inline-size: var(--date-range-picker-overview-nav-size);
border-radius: var(--date-range-picker-overview-nav-radius);
border: var(--border-width) solid transparent;
background: transparent;
color: var(--color-content-primary);
color: var(--date-range-picker-overview-nav-fg);
cursor: pointer;
font: inherit;
font-size: var(--font-size-md);
font-size: var(--date-range-picker-overview-nav-font-size);
}
[data-date-range-picker-year-view-prev]:hover,
[data-date-range-picker-year-view-next]:hover,
[data-date-range-picker-month-view-prev]:hover,
[data-date-range-picker-month-view-next]:hover {
background: var(--color-surface-overlay);
background: var(--date-range-picker-hover-overview-nav-bg);
}
[data-date-range-picker-year-view-grid],
[data-date-range-picker-month-view-grid] {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--space-2);
gap: var(--date-range-picker-overview-grid-gap);
}
[data-date-range-picker-year-view-cell],
[data-date-range-picker-month-view-cell] {
min-block-size: var(--control-height-md);
border-radius: var(--radius-md);
min-block-size: var(--date-range-picker-overview-cell-height);
border-radius: var(--date-range-picker-overview-cell-radius);
border: var(--border-width) solid transparent;
background: transparent;
color: var(--color-content-primary);
color: var(--date-range-picker-overview-cell-fg);
cursor: pointer;
font: inherit;
font-size: var(--font-size-sm);
font-size: var(--date-range-picker-overview-cell-font-size);
transition:
background var(--duration-fast) var(--ease-default),
color var(--duration-fast) var(--ease-default);
@ -444,7 +443,7 @@
[data-date-range-picker-year-view-cell]:hover,
[data-date-range-picker-month-view-cell]:hover {
background: var(--color-surface-overlay);
background: var(--date-range-picker-hover-overview-cell-bg);
}
/* Range stripe: in-range cells get a tinted background matching the
@ -459,8 +458,8 @@
* 22% of solid produced. */
[data-date-range-picker-year-view-cell][data-in-range],
[data-date-range-picker-month-view-cell][data-in-range] {
background: var(--color-primary-track);
color: var(--color-primary-text);
background: var(--date-range-picker-in-range-overview-cell-bg);
color: var(--date-range-picker-in-range-overview-cell-fg);
border-radius: 0;
}
@ -468,9 +467,9 @@
[data-date-range-picker-year-view-cell][data-range-end],
[data-date-range-picker-month-view-cell][data-range-start],
[data-date-range-picker-month-view-cell][data-range-end] {
background: var(--color-primary-solid);
color: var(--color-content-on-solid);
border-color: var(--color-primary-border);
background: var(--date-range-picker-endpoint-overview-cell-bg);
color: var(--date-range-picker-endpoint-overview-cell-fg);
border-color: var(--date-range-picker-endpoint-overview-cell-border);
}
/* Round the open edge of the range strip on start / end cells. */
@ -492,7 +491,6 @@
outline-offset: var(--focus-ring-offset);
}
@media (prefers-reduced-motion: reduce) {
[data-date-range-picker-trigger],
[data-date-range-field-input],

@ -1657,6 +1657,30 @@
--button-loss-solid-hover: var(--color-loss-solid-hover);
--button-loss-text: var(--color-loss-text);
--button-loss-contrast: var(--color-loss-contrast);
--date-range-picker-accent-border: var(--color-primary-border);
--date-range-picker-accent-track: var(--color-primary-track);
--date-range-picker-accent-text: var(--color-primary-text);
--date-range-picker-overview-gap: var(--space-3);
--date-range-picker-overview-width: min(20rem, 100%);
--date-range-picker-overview-header-gap: var(--space-2);
--date-range-picker-overview-heading-fg: var(--color-content-primary);
--date-range-picker-overview-heading-font-weight: var(--font-weight-semibold);
--date-range-picker-overview-nav-size: var(--size-sm-control-height);
--date-range-picker-overview-nav-radius: var(--radius-md);
--date-range-picker-overview-nav-fg: var(--color-content-primary);
--date-range-picker-overview-nav-font-size: var(--size-md-font-size);
--date-range-picker-hover-overview-nav-bg: var(--color-surface-overlay);
--date-range-picker-overview-grid-gap: var(--space-2);
--date-range-picker-overview-cell-height: var(--size-md-control-height);
--date-range-picker-overview-cell-radius: var(--radius-md);
--date-range-picker-overview-cell-fg: var(--color-content-primary);
--date-range-picker-overview-cell-font-size: var(--size-sm-font-size);
--date-range-picker-hover-overview-cell-bg: var(--color-surface-overlay);
--date-range-picker-in-range-overview-cell-bg: var(--color-primary-track);
--date-range-picker-in-range-overview-cell-fg: var(--color-primary-text);
--date-range-picker-endpoint-overview-cell-bg: var(--color-primary-solid);
--date-range-picker-endpoint-overview-cell-fg: var(--color-content-on-solid);
--date-range-picker-endpoint-overview-cell-border: var(--color-primary-border);
--time-range-picker-accent-border: var(--color-primary-border);
--time-range-picker-accent-track: var(--color-primary-track);
--time-range-picker-accent-text: var(--color-primary-text);

@ -1989,6 +1989,37 @@ export const THEME_BASE_RECIPE_TOKENS = defineRecipes({
'_palette-element': { value: 'var(--color-primary-element)', scope: 'host' }
},
// ─────────────────────────────────────────────────────────────────────
// DateRangePicker — only the DECADE / MONTH view is its own invention; the
// calendar half borrows `--calendar-*` (that is the calendar-family decision
// in theming-audit §B, not this axis) and the field half borrows `--field-*`
// (the field-composition mandate). Theme-reach 2026-08-20.
'date-range-picker': {
'accent-border': 'var(--color-primary-border)',
'accent-track': 'var(--color-primary-track)',
'accent-text': 'var(--color-primary-text)',
'overview-gap': 'var(--space-3)',
'overview-width': 'min(20rem, 100%)',
'overview-header-gap': 'var(--space-2)',
'overview-heading-fg': 'var(--color-content-primary)',
'overview-heading-font-weight': 'var(--font-weight-semibold)',
'overview-nav-size': 'var(--size-sm-control-height)',
'overview-nav-radius': 'var(--radius-md)',
'overview-nav-fg': 'var(--color-content-primary)',
'overview-nav-font-size': 'var(--size-md-font-size)',
'hover-overview-nav-bg': 'var(--color-surface-overlay)',
'overview-grid-gap': 'var(--space-2)',
'overview-cell-height': 'var(--size-md-control-height)',
'overview-cell-radius': 'var(--radius-md)',
'overview-cell-fg': 'var(--color-content-primary)',
'overview-cell-font-size': 'var(--size-sm-font-size)',
'hover-overview-cell-bg': 'var(--color-surface-overlay)',
'in-range-overview-cell-bg': 'var(--color-primary-track)',
'in-range-overview-cell-fg': 'var(--color-primary-text)',
'endpoint-overview-cell-bg': 'var(--color-primary-solid)',
'endpoint-overview-cell-fg': 'var(--color-content-on-solid)',
'endpoint-overview-cell-border': 'var(--color-primary-border)'
},
// ─────────────────────────────────────────────────────────────────────
// TimeRangePicker — same split as `time-picker`: the two-column clock and
// the AM/PM strip are its own, the field-shaped half stays on `--field-*`
// (it composes Field). Theme-reach 2026-08-20.

Loading…
Cancel
Save

Powered by TurnKey Linux.