17 KiB
natural-time-picker — 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 · método y protocolo:PLAN-theming.md§1, §2, §7.
- Medido: 2026-08-20 · Alcance: 61% — 46 de 76 knobs por token público
- Knobs de apariencia: 77 — público 46 · privado 10 · global 14 · literal 6 · sistema 1 (fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 62 pública(s) —band-height-sm,band-height-md,band-height-lg,knob-size-sm,knob-size-md,knob-size-lg,band-height,knob-size,panel-gap-sm,panel-gap-md,panel-gap-lg,panel-gap,band-radius,band-border,band-border-width,line-width,line-radius,knob-radius,knob-shadow,knob-focus-ring,knob-focus-ring-offset,ticks-inset-inline,ticks-inset-block-end,tick-font-size,tick-font-family,display-gap,time-font-family,time-font-size,time-font-weight,time-letter-spacing,meridiem-margin-inline-start,meridiem-font-size,meridiem-font-weight,meridiem-fg,period-gap,period-font-size,period-font-weight,period-fg,steppers-gap,stepper-group-gap,stepper-label-font-size,stepper-label-font-weight,stepper-label-fg,stepper-label-letter-spacing,periods-gap,periods-margin-block,chip-font-size,trigger-gap,trigger-min-width,trigger-padding-block,trigger-padding-inline,trigger-bg,trigger-fg,trigger-border,trigger-border-width,trigger-radius,trigger-font-size,hover-trigger-border,open-trigger-border,open-trigger-ring,trigger-value-empty-fg,trigger-icon-fg - Eje
size: sí · ficheros:natural-time-picker.css
1. Knobs fuera de alcance
1.1 Directo a primitivo global (14)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | natural-time-picker.css:40 |
[data-natural-time-picker-panel] |
min-inline-size |
var(--popover-min-width-md) ⤴ prestado de popover |
| 2 | natural-time-picker.css:44 |
[data-natural-time-picker-panel] |
padding-block |
var(--popover-padding-block-md) ⤴ prestado de popover |
| 3 | natural-time-picker.css:45 |
[data-natural-time-picker-panel] |
padding-inline |
var(--popover-padding-inline-md) ⤴ prestado de popover |
| 4 | natural-time-picker.css:46 |
[data-natural-time-picker-panel] |
background |
var(--color-surface-overlay) |
| 5 | natural-time-picker.css:47 |
[data-natural-time-picker-panel] |
color |
var(--color-content-primary) |
| 6 | natural-time-picker.css:48 |
[data-natural-time-picker-panel] |
border |
var(--border-width) solid var(--color-border-subtle) |
| 7 | natural-time-picker.css:49 |
[data-natural-time-picker-panel] |
border-radius |
var(--popover-radius) ⤴ prestado de popover |
| 8 | natural-time-picker.css:50 |
[data-natural-time-picker-panel] |
box-shadow |
var(--shadow-overlay) |
| 9 | natural-time-picker.css:53 |
[data-natural-time-picker-panel][data-size='sm'] |
min-inline-size |
var(--popover-min-width-sm) ⤴ prestado de popover |
| 10 | natural-time-picker.css:54 |
[data-natural-time-picker-panel][data-size='sm'] |
padding-block |
var(--popover-padding-block-sm) ⤴ prestado de popover |
| 11 | natural-time-picker.css:55 |
[data-natural-time-picker-panel][data-size='sm'] |
padding-inline |
var(--popover-padding-inline-sm) ⤴ prestado de popover |
| 12 | natural-time-picker.css:58 |
[data-natural-time-picker-panel][data-size='lg'] |
min-inline-size |
var(--popover-min-width-lg) ⤴ prestado de popover |
| 13 | natural-time-picker.css:59 |
[data-natural-time-picker-panel][data-size='lg'] |
padding-block |
var(--popover-padding-block-lg) ⤴ prestado de popover |
| 14 | natural-time-picker.css:60 |
[data-natural-time-picker-panel][data-size='lg'] |
padding-inline |
var(--popover-padding-inline-lg) ⤴ prestado de popover |
1.2 A través de un privado (10)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | natural-time-picker.css:125 |
[data-natural-time-picker-band] |
block-size |
var(--_natural-time-picker-band-block) |
| 2 | natural-time-picker.css:129 |
[data-natural-time-picker-band] |
background |
linear-gradient( 90deg, var(--_natural-time-picker-sky-night) 0%, var(--_natural-time-picker-sky-night) 18%, var(--_natural-time-picker-sky-dawn) 25%, var(--_natural-time-picker-sky-gold) 33%, var(--_natural-time-picker-sky-day) 50%, var(--_natural-time-picker-sky-gold) 67%, var(--_natural-time-picker-sky-dusk) 76%, var(--_natural-time-picker-sky-night) 83%, var(--_natural-time-picker-sky-night) 100% ) |
| 3 | natural-time-picker.css:154 |
[data-natural-time-picker-panel] [data-natural-time-picker-band] [data-slider] |
block-size |
var(--_natural-time-picker-band-block) |
| 4 | natural-time-picker.css:173 |
[data-natural-time-picker-band] [data-slider-thumb] |
block-size |
var(--_natural-time-picker-band-block) |
| 5 | natural-time-picker.css:175 |
[data-natural-time-picker-band] [data-slider-thumb] |
background |
var(--_natural-time-picker-line) |
| 6 | natural-time-picker.css:192 |
[data-natural-time-picker-knob] |
inline-size |
var(--_natural-time-picker-knob) |
| 7 | natural-time-picker.css:193 |
[data-natural-time-picker-knob] |
block-size |
var(--_natural-time-picker-knob) |
| 8 | natural-time-picker.css:195 |
[data-natural-time-picker-knob] |
background |
var(--_natural-time-picker-ink) |
| 9 | natural-time-picker.css:196 |
[data-natural-time-picker-knob] |
color |
var(--_natural-time-picker-sky-night) |
| 10 | natural-time-picker.css:225 |
[data-natural-time-picker-tick] |
color |
var(--_natural-time-picker-tick) |
1.3 Literales (6)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | natural-time-picker.css:39 |
[data-natural-time-picker-panel] |
inline-size |
100% |
| 2 | natural-time-picker.css:86 |
[data-natural-time-picker-time] |
line-height |
1 |
| 3 | natural-time-picker.css:96 |
[data-natural-time-picker-meridiem] |
line-height |
1 |
| 4 | natural-time-picker.css:124 |
[data-natural-time-picker-band] |
inline-size |
100% |
| 5 | natural-time-picker.css:222 |
[data-natural-time-picker-tick] |
line-height |
1 |
| 6 | natural-time-picker.css:292 |
[data-natural-time-picker-panel] [data-natural-time-picker-periods]:not([data-icon-only]) [data-button] |
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 | natural-time-picker.css:66 |
[data-natural-time-picker][data-disabled] |
opacity |
var(--opacity-disabled) |
3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
|---|---|---|---|---|
--_natural-time-picker-sky-night |
1 | #1a1d2e |
literal | no |
--_natural-time-picker-sky-dawn |
1 | #3a4a7a |
literal | no |
--_natural-time-picker-sky-gold |
1 | #f0b85a |
literal | no |
--_natural-time-picker-sky-day |
1 | #7fc8e8 |
literal | no |
--_natural-time-picker-sky-dusk |
1 | #c4623a |
literal | no |
--_natural-time-picker-ink |
1 | #ffffff |
literal | no |
--_natural-time-picker-line |
1 | rgb(255 255 255 / 0.9) |
literal | no |
--_natural-time-picker-tick |
1 | rgb(255 255 255 / 0.88) |
literal | no |
--_natural-time-picker-tick-shadow |
1 | rgb(0 0 0 / 0.5) |
literal | no |
--_natural-time-picker-band-block |
1 | var(--natural-time-picker-band-height) |
public | sí |
--_natural-time-picker-knob |
1 | var(--natural-time-picker-knob-size) |
public | sí |
4. Propuesta de corrección
- Consume la capa compartida
picker-shell. Un eje que la capa posee se consume comovar(--_x, var(--x)); el consumidor no acuña--natural-time-picker-{eje}para él — sería un vocabulario paralelo (README deeidos/components, «Capas compartidas» regla 2). - Consume tokens públicos de
popover. 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 guardrecipe-css-contractprohíbe el primitivo).
4.1 Tokens a declarar en lib/recipes/base.ts (17)
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 (--natural-time-picker-…) |
scope TSC | valor propuesto | usos |
|---|---|---|---|
band-bg |
root |
⚠ #1a1d2e / rgb(255 255 255 / 0.9) |
2 |
panel-width |
root |
var(--popover-min-width-md) |
1 |
panel-padding-block |
root |
var(--popover-padding-block-md) |
1 |
panel-padding-inline |
root |
var(--popover-padding-inline-md) |
1 |
panel-bg |
root |
var(--color-surface-overlay) |
1 |
panel-fg |
root |
var(--color-content-primary) |
1 |
panel-radius |
root |
var(--popover-radius) |
1 |
panel-shadow |
root |
var(--shadow-overlay) |
1 |
panel-width-sm |
root |
var(--popover-min-width-sm) |
1 |
panel-padding-block-sm |
root |
var(--popover-padding-block-sm) |
1 |
panel-padding-inline-sm |
root |
var(--popover-padding-inline-sm) |
1 |
panel-width-lg |
root |
var(--popover-min-width-lg) |
1 |
panel-padding-block-lg |
root |
var(--popover-padding-block-lg) |
1 |
panel-padding-inline-lg |
root |
var(--popover-padding-inline-lg) |
1 |
knob-bg |
root |
#ffffff |
1 |
knob-fg |
root |
#1a1d2e |
1 |
tick-fg |
root |
rgb(255 255 255 / 0.88) |
1 |
4.2 Sin nombre mecánico (12)
- ⚠ 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 — 3:inline-size. - ⚠ decisión:
borderes shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4) — 1:border. - ⚠ decisión:
1es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar — 3:line-height. - ya alcanzable: el privado
--_natural-time-picker-band-blockderiva de un público (var(--natural-time-picker-band-height)) — sin acción; el censo lo cuenta como no alcanzable por el límite del regex — 3:block-size. - ya alcanzable: el privado
--_natural-time-picker-knobderiva de un público (var(--natural-time-picker-knob-size)) — sin acción; el censo lo cuenta como no alcanzable por el límite del regex — 2:inline-size,block-size.
4.3 Avisos sobre los tokens propuestos (4)
- el privado
--_natural-time-picker-sky-nightdebe pasar a leer este público (o desaparecer) —--natural-time-picker-band-bg,--natural-time-picker-knob-fg - el privado
--_natural-time-picker-linedebe pasar a leer este público (o desaparecer) —--natural-time-picker-band-bg - el privado
--_natural-time-picker-inkdebe pasar a leer este público (o desaparecer) —--natural-time-picker-knob-bg - el privado
--_natural-time-picker-tickdebe pasar a leer este público (o desaparecer) —--natural-time-picker-tick-fg
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, unbackgrounden 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
Revisión 2026-08-20 — verificación previa a implementación (Opus).
Análisis (§1–§3): CORRECTO en cifras (78 · 0 · 0 · 69 · 7 · 2), con el
mismo hallazgo de prefijo que sus hermanos de familia: el «privado 0» es
falso de nombre — la receta declara y consume --_ntp-* (band-block,
sky-night/dawn/gold/day/dusk, knob, ink, line), prefijo ABREVIADO que
viola la regla 5 de theming §6 («no abreviar el nombre del componente») y
deja al censo contándolos como global. Paso previo: renombrar --_ntp-*
→ --_natural-time-picker-* (mecánico, git ls-files antes).
Propuesta (§4.1): APTA EN SU SUBCONJUNTO PROPIO, con tres correcciones:
- Las filas
panel-*que alias-an públicos depopover(panel-width = var(--popover-min-width-md), paddings, radius) no se acuñan: son el préstamo-con-prefijo que la nota de §4 prohíbe. Si el panel se monta dentro de un Popover compuesto, su cromo se tema en la ficha de popover; si el autor quiere ejes propios del panel, el valor es el VERBATIM de hoy, nunca el alias del token ajeno. Decisión del autor. - La talla vive SÓLO en el panel (
[data-natural-time-picker-panel] [data-size]), que además viaja por portal: coordenadas por talla enroot(como propone la tabla) + nombre resuelto conparts: ['panel']y defaulthost(tsc.md §multi-part) — sinparts, las declarations por talla no alcanzan nunca el panel. - El cielo es LA decisión de diseño de este componente: la banda es un
gradiente de 5 paradas (
--_ntp-sky-*). O (a) los cielos son físicamente fijos (la válvula que recipe-contract §3 nombra literalmente: «the natural clock's skies») → anotarlos y excepción R-5; o (b) son temables → promover las 5 paradas a públicos (sky-night/dawn/gold/day/dusk) y el gradiente las lee. Las dos son coherentes; la elige el autor. La filaband-bgcon el gradiente entero como valor NO — un tema no debe re-escribir la rampa para mover un cielo.
Lo acuñable tal cual (patrón Sidebar, valores verbatim): band-height/ radius/width, knob-width/height/radius/bg/fg (leyendo los privados
renombrados o promoviéndolos), display-gap, time-font-*,
meridiem-*, period-*, stepper-group-* — partes limpias
(panel, band, trigger, stepper-group, periods, meridiem, time).
Los 7 literales: anotar o tokenizar uno a uno. Sonda §7.2: abrir el panel
ANTES de medir (portal + pantalla oculta congela rAF).
Bloqueos de firma: cielos fijos vs temables (punto 3) · panel propio vs cromo de popover (punto 1) · D-TH.4 (familia tiempo, B7).
EJECUTADO 2026-08-20. Alcance 0 % → 61 % · contrato 0 → 60 claves públicas. Los dos «bloqueos» de arriba resultaron NO serlo: la doctrina ya estaba escrita y no la había leído al revisar.
- Los cielos no había que decidirlos: el guard
recipe-css-contractya listanatural-time-pickerenFIXED_TONE_COMPONENTS— la excepción de tono fijo (un cielo no cambia con el tema) — y la receta ya anota cada literal con su válvula. Se quedan privados, como estaban. - El panel sigue prestando
--popover-*: su cabecera dice que la superficie ES el flotante canónico. Duplicarlo con prefijo propio sería el vocabulario paralelo que el contrato prohíbe. Sólo se acuñó lo que sí es suyo: elpanel-gappor talla. - Prefijo abreviado muerto: 37 referencias
--_ntp-*renombradas a--_natural-time-picker-*(receta, wrapper, README y el propio guard).
Acuñado: banda y knob por talla con parts: ['panel'] — conservando su
derivación calc(--size-{k}-control-height * 1.7 + --space-2) y * 0.62, así
que la expresión sigue siendo el knob —, línea indicadora, ticks, readout
(time / meridiem / period), steppers, chips y trigger.
Verificación: diff de computed = 0 sobre 6.438 valores en 8 estados ·
centinela 40/62 automático, y los marcados como muertos verificados a mano:
band-height-md, knob-size-md, panel-gap-md, line-width, line-radius y
ticks-inset-block-end alcanzan; los trigger-* no, porque
[data-popover-trigger]:not([data-archetype='field-trigger']) gana la cascada y
viste el trigger — inertes ya antes de tokenizarlos, ahora dicho en el README.
Guards: component:audit PASS · eidos-lint 0 invalid · suite sin rojos nuevos
· rtl:check 0 · docs:check 0 · el guard del bundle obligó a apuntar
tick-font-size a --size-xxs-font-size.
El 39 % que no alcanza son los préstamos de popover y el trío de superficie
(--color-surface-overlay, --color-border-subtle, --shadow-overlay) que el
componente declara a mano en vez de estampar data-depth='overlay': migrarlo es
otra decisión, anotada.