From 152d2ad96009adff88c364f0a8b47aec3d5bf188 Mon Sep 17 00:00:00 2001 From: dev Date: Tue, 2 Jun 2026 03:24:40 +0200 Subject: [PATCH] Theming: Radix-parity palette + intent auto-derivation + color-model docs Two-level color model settled (THEMING.md section 25), replacing the anchor RFC: the palette is the source (scales, directly usable, designable); hierarchy roles alias scales explicitly; intents auto-derive from the palette by the book's canonical convention. - Palette library expanded 12 -> 31 scales at Radix Colors parity (exact values): radix-scales.ts (19 added: mauve/sage/olive/sand/tomato/ruby/crimson/plum/ violet/iris/indigo/jade/grass/brown/sky/mint/lime/gold/bronze) spread into base.ts. Each directly usable as --scale-{name}-{step}. - Intent auto-derivation: CANONICAL_INTENT_SCALES (neutral->gray, affirm->teal, fulfill->green, risk->amber, threat->red, loss->plum) + completeColorRoleMap. Intents omitted from a theme role map fill from the convention (identity = step 9); slots derive normally; override optional. ColorRoleMap: hierarchy required, intents optional. - Validation: hierarchy roles required; omitted intents validate the canonical scale exists in the palette. - index: export ScalingKey / SCALING_KEYS. - docs: THEMING.md section 25 (full color model + decisions), section 21 marked resolved, COLOR_MODEL_RFC resolved (anchor rejected). - test: base library asserts 31 scales x 12 steps. Verified: npm run check (0 new errors), vitest eidos (0 new regressions), browser (intents auto-derive: affirm=teal #0E9384, risk=amber #DC6803, loss=plum #7A3AAD at step 9). Co-Authored-By: Claude Opus 4.8 --- src/uix/eidos/COLOR_MODEL_RFC.md | 17 +- src/uix/eidos/THEMING.md | 91 ++- src/uix/eidos/active-eidos-config.test.ts | 13 +- src/uix/eidos/generated/base.css | 912 ++++++++++++++++++++++ src/uix/eidos/index.ts | 2 + src/uix/eidos/lib/config-types.ts | 37 +- src/uix/eidos/lib/config.ts | 23 +- src/uix/eidos/lib/render-css.ts | 8 +- src/uix/eidos/lib/themes/base.ts | 7 +- src/uix/eidos/lib/themes/radix-scales.ts | 71 ++ 10 files changed, 1168 insertions(+), 13 deletions(-) create mode 100644 src/uix/eidos/lib/themes/radix-scales.ts diff --git a/src/uix/eidos/COLOR_MODEL_RFC.md b/src/uix/eidos/COLOR_MODEL_RFC.md index a95cc02ed..4334db33e 100644 --- a/src/uix/eidos/COLOR_MODEL_RFC.md +++ b/src/uix/eidos/COLOR_MODEL_RFC.md @@ -1,8 +1,19 @@ # RFC — Modelo de color: accents ricos + intents de un solo ancla -> **Estado: PROPUESTA — no implementada.** (2026-06-01) -> El modelo vigente sigue siendo el de `THEMING.md` (rol → escala de 12 pasos). -> Este documento captura el diseño para decidir/implementar más adelante. +> **Estado: RESUELTO (2026-06-02).** El modelo de color quedó decidido — la +> referencia canónica es **THEMING.md §25**. +> +> **Qué se adoptó**: paleta rica (librería ampliada a 31 escalas Radix) + capa +> semántica de alias, y los **intents auto-derivan de la paleta por convención +> del libro** (`CANONICAL_INTENT_SCALES`, identidad = step 9). Roles de jerarquía +> = alias explícito. Override por componente vía prop `color`. +> +> **Qué se DESCARTÓ**: el "intent = ancla de un solo color" con slots derivados +> inline (este documento, §4-5). Radix no lo hace (genera una *escala* desde un +> hex y la aliasa), y con la paleta rica el problema que lo motivaba (autorar 12 +> pasos para `loss`) desaparece — `loss` aliasa la escala `plum` de la paleta. +> +> Lo de abajo se conserva como registro histórico de la propuesta original. ## 0. Origen diff --git a/src/uix/eidos/THEMING.md b/src/uix/eidos/THEMING.md index 46d6963ce..635176aac 100644 --- a/src/uix/eidos/THEMING.md +++ b/src/uix/eidos/THEMING.md @@ -1841,7 +1841,13 @@ step 11). --- -## 21. Propuesta abierta — modelo de color de dos niveles (RFC, NO implementado) +## 21. Modelo de color de dos niveles (RFC — RESUELTO en §25) + +> **Resuelto (2026-06-02).** El modelo de color quedó decidido — ver **§25**. +> Se adoptó "paleta rica + capa semántica de alias / auto-derivación" y se +> **descartó** "intent = ancla de un solo color" (Radix no lo hace, y con una +> paleta rica el problema que motivaba el ancla desaparece). Lo de abajo se +> conserva como registro histórico de la propuesta original. Tras el sprint de theming surgió una observación de fondo (comparando con Radix Themes): hoy **cada rol de color exige una escala de 12 pasos**, incluidos @@ -2018,6 +2024,89 @@ ven casi idénticos (a2 ≈ el step-1 anterior); sobre fondos no uniformes ahora --- +## 25. Modelo de color — paleta + roles/intents derivados (2026-06-02) + +Decisiones **cerradas** sobre el modelo de color. Resuelve el RFC §21. Es, 1:1, +el modelo de **Radix Themes**: una **paleta** de escalas + una **capa semántica** +de alias + **override por componente**. Lo único propio es que los **intents** +(capa del libro) **auto-derivan** de la paleta por convención. + +### 25.1 — Las tres capas + +| Capa | Qué es | Cómo se define | +| --- | --- | --- | +| **Paleta** | librería de escalas de 12 pasos | `--scale-{name}-{step}` (+ alpha `--scale-{name}-a{step}`) · directamente usable · **diseñable por el tema** | +| **Roles** (jerarquía) | `primary` · `secondary` · `tertiary` | **alias explícito** a una escala (decisión de marca · obligatorio) | +| **Intents** | `neutral` + `affirm`/`fulfill`/`risk`/`threat`/`loss` | **auto-derivados** de la paleta por convención del libro · identidad = step 9 · slots derivan normal · override opcional | + +Los componentes consumen la capa semántica (`--color-{role}-{slot}`) y pueden +**override** su color a cualquier escala vía la prop `color` / `data-color`. + +### 25.2 — Paleta (la fuente, diseñable) + +- Escalas **funcionales** de 12 pasos: `1-2` fondos · `3-5` componente · `6-8` + bordes · **`9` sólido** · `10` hover · `11-12` texto. El **representativo** de + una escala es el **step 9** (el sólido), NO el medio geométrico (step 6, que es + un tono de borde lavado). +- **Directamente usable**: cualquier paso es `var(--scale-{name}-{step})` + (p. ej. `var(--scale-green-10)`). **No** existe alias corto `--{name}-{step}`: + dos formas para el mismo valor crearían ambigüedad sobre cuál es la canónica. +- **Diseñable**: la paleta la trae el tema (dominio del diseñador). El framework + envía una paleta por defecto de **31 escalas** (valores exactos de Radix + Colors, en `lib/themes/radix-scales.ts` + `base.ts`) — pero es "la paleta", no + "la de Radix": un tema la reemplaza/amplía. Un color de marca se añade como + **una escala** (autorada o generada), nunca como un valor inline suelto. + +### 25.3 — Roles de jerarquía (alias explícito) + +`primary` / `secondary` / `tertiary` son decisiones de marca sin color canónico: +el tema **DEBE** mapearlos a una escala de la paleta. Pueden llevar override de +slots (p. ej. un primario monocromo con `slots: { contrast: '1' }`). + +### 25.4 — Intents auto-derivados (convención del libro) + +- Los 6 intents tienen color canónico definido en el libro *Diseñando lo que + ocurre*. La convención `INTENT → escala` vive en `CANONICAL_INTENT_SCALES` + (`lib/config-types.ts`): + `neutral→gray · affirm→teal · fulfill→green · risk→amber · threat→red · loss→plum`. +- Un intent **omitido** del mapa de roles **auto-deriva** de la paleta por esa + convención (`completeColorRoleMap`, consumido por `render-css` y la validación). + Su **identidad es el sólido (step 9)**; los 9 slots derivan normal. La paleta + debe proveer esas escalas (o el tema overridea el intent mapeándolo explícito). +- **Tipos**: en `ColorRoleMap` la jerarquía es **obligatoria** y los intents + **opcionales** — `Record & Partial>`. +- **`neutral`** es el 6º intent pero **sin valencia**: funciona como gris de + superficies/bordes/texto, por eso auto-deriva a una escala gris (no es una + señal valenced). Las 5 valenced llevan la carga. +- Doctrina: **el color EXPRESA el intent, no lo define** — la valencia/activación + la lleva la capa **sema** (sonido/haptic/motion); el color solo aporta la + identidad de hue. + +### 25.5 — Override por componente + +Cualquier componente acepta `color="..."` (cualquier escala de la paleta) → la +cascada `_accent-*` del recipe remapea sus tokens a esa escala para esa +instancia. Equivalente a `