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/docs/process/open-color-cage-2026-07.md

13 KiB

title type audience status date
Handoff — Abrir la jaula del color (`color` = sistema completo en todos los componentes) process human + agent en curso — Fase 0/1/2a/2b ✅ · Fase 3 mayoría ✅ · cola de ~11 standalones + Fase 4/5 pendientes 2026-07-18 (actualizado tras la sesión de continuación, 7 commits)

Handoff — Abrir la jaula del color

Objetivo

El prop color de un componente debe aceptar todo el sistema de color del ecosistema — por role, por intent, por paleta (33 escalas donantes) y por valor (raw CSS) — en TODOS los componentes. Decisión de diseño del usuario (2026-07-18): revierte la restricción de THM-2 (2026-07-12) que dejaba los controles semánticos en subconjuntos; la jaula se abre siempre, sin excepciones (incluida la tinta de contenido).

Doctrina de respaldo: theming/reference.md §25 (THM-2)

  • §39 — color = IDENTIDAD (role/scale/custom), desacoplada de la evaluación (que vive en invalid + el intent del evento).

⚡ Empieza aquí (nueva sesión)

  1. Lee este doc entero + la memoria project-open-color-cage-2026-07-18.
  2. El motor y el patrón están LISTOS y probados. Lo que queda es ~11 componentes standalone HETEROGÉNEOS (§Cola). NO son un batch uniforme: cada uno rompe el patrón de una forma distinta y con su propia trampa.
  3. Verifica el estado: npm run check (⚠️ el total oscila 76↔94, NO es baseline estable; verifica CERO errores en los componentes que toques, no el total).
  4. Arranca por los MENOS peligrosos de la cola (skeleton/spinner/textarea), no por los portalados (color-picker/float-panel).

Estado — HECHO

Motor (Fase 0) ✅ — la costura compartida, LISTA

  • ComponentColorProp (src/uix/eidos/lib/types.ts) = ComponentColor | (string & {}) — el tipo canónico ABIERTO al que todos apuntan.
  • resolveComponentColor(color) (src/uix/eidos/lib/component-color.ts) — el helper del wrapper: { dataColor, isCustom, customStyle }. Canónico → data-color; valor CSS crudo → data-color-custom + seed --color-custom.
  • Derivación custom compartida (render-css.ts renderSharedPaletteLayer): [data-color-custom] deriva los 10 slots --palette-* desde var(--color-custom) por color-mix. El forward renderRecipePaletteForward emite [data-{c}][data-color], [data-{c}][data-color-custom] → toda receta con tokens _palette-* gana roles + 33 escalas + custom con CERO CSS extra.
  • Guard recipe-css-contract.test.ts con la forma del forward + invariante custom.

Fase 1/2a/2b ✅ (commit 149c0fef6, pre-continuación)

  • Eidos-wrapper (14): radio-group·checkbox·stepper·toggle-group·select·badge· editable·file-upload·tag-group·tags-input·surface·avatar·card. Ref: checkbox.
  • Soma-routed (button/switch/toggle): color por soma/morfo, dos ejes intent+color. Ref: button. (2 bugs de framework arreglados: html-presence con v.literal('') → usar v.propRef; custom pisaba intent evaluativo → anular.)

Fase 3 — familias (esta sesión, 7 commits) ✅

Commit Componentes
861427fe1 Field family (field base + search/password/mask/number/css/color/date/date-range/time-field) + calendar + month-grid + time-picker/time-range-picker + fix regresión runtime + 9 fixes de tipo (tests switch/toggle colorCustom)
4adcc4c7f sweep custom-threading: 12 sub-partes date/time (trigger/calendar/clock/input/root) por resolveComponentColor
889b03dae year-grid + range-calendar
c5699bd01 familia lista/data-grid (10): table·tree-grid·tree-view·virtual-list·virtual-grid·feed·drag-drop·grid-list·clipboard·carousel
528ddaa7f listbox + timeline + combobox
1efa03439 link + mark (tinta de contenido)
28aacf092 button-group + highlight (delegan a Button/Mark)

Cada familia verificada en Chrome (role · escala · custom → token compartido exacto).


Los PATRONES (elige el correcto por componente)

Antes de tocar un componente, identifica su patrón:

A. Eidos-wrapper (estampa data-color directo). Ref: checkbox. Ya tiene forward-ready recipe → solo tipo + wrapper resolveComponentColor.

B. Soma-routed (color por soma+morfo). Ref: button. Toca soma types/provider/ component + morfo + wrapper. Dos ejes intent+color.

C. Mini-recipe (cascada --_X-accent per-rol → forward). Ref: month-grid. El patrón dominante de Fase 3:

  1. Recipe (lib/recipes/base.ts): añade tokens _palette-{slot} (host = token de rol actual, normalmente primary → behavior-preserving).
  2. CSS: quita las decls base --_X-accent-* + los bloques per-rol [data-X][data-color='rol']; renombra los consumidores var(--_X-accent-*) → var(--_X-palette-*).
  3. types: XColor → ComponentColorProp.
  4. wrapper: resolveComponentColor (estampa el trío + style).
  5. npm run generate:eidos-css + verifica el forward en generated/base.css.

D. Tinta de contenido (color:/background: per-rol directo). Ref: link (1 slot text) / mark (element+text). Reemplaza la cascada color: var(--color-{rol}-text) por color: var(--_X-palette-text) + recipe _palette-text.

E. Delegante (pasa el color a un hijo ya abierto). Ref: button-group (contexto→Button) / highlight (→Mark). Solo tipo + wrapper.

⚠️ TRAMPAS (todas cazadas esta sesión — NO repetir)

  1. parts: SOLO se lee en la forma declarations: [...], no en { value, scope } (render-css.ts expandToDeclarationsWithParts l.2183). Si la cascada vive en [data-X-root] o [data-X-content] (no el provider bare), el recipe necesita '_palette-slot': { parts: ['root'], declarations: [{ value, scope: 'host' }] }. Verifica con grep '\[data-X...\]\[data-color=' X.css DÓNDE se estampa data-color.
  2. Verifica recipe-exists FIABLE antes de añadir (grep ^\t'?X'?: \{). Varios componentes YA tienen recipe (z-index/otros): drag-drop, combobox, timeline, color-picker, float-panel. FUSIONA en el existente, NO dupliques la clave (clave duplicada = el último gana, silencioso; svelte-check lo marca).
  3. Declara SOLO los slots con consumidor real (grep 'var(--_X-palette-slot)'). Slots sin var() consumidor = token de recipe HUÉRFANO → falla el orphan test. Si TODO estaba muerto (virtual-list/grid) → NO pongas recipe (tipo abierto + wrapper inerte basta).
  4. Trampa --x: inherit: un custom-prop con valor inherit NO guarda el token inherit; hace que el prop herede del padre (→ inválido). Para "default = inherit" usa una regla [data-X][data-color],[…custom]{ color: var(--_X-palette-text) } y deja la base en color: inherit (patrón de mark).
  5. Cross-portal: si el componente RE-DECLARA su accent en 2 scopes (trigger + contenido portalado), el forward en el root NO alcanza el portal. Requiere data-color
    • forward en el scope del portal (color-picker cae aquí — ver §Cola).
  6. accent bare vs accent-soft: renombra -soft PRIMERO, luego el bare var(--_X-accent) (con ) de cierre) → evita el solape de prefijo.

Cola — ~11 standalones HETEROGÉNEOS (lo que falta)

Cada uno es trabajo INDIVIDUAL con su análisis y verificación propia. Orden sugerido: los menos peligrosos primero.

Patrón D/simple (menos peligrosos — empieza aquí)

  • skeleton, spinner, textarea, metrics, form — tienen cascada per-rol pero cada uno pone una PROPIEDAD distinta (color/background/border) directa. Analiza qué propiedad tinta cada uno y a qué slot mapea (grep 'data-color=' + var(--color-). spinner además tiene | 'inherit' en su tipo (conservar como unión aditiva).
  • field-langs — FieldLangsColor = ColorRole, no estampa data-color (¿compone Field?); investigar cómo colorea.
  • radio-cards — AffirmativeColorRole; compone RadioGroup (ya abierto). Probable delegante (patrón E) o mini-recipe.
  • image — ImagePlaceholderColor = ColorRole | (string & {}) (ya semi-abierto); el placeholder. Poco trabajo.

Patrón C con TRAMPA (compound/portalado — CUIDADO, requieren verificación)

  • color-picker — cascada 1 slot (accent→border) en [data-color-picker], PERO re-declara --_color-picker-accent en 2 scopes (trigger l.28 + contenido portalado l.99). El forward en el root no alcanza el portal → el contenido portalado necesita su propio data-color+forward. Compound (root+trigger+ channel-input estampan data-color; las partes threading raw necesitan resolveComponentColor como el sweep de combobox). Recipe YA existe (fusionar). Intentado y revertido esta sesión por el matiz cross-portal.
  • float-panel — cascada 1 slot (accent→border) en [data-float-panel-content] (parte → parts: ['content']). PERO su default base es --_float-panel-accent: var(--float-panel-accent) y --float-panel-accent NO existe en el recipe → el comportamiento actual es "sin acento salvo data-color". Un host primary-border lo cambiaría a "siempre primary" (cambio silencioso). Verifica primero el default REAL (¿el content-wrapper siempre estampa data-color vía ctx?.color? ¿ctx.color default 'primary'?). Recipe YA existe (fusionar). Intentado y revertido esta sesión.

Especiales

  • proof-of-human — fixed-tone. Sus literales de color/font-size en clock.css/rotate-align.css YA fallan 2 tests del contract (raw-color + font-size) — añadir a FIXED_TONE_COMPONENTS (recipe-css-contract.test.ts) o tokenizar. Su color es accesorio.
  • chronos — en WIP_TRACKS (excluido del contract); scheduler sin commitear.
  • card-group — el .svelte raíz NO tiene prop color (sus items componen Card, ya abierto). card-group-item sí; revisar si necesita apertura.

Fase 4 — Tinta de contenido (code, display, heading, label)

Otro eje (primary|secondary|muted|disabled|on-solid). Abrir como unión que conserva su eje: ComponentColorProp | 'muted' | 'disabled' | 'on-solid'; cablear el color de texto al slot text de la paleta (patrón D, como link/mark). Nota: link/mark YA se hicieron con este patrón — reúsalo.

Fase 5 — Guard estructural + docs

  • Guard: test que falla si algún tipo *Color es más estrecho que ComponentColorProp (salvo la unión aditiva de tinta: | 'muted' | ...). Ancla: scripts/component-audit.ts:1327 o recipe-css-contract.test.ts. Esto ENFORCEA "la jaula siempre abierta" y cierra la iniciativa.
  • Docs: reference.md §25 + tracker continue-cleanroom-fixes-2026-07.md §THM-2 (registrar la reversión) + changelog.

Operativa (verificada esta sesión)

  • Dev server: preview_start con la config verify de .claude/launch.json (:5201). Reiniciar tras tocar un morfo (HMR no recarga morfo/*.ts fiable — compile cacheado por WeakMap).
  • ⚠️ check NO es baseline estable: la caché incremental de svelte-check aflora intermitentemente errores any PRE-EXISTENTES de demos ajenos (heroscrolling/ animations/palabras/alpha/temas): oscila 76↔94. La verificación FIABLE es CERO errores en los componentes TOCADOS (grep 'ERROR "src...components/X'), no el total.
  • Tras tocar un recipe: npm run generate:eidos-css + verifica el forward emite en generated/base.css (grep '\[data-X...\]\[data-color\],'). NO hace falta tras solo .svelte/.ts.
  • Contract test: npx vitest run src/uix/eidos/recipe-css-contract.test.ts — 26/28 pasan; los 2 fallos son proof-of-human (pre-existente). >2 fallos = tu cambio (orphan/phantom/forward).
  • Navegador: probe getComputedStyle de --{c}-palette-{slot} sobre el elemento que estampa data-color; fuerza data-color='risk' y compara con un <div data-color='risk'> probe (--palette-{slot}); custom con style.setProperty('--color-custom', '#00b894') → espera color-mix.

⚠️ ÍNDICE GIT COMPARTIDO

El working tree tiene WIP de OTROS tracks sin commitear. Al commitear: git reset -q + git add de rutas EXPLÍCITAS + git diff --cached --name-only para verificar ANTES de git commit -F - (backticks en el mensaje → usar -F, no -m). EXCLUIR siempre:

  • menubar (eidos/soma/morfo), dropdown-menu, palabras, words — track palabras.
  • soma/components/virtual-list/* + web/routes/uix/components/virtual-list/+page.svelte — el track de chat (chat-*) extiende VirtualList ("anchor end/chat mode"), AJENO al color. Yo solo toco eidos/components/virtual-list/*.
  • web/routes/alpha/, .claude/settings.local.json.
  • Cambios de comentario "Words"→"Palabras" en css ajenos (p.ej. color-picker.css).

Referencias de patrón (copiar de estos)

  • Mini-recipe (C): month-grid (recipe _palette-* + css + types + wrapper).
  • Con parts: combobox (parts: ['control','input','trigger','content']) / table (parts: ['root']).
  • Tinta (D): link (1 slot) / mark (element+text, regla colored-only).
  • Delegante (E): button-group / highlight.
  • Sweep de sub-partes que threading raw: workflow con ref select-trigger.svelte.

Powered by TurnKey Linux.