diff --git a/docs/audit/theming/README.md b/docs/audit/theming/README.md index 8b3c37a80..f97d3ee15 100644 --- a/docs/audit/theming/README.md +++ b/docs/audit/theming/README.md @@ -10,8 +10,8 @@ - **Medido**: 2026-08-23 · **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**: **67%** — 3047 de 4577 knobs pasan por un token público del componente -- **Reparto**: público 3047 · privado 317 · global 814 · literal 399 · sistema transversal 509 · excepción firmada 132 _(los dos últimos, fuera del ratio)_ +- **Alcance global**: **67%** — 3049 de 4572 knobs pasan por un token público del componente +- **Reparto**: público 3049 · privado 317 · global 813 · literal 393 · sistema transversal 509 · excepción firmada 138 _(los dos últimos, fuera del ratio)_ - **Sin token público propio**: 24 · **alcance < 20 %**: 12 · **alcance 100 %**: 28 · **con eje `size`**: 57 ## Cómo se lee @@ -147,7 +147,6 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component | [virtual-list](./virtual-list.md) | 67% | 13 | 8 | 0 | 0 | 4 | 1 | 12 | – | | [separator](./separator.md) | 67% | 6 | 4 | 0 | 0 | 2 | 0 | 3 | – | | [listbox](./listbox.md) | 68% | 37 | 23 | 9 | 1 | 1 | 3 | 21 | – | -| [progress](./progress.md) | 69% | 35 | 24 | 2 | 3 | 6 | 0 | 41 | y | | [color-swatch](./color-swatch.md) | 70% | 10 | 7 | 0 | 3 | 0 | 0 | 12 | y | | [s-text-virtual-list](./s-text-virtual-list.md) | 70% | 10 | 7 | 0 | 3 | 0 | 0 | 9 | – | | [form](./form.md) | 71% | 52 | 36 | 8 | 5 | 2 | 1 | 54 | y | @@ -191,6 +190,7 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component | [waveform](./waveform.md) | 86% | 7 | 6 | 0 | 1 | 0 | 0 | 11 | y | | [table](./table.md) | 86% | 46 | 37 | 3 | 0 | 3 | 3 | 45 | – | | [context-menu](./context-menu.md) | 87% | 33 | 26 | 0 | 1 | 3 | 3 | 28 | – | +| [progress](./progress.md) | 87% | 30 | 26 | 2 | 2 | 0 | 0 | 43 | y | | [kbd](./kbd.md) | 87% | 15 | 13 | 0 | 1 | 1 | 0 | 13 | – | | [fab](./fab.md) | 88% | 16 | 14 | 0 | 2 | 0 | 0 | 10 | – | | [announce](./announce.md) | 88% | 8 | 7 | 0 | 1 | 0 | 0 | 9 | – | diff --git a/docs/audit/theming/progress.md b/docs/audit/theming/progress.md index ce092a8bc..aab11ec20 100644 --- a/docs/audit/theming/progress.md +++ b/docs/audit/theming/progress.md @@ -5,47 +5,46 @@ > Vista de conjunto: [README](./README.md) · método y protocolo: > [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7. -- **Medido**: 2026-08-23 · **Alcance**: **69%** — 24 de 35 knobs por token público -- **Knobs de apariencia**: 35 — público 24 · privado 2 · global 3 · literal 6 · sistema 0 · excepción 0 _(los dos últimos, fuera del ratio)_ -- **Contrato hoy** (`lib/recipes/base.ts`): 41 pública(s) — `height-xs`, `height-sm`, `height-md`, `height-lg`, `height-xl`, `vertical-height`, `radius-xs`, `radius-sm`, `radius-md`, `radius-lg`, `radius-xl`, `ring-size-xs`, `ring-size-sm`, `ring-size-md`, `ring-size-lg`, `ring-size-xl`, `ring-thickness-xs`, `ring-thickness-sm`, `ring-thickness-md`, `ring-thickness-lg`, `ring-thickness-xl`, `label-font-family`, `label-font-size`, `label-font-weight`, `label-line-height`, `label-fg`, `value-text-font-family`, `value-text-font-size`, `value-text-font-weight`, `value-text-line-height`, `value-text-fg`, `track-bg`, `ring-track-bg`, `ring-center-bg`, `indicator-bg`, `indicator-bg-loaded`, `transition-duration`, `transition-ease`, `indeterminate-width`, `indeterminate-duration`, `indeterminate-ease` +- **Medido**: 2026-08-23 · **Alcance**: **87%** — 26 de 30 knobs por token público +- **Knobs de apariencia**: 30 — público 26 · privado 2 · global 2 · literal 0 · sistema 0 · excepción 6 _(los dos últimos, fuera del ratio)_ +- **Contrato hoy** (`lib/recipes/base.ts`): 43 pública(s) — `height-xs`, `height-sm`, `height-md`, `height-lg`, `height-xl`, `vertical-height`, `row-gap`, `column-gap`, `radius-xs`, `radius-sm`, `radius-md`, `radius-lg`, `radius-xl`, `ring-size-xs`, `ring-size-sm`, `ring-size-md`, `ring-size-lg`, `ring-size-xl`, `ring-thickness-xs`, `ring-thickness-sm`, `ring-thickness-md`, `ring-thickness-lg`, `ring-thickness-xl`, `label-font-family`, `label-font-size`, `label-font-weight`, `label-line-height`, `label-fg`, `value-text-font-family`, `value-text-font-size`, `value-text-font-weight`, `value-text-line-height`, `value-text-fg`, `track-bg`, `ring-track-bg`, `ring-center-bg`, `indicator-bg`, `indicator-bg-loaded`, `transition-duration`, `transition-ease`, `indeterminate-width`, `indeterminate-duration`, `indeterminate-ease` - **Eje `size`**: sí · **ficheros**: `progress.css` ## 1. Knobs fuera de alcance -### 1.1 Directo a primitivo global (3) +### 1.1 Directo a primitivo global (2) | # | fichero:línea | selector | propiedad | valor | | ---: | --- | --- | --- | --- | -| 1 | `progress.css:11` | `[data-progress]` | `gap` | `var(--space-2) var(--space-3)` | -| 2 | `progress.css:122` | `[data-progress][data-shape='circular'] [data-progress-indicator]` | `border-radius` | `var(--radius-full)` | -| 3 | `progress.css:134` | `[data-progress][data-shape='circular'] [data-progress-indicator]::before` | `border-radius` | `var(--radius-full)` | +| 1 | `progress.css:127` | `[data-progress][data-shape='circular'] [data-progress-indicator]` | `border-radius` | `var(--radius-full)` | +| 2 | `progress.css:139` | `[data-progress][data-shape='circular'] [data-progress-indicator]::before` | `border-radius` | `var(--radius-full)` | ### 1.2 A través de un privado (2) | # | fichero:línea | selector | propiedad | valor | | ---: | --- | --- | --- | --- | -| 1 | `progress.css:66` | `[data-progress-indicator]::before` | `inline-size` | `calc(var(--_progress-value-pct, 0) * 1%)` | -| 2 | `progress.css:82` | `[data-progress][data-orientation='vertical'] [data-progress-indicator]::before` | `block-size` | `calc(var(--_progress-value-pct, 0) * 1%)` | +| 1 | `progress.css:67` | `[data-progress-indicator]::before` | `inline-size` | `calc(var(--_progress-value-pct, 0) * 1%)` | +| 2 | `progress.css:83` | `[data-progress][data-orientation='vertical'] [data-progress-indicator]::before` | `block-size` | `calc(var(--_progress-value-pct, 0) * 1%)` | -### 1.3 Literales (6) +### 1.3 Literales (0) -| # | fichero:línea | selector | propiedad | valor | -| ---: | --- | --- | --- | --- | -| 1 | `progress.css:12` | `[data-progress]` | `inline-size` | `100%` | -| 2 | `progress.css:44` | `[data-progress][data-orientation='vertical']` | `inline-size` | `max-content` | -| 3 | `progress.css:54` | `[data-progress-indicator]` | `inline-size` | `100%` | -| 4 | `progress.css:81` | `[data-progress][data-orientation='vertical'] [data-progress-indicator]::before` | `inline-size` | `100%` | -| 5 | `progress.css:102` | `[data-progress][data-orientation='vertical'][data-state='indeterminate'] [data-progress-indicator]::before` | `inline-size` | `100%` | -| 6 | `progress.css:107` | `[data-progress][data-shape='circular']` | `inline-size` | `max-content` | +_Ninguno._ -### 1.4 Excepciones firmadas (0) — fuera del ratio +### 1.4 Excepciones firmadas (6) — fuera del ratio Literales que llevan su anotación `/* literal: */` 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. -_Ninguno._ +| # | fichero:línea | selector | propiedad | valor | +| ---: | --- | --- | --- | --- | +| 1 | `progress.css:13` | `[data-progress]` | `inline-size` | `100%` | +| 2 | `progress.css:45` | `[data-progress][data-orientation='vertical']` | `inline-size` | `max-content` | +| 3 | `progress.css:55` | `[data-progress-indicator]` | `inline-size` | `100%` | +| 4 | `progress.css:82` | `[data-progress][data-orientation='vertical'] [data-progress-indicator]::before` | `inline-size` | `100%` | +| 5 | `progress.css:103` | `[data-progress][data-orientation='vertical'][data-state='indeterminate'] [data-progress-indicator]::before` | `inline-size` | `100%` | +| 6 | `progress.css:108` | `[data-progress][data-shape='circular']` | `inline-size` | `max-content` | ## 2. Sistema transversal (0) — informativo, fuera del ratio Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2). @@ -68,7 +67,7 @@ Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inl - **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` (3) +### 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 @@ -80,7 +79,6 @@ no distingue lo que debería — se marca `⚠`. | --- | --- | --- | ---: | | `width` | `root` | `max-content` | 2 | | `indicator-radius` | `root` | `var(--radius-full)` | 2 | -| `gap` | `root` | `var(--space-2) var(--space-3)` | 1 | ### 4.2 Sin nombre mecánico (6) @@ -99,6 +97,74 @@ no distingue lo que debería — se marca `⚠`. -_(pendiente — lo escribe el autor; se conserva al regenerar)_ +**Ejecutado 2026-08-23 — 69 % → 87 %.** Dos claves acuñadas, seis literales +firmados, cuatro knobs adjudicados. Diff de computed **0** sobre 60 +configuraciones (2 formas × 2 orientaciones × 3 estados × 5 tallas) y capturas +2× **idénticas byte a byte**. Guard R-5.4: **40 de 43** tokens mueven un +computed; los tres callados, medidos y escritos en el ledger. + +**Lo que entra (2 claves, el ÚNICO knob que iba a un primitivo a pelo):** + +- `row-gap` (`--space-2`) y `column-gap` (`--space-3`). Eran un `gap` en + atajo de DOS valores distintos, y por eso se parte: el hueco de fila separa + la línea de texto de la barra, el de columna separa el rótulo del valor. Un + `gap` único habría nombrado un knob para dos. El catálogo tiene las dos + palabras (`row-gap` ×10, `column-gap` ×4) y el molde exacto es + `chart.legend-row-gap` / `-column-gap`. + +**Lo que se FIRMA en vez de acuñarse (6 literales, fuera del ratio):** los +cuatro `100%` y los dos `max-content` son la geometría de la barra, no una +decisión de tema — llena la fila que le dan (`100%`) o se encoge a su propio +grosor / diámetro (`max-content`). Llevan su `/* literal: */` en la +declaración; válvula de recipe-contract §3. + +**Lo que se RECHAZA de la propuesta §4 (dos de las tres filas):** + +1. `indicator-radius` — el `--radius-full` del anillo. Su gemelo `meter` ya + dejó el veredicto escrito EN EL CSS: es lo que hace circular a + `shape='circular'`, y un token dejaría que un tema des-redondease una forma + que el consumidor pidió POR SU NOMBRE. **Identidad, no knob.** Se copia el + comentario del gemelo. Son los dos únicos `global` que quedan, y el censo no + puede sacarlos del ratio: la válvula `/* literal: */` sólo reclasifica la + clase `literal`, nunca un `global` (mismo techo que `meter`). +2. `width: max-content` — la §4 fundía en UN nombre dos nodos distintos (la + raíz vertical y la raíz circular) y además lo llamaba por el primer selector, + no por lo que pinta. Es el literal de identidad de arriba. + +**Los dos knobs `private` que quedan son el CANAL DE VALOR, no deuda.** +`--_progress-value-pct` lo escribe **soma** en el estilo inline del provider en +cada render (`progress-provider.svelte.ts`, 0–100 saturado); la receta lo lee +para el ancho del relleno lineal y el alto del vertical. Un público encima +mentiría: un tema no puede fijar el progreso de una tarea. Es la misma clase que +el `z-index` inline de `drag-drop` y el gap de `carousel`. Con ellos y con los +dos `--radius-full` de identidad, **el techo honesto de este componente es +87 %**, no el 100 %. + +**Lo que el guard da por callado (3 de 43, todos medidos sobre el nodo real):** + +- `indicator-bg-loaded` — sólo pinta bajo `[data-state='loaded']`, y la corrida + mantiene `indeterminate` encendido para alcanzar los tokens del barrido: + forzado → `oklch(0.6406 0.1329 157.68)` → `rgb(1,2,3)`. +- `transition-duration` / `transition-ease` — los congela el propio guard por + diseño; pasada SIN congelar → `0.18s` → `11.5s` y + `cubic-bezier(0.4, 0, 0.2, 1)` → `steps(7)`. Mismo par que en `meter`. + +**Lo que enseñó el instrumento.** La sonda estándar mide 4 nodos — que son +TODAS las partes del morfo — pero una sola configuración: lineal, horizontal, +`loading`, `md`. Medio contrato (el anillo, el eje vertical, el barrido +indeterminado, la tinta de completado) no entra en ese diff, y el gate habría +pasado en verde sin haberlo mirado. El guard lo dijo antes: **22 de 41** en la +página por defecto. Con `sweepAttr: data-shape` (el interruptor que su gemelo +`meter` ya tenía) sube a 34; encendiendo el interruptor `indeterminate` de la +demo, a 37; y el chip `vertical`, a 38 — **cada control comprobado por separado, +antes y después, porque montar más puede medir menos**. Aquí no tapó ninguno. + +**Y una trampa nueva del instrumento, medida aquí**: una sonda que CACHEA los +nodos y luego mide en bucle da 8.352 falsos diffs si el HMR reemplaza el +subárbol a mitad de corrida — `getComputedStyle` sobre un nodo DESACOPLADO +devuelve la cadena VACÍA en todas las propiedades, y el diff lee cada vacío como +un cambio. Se arregla re-consultando los nodos en cada instantánea, y se detecta +haciendo fallar la sonda ante un computed vacío. Es pariente de +`hmr-stale-tab-phantom-findings`, con otra cara. diff --git a/docs/process/PLAN-theming.md b/docs/process/PLAN-theming.md index 02354aeb2..7fda494fb 100644 --- a/docs/process/PLAN-theming.md +++ b/docs/process/PLAN-theming.md @@ -515,6 +515,22 @@ commits de corrección. animaciones (ningún commit toca `animation`); contrato sin duplicados ni huérfanos. +- 2026-08-23 — **`progress` 69 % → 87 %** (COMMIT), 2 claves. `row-gap` + + `column-gap`: el `gap` en atajo tenía DOS valores distintos, así que es un knob + por eje (molde `chart.legend-row-gap`). **Seis literales de identidad + firmados** (cuatro `100%`, dos `max-content`: llena la fila que le dan o se + encoge a su propio grosor). **Rechazadas dos de las tres filas de la §4**: el + `--radius-full` del anillo es lo que HACE circular a `shape='circular'` — su + gemelo `meter` ya lo dejó escrito en el CSS, y se copia el comentario. Los dos + `private` que quedan son el CANAL DE VALOR (`--_progress-value-pct`, inline de + soma), así que **su techo honesto es 87 %**. R-5.4 40/43 con `sweepAttr: + data-shape` + los controles `indeterminate` y `vertical` de la demo (22/41 sin + ellos); tres adjudicados. Diff 0 sobre **60 configuraciones** (2 formas × 2 + orientaciones × 3 estados × 5 tallas, 17.280 valores) y capturas 2× + **idénticas byte a byte**. ⚠ **una sonda que CACHEA los nodos da 8.352 falsos + diffs si el HMR reemplaza el subárbol**: `getComputedStyle` de un nodo + desacoplado devuelve la cadena vacía en TODAS las propiedades. + - 2026-08-23 — **`cropper` 60 % → 94 %** (`f03ee5af4`), 2 claves. El cromo del botón de zoom (radio + `font-size`, costura). **Siete literales de IDENTIDAD** firmados: cuatro `100%`, dos `50%` (lo que HACE redonda una selección y un diff --git a/scripts/theming-sentinel-exceptions.ts b/scripts/theming-sentinel-exceptions.ts index a7b52a397..c84fd74e8 100644 --- a/scripts/theming-sentinel-exceptions.ts +++ b/scripts/theming-sentinel-exceptions.ts @@ -155,6 +155,18 @@ export const SENTINEL_EXCEPTIONS: Record> = { 'transition-ease': 'same freeze; unfrozen pass -> reaches (cubic-bezier(0.4,0,0.2,1) -> steps(7))' }, + progress: { + // 2026-08-23. The guard now sweeps `data-shape` (like its twin meter) and + // switches the demo's indeterminate + vertical controls on, which takes it + // from 22/41 to 40/43. What is left needs a state the demo cannot hold at + // the same time as the ones already forced, or a property the guard freezes. + 'indicator-bg-loaded': + "only under [data-state='loaded'], and the run holds `indeterminate` to reach the sweep tokens; forced on the real root -> reaches (oklch(0.6406 0.1329 157.68) -> rgb(1,2,3))", + 'transition-duration': + 'frozen by the guard by design; unfrozen pass -> reaches (0.18s -> 11.5s)', + 'transition-ease': + 'same freeze; unfrozen pass -> reaches (cubic-bezier(0.4,0,0.2,1) -> steps(7))' + }, 'emoji-picker': { // 2026-08-23. Four keys of the PORTALED panel. The guard writes the // sentinel on :root and on the host, and :root does cross the portal diff --git a/scripts/theming-sentinel.ts b/scripts/theming-sentinel.ts index 9592176fe..338f6dcd9 100644 --- a/scripts/theming-sentinel.ts +++ b/scripts/theming-sentinel.ts @@ -207,6 +207,15 @@ const COMPONENT_OVERRIDES: Record< // its track and centre) and the demo boots `linear`, so 14 of its 28 tokens // had no node to paint. meter: { sweepAttr: { attr: 'data-shape', values: ['linear', 'circular'] } }, + // Same split as its twin: half the contract is the RING (12 size / thickness + // steps plus its track and its centre) and the demo boots `linear`. + progress: { + prepareWith: [ + "[data-uix-control]:has([data-uix-control-label]:text-is('indeterminate')) input[type=checkbox]", + "[data-uix-control]:has([data-uix-control-label]:text-is('orientation')) [data-uix-chip]:text-is('vertical')" + ], + sweepAttr: { attr: 'data-shape', values: ['linear', 'circular'] } + }, // Its dot / icon / remove parts are OPT-IN switches, all off by default. badge: { prepareWith: [ diff --git a/src/uix/eidos/components/progress/README.md b/src/uix/eidos/components/progress/README.md index 58cde505d..5b69d06f3 100644 --- a/src/uix/eidos/components/progress/README.md +++ b/src/uix/eidos/components/progress/README.md @@ -2,6 +2,48 @@ Fecha de revision: 2026-05-17. +## Talla y tema + +**43 claves públicas** en `lib/recipes/base.ts`: la barra por talla +(`height-{xs…xl}`, `radius-{xs…xl}`), el anillo por talla +(`ring-size-{xs…xl}`, `ring-thickness-{xs…xl}`), la altura del eje vertical +(`vertical-height`), los dos huecos de la rejilla raíz +(**`row-gap`**, **`column-gap`**), la tipografía de sus dos textos +(`label-*`, `value-text-*`, cinco claves cada uno), las tintas +(`track-bg`, `ring-track-bg`, `ring-center-bg`, `indicator-bg`, +`indicator-bg-loaded`), la transición (`transition-duration`, +`transition-ease`) y el barrido indeterminado +(`indeterminate-{width,duration,ease}`). La pestaña **Tokens** de su demo las +resuelve en vivo. + +Lo que entró el **2026-08-23** (69 % → 87 %): + +- **`row-gap` + `column-gap`** — el único knob de apariencia que iba a un + primitivo a pelo (`gap: var(--space-2) var(--space-3)`). Se parte en dos + porque sus dos valores DIFIEREN: el hueco de fila separa la línea de texto de + la barra, el de columna separa el rótulo del valor. Un `gap` único habría + nombrado un knob para dos (molde `chart.legend-row-gap` / `-column-gap`). +- **Los seis literales quedan FIRMADOS**, no acuñados: `100%` y `max-content` + son la geometría de la barra —llena la fila que le dan, o se encoge a su + propio grosor—, no una decisión de tema. Llevan su + `/* literal: */` en la declaración (válvula de recipe-contract §3). + +**Lo que NO se acuña, y por qué** (mismo veredicto que su gemelo `meter`): + +- **El `--radius-full` del anillo.** Es lo que hace circular a + `shape='circular'`: un `--progress-ring-radius` dejaría que un tema + des-redondease una forma que el consumidor pidió POR SU NOMBRE. Identidad, no + knob. Son los dos únicos knobs `global` que le quedan. +- **`--_progress-value-pct`.** Es el canal de VALOR: lo escribe soma en el + estilo inline del provider en cada render (`0–100`, saturado). Un público + encima mentiría — un tema no puede fijar el progreso de una tarea. + +**Lo que el guard da por silencioso** (tres de 43, todos medidos): +`indicator-bg-loaded` sólo pinta bajo `[data-state='loaded']`, y la corrida +mantiene `indeterminate` para alcanzar los tokens del barrido; los dos de +transición los congela el propio guard por diseño y se miden en una pasada sin +congelar. + ## Baseline Air no tenia `progress` en `glm-5:src/uix/air/components`; la referencia local diff --git a/src/uix/eidos/components/progress/progress.css b/src/uix/eidos/components/progress/progress.css index 19591f464..4bbb55f43 100644 --- a/src/uix/eidos/components/progress/progress.css +++ b/src/uix/eidos/components/progress/progress.css @@ -8,8 +8,9 @@ display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; - gap: var(--space-2) var(--space-3); - inline-size: 100%; + row-gap: var(--progress-row-gap); + column-gap: var(--progress-column-gap); + inline-size: 100%; /* literal: identity — a linear bar IS its container's width */ } [data-progress][data-size='xs'] { @@ -41,7 +42,7 @@ } [data-progress][data-orientation='vertical'] { - inline-size: max-content; + inline-size: max-content; /* literal: identity — it is its own thickness wide */ grid-template-columns: auto; justify-items: center; } @@ -51,7 +52,7 @@ position: relative; overflow: hidden; grid-column: 1 / -1; - inline-size: 100%; + inline-size: 100%; /* literal: identity — the track spans the row it is given */ block-size: var(--_progress-height); border-radius: var(--_progress-radius); background: var(--progress-track-bg); @@ -78,7 +79,7 @@ [data-progress][data-orientation='vertical'] [data-progress-indicator]::before { inset-block: auto 0; - inline-size: 100%; + inline-size: 100%; /* literal: identity — the fill spans the track's thickness */ block-size: calc(var(--_progress-value-pct, 0) * 1%); } @@ -99,12 +100,12 @@ [data-progress][data-orientation='vertical'][data-state='indeterminate'] [data-progress-indicator]::before { block-size: var(--progress-indeterminate-width); - inline-size: 100%; + inline-size: 100%; /* literal: identity — same span, sweeping the other axis */ animation-name: progress-indeterminate-vertical; } [data-progress][data-shape='circular'] { - inline-size: max-content; + inline-size: max-content; /* literal: identity — the ring is its own diameter wide */ grid-template-columns: auto; justify-items: center; justify-self: center; @@ -119,6 +120,10 @@ [data-progress][data-shape='circular'] [data-progress-indicator] { inline-size: var(--_progress-ring-size); block-size: var(--_progress-ring-size); + /* NOT a recipe token: `--radius-full` IS what makes `shape='circular'` + circular. A `--progress-ring-radius` would let a theme un-circle a shape + the consumer asked for BY NAME — identity, not a knob. Same reading, and + the same wording, as its twin `meter`. */ border-radius: var(--radius-full); background: conic-gradient( var(--_progress-indicator-bg) calc(var(--_progress-value-pct, 0) * 1%), @@ -131,7 +136,7 @@ inset: var(--_progress-ring-thickness); inline-size: auto; block-size: auto; - border-radius: var(--radius-full); + border-radius: var(--radius-full); /* same identity: the hole is round because the ring is */ background: var(--progress-ring-center-bg); transition: background var(--progress-transition-duration) var(--progress-transition-ease); } diff --git a/src/uix/eidos/generated/base.css b/src/uix/eidos/generated/base.css index 7d2be9e31..891e4e84b 100644 --- a/src/uix/eidos/generated/base.css +++ b/src/uix/eidos/generated/base.css @@ -2470,6 +2470,8 @@ --progress-height-lg: 8px; --progress-height-xl: 12px; --progress-vertical-height: 10rem; + --progress-row-gap: var(--space-2); + --progress-column-gap: var(--space-3); --progress-radius-xs: var(--radius-full); --progress-radius-sm: var(--radius-full); --progress-radius-md: var(--radius-full); diff --git a/src/uix/eidos/lib/recipes/base.ts b/src/uix/eidos/lib/recipes/base.ts index 5ee275f28..f81a0d70f 100644 --- a/src/uix/eidos/lib/recipes/base.ts +++ b/src/uix/eidos/lib/recipes/base.ts @@ -3797,6 +3797,12 @@ export const THEME_BASE_RECIPE_TOKENS = defineRecipes({ 'height-lg': '8px', 'height-xl': '12px', 'vertical-height': '10rem', + // The two axes of the root grid, split because their values DIFFER: the + // row gap separates the text row from the bar, the column gap separates + // the label from the value text. A single `gap` shorthand would name one + // knob for two (the `chart.legend-row-gap` / `-column-gap` pair). + 'row-gap': 'var(--space-2)', + 'column-gap': 'var(--space-3)', 'radius-xs': 'var(--radius-full)', 'radius-sm': 'var(--radius-full)', 'radius-md': 'var(--radius-full)', diff --git a/web/routes/uix/components/progress/+page.svelte b/web/routes/uix/components/progress/+page.svelte index 2f7aea6c0..74a4cd3a7 100644 --- a/web/routes/uix/components/progress/+page.svelte +++ b/web/routes/uix/components/progress/+page.svelte @@ -2,8 +2,9 @@ import { Progress, type ProgressShape, type ProgressSize } from '$uix/eidos/components/progress'; import { compileMorfo } from '$uix/morfo'; import { progressMorfo } from '@/uix/morfo/components/progress'; + import TokensPanel from '../../lib/TokensPanel.svelte'; - type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y'; + type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'tokens' | 'a11y'; type Orientation = 'horizontal' | 'vertical'; type TraceEntry = { event: string; family: string; intent?: string; at: number }; @@ -176,6 +177,9 @@ + @@ -457,6 +461,10 @@ {/if} + {#if tab === 'tokens'} + + {/if} + {#if tab === 'recipe'}

Eidos recipe