You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/web/routes/temas/grafito/README.md

113 lines
5.9 KiB

# Tema · Untitled UI · Carbon
Demo de theming en vivo para activeUIX sobre el sistema de Eidos. Es a la vez
un **tema completo** (`untitled-ui-light` / `untitled-ui-dark`) y un **playground**
que muestra todos los elementos del tema: roles de color, rampas físicas de 12
pasos, superficies, tipografía, espaciado, radios, sombras, tamaños y el aspecto
real de cada control con sus variantes — más la capa semántica (sema).
Ruta: `/temas/untitled-ui`.
## Identidad del tema
Fiel a [untitledui.com](https://untitledui.com) (tipografía Inter, sombras en
capas, radios de 8px, anillos de foco suaves) pero con una decisión deliberada:
el **primario es carbón** (grafito casi negro `#1F2024`), monocromo al estilo
Vercel / Linear — **no** el violeta de marca de UUI. El violeta de UUI (`#7F56D9`)
se reubica como **secundario**.
Los 9 roles canónicos del framework quedan retintados con jerarquía diferenciada
(ninguno se repite):
| Rol | Escala | Color | Papel |
| --- | --- | --- | --- |
| `primary` | carbon | `#1F2024` | Acción principal, monocroma. Texto auto-invertido vía `slots.contrast: '1'`. |
| `secondary` | violet | `#7F56D9` | Violeta de marca UUI. |
| `tertiary` | blue | `#1570EF` | Acento azul. |
| `neutral` | gray | `#667085` | Gris frío UUI. |
| `affirm` | teal | — | Positivo ligero (baja activación). |
| `fulfill` | green | — | Éxito / completado. |
| `risk` | amber | `#DC6803` | Aviso. |
| `threat` | red | `#D92D20` | Error / peligro. |
| `loss` | plum | `#7A3AAD` | Pérdida grave: violeta sombrío, posterior (más oscuro que el secundario). |
Otros tokens del tema:
- **Tipografía**: Inter (`primary` / `secondary` / `display`), Roboto Mono (`mono`).
Letter-spacing negativo en los displays (`hero` / `h1` / `h2` a `-0.02em`, `h3` a `-0.01em`).
- **Radios**: escala con `md = 8px` como base UUI (`none` → `full`).
- **Foco**: `focusRing` con `offset 1px` + `width 3px`; el halo lavanda se pinta
en `untitled-ui.css` (`--uui-ring`, derivado de `--color-secondary-solid`).
- **Sombras**: set en capas estilo UUI (light + dark).
- **Densidad**: `compact` / `comfortable` / `spacious` — **funcional**, escala el
espaciado y la altura de los controles (ver «Correcciones del engine» abajo).
El tema vive en `_lib/untitled-ui.ts` como un `EidosConfig` independiente
(no parchea el `base`): define escalas light/dark, el `ColorRoleMap` y los dos
themes. No inventa variants ni roles nuevos — solo retinta lo canónico.
## Componentes mostrados
Foundations (markup propio sobre tokens del tema): roles + rampas + superficies,
tipografía, espaciado / radio / sombra / tamaño.
Controles eidos reales, todos dirigidos por el tema:
- **Button** (6 variants × roles × tamaños × estados)
- **Badge**
- **Form**: Field, Select, Checkbox, RadioGroup, Switch, Slider
- **Feedback**: Banner, Progress, Avatar, Card
- **Tabs**, **Accordion**
- **Toggle**, **ToggleGroup** (single + multiple, segmentado)
- **Toolbar**
- **Overlays**: Popover, Dialog (portaleados)
- **Menús**: Menubar, DropdownMenu, ContextMenu, Tooltip (portaleados)
- **Semántica**: la capa sema (sonido + haptic + reacción visual `data-event-*`)
encendida en el layout vía `createActiveUix({ events: { sound, haptic, components } })`.
## Estructura
| Archivo | Rol |
| --- | --- |
| `_lib/untitled-ui.ts` | Config del tema (`EidosConfig`): escalas, roles, themes light/dark. Exporta `THEME_ROLES`, `THEME_SCALES`, `COLOR_STEPS`. |
| `+layout@.svelte` | Raíz de composición. Arranca `ActiveUix` + `Soma` + `ActiveEidos` con el tema. Posee modo (claro/oscuro) y densidad como fuentes visuales. El `@` resetea la herencia del chrome de `/uix`. |
| `+page.svelte` | La página demo. |
| `theme.css` | Chrome del shell + helpers de layout (`[data-temas-*]`). |
| `untitled-ui.css` | Capa de pulido scoped a `[data-theme^='untitled-ui']`: anillo lavanda, sombras de control, bordes. |
## Correcciones del engine de theming (dependencias)
Este tema fue el primer consumidor que reveló dos bugs del engine de Eidos,
corregidos **a nivel engine** (sin deuda en el tema). Documentados en detalle en
[`src/uix/eidos/THEMING.md` §20](../../../../src/uix/eidos/THEMING.md):
1. **Densidad inerte** — `data-density` no afectaba a nada. Fix: `renderStaticCss`
emite `space` y `control-height` como `calc(value * var(--density-*-scale))`,
de modo que `[data-density]` reescala de verdad. (§20.1)
2. **`contrast` ilegible sobre sólidos** — el texto sobre el sólido de color
resolvía al paso 12 de la escala (casi invisible). Fix: el slot `contrast` por
defecto resuelve a `var(--color-content-on-solid, …)`. Por eso el primario
carbón lleva texto casi blanco sin configurar nada extra. (§20.2)
## Hallazgo de autoría: `bind:value` debe respetar el default `$bindable`
La página tuvo un síntoma engañoso: bajo SSR renderizaba completa (~1.1 MB) pero
la hidratación en cliente **desmontaba** casi todo el árbol (los componentes
quedaban como anclas vacías `<!---->`), sin error visible en consola. Parecía un
fallo de hidratación de los componentes con portal.
La causa real era un único `bind:value={menubarValue}` con
`menubarValue = $state(undefined)`, mientras `<Menubar>` declara
`value = $bindable('')`. Svelte 5 lanza `props_invalid_value` («Cannot do
`bind:value={undefined}` when `value` has a fallback value») **durante** la
hidratación; el error aborta el render de la página y desmonta el árbol.
Lección: al usar `bind:` contra un prop con default `$bindable`, el estado local
debe inicializarse con un valor del mismo tipo que el default — nunca `undefined`.
Aquí: `menubarValue = $state('')` y `align = $state<string[]>(['left'])`
(`ToggleGroup` usa `value = $bindable([])`, también para `type="single"`).
No era un bug del engine de theming ni de los portales: los componentes con portal
(Popover / Dialog / Menubar / DropdownMenu / Tooltip) renderizan, hidratan y abren
correctamente cuando el `bind:value` es válido.

Powered by TurnKey Linux.