astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
19 Commits (6998c5bde229ddc75244aeeb85e9280a2ed63cbf)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
6998c5bde2 |
feat(eidos): depth Fase 4 — atmosphere (frost) + applyDepth runtime builder
Closes the depth channel. Atmosphere as the channel's materials layer:
- Per-plane `blur` cue (overlay 10px, modal 16px) + an opt-in frost rule
`[data-depth=`{plane}`][data-frost]` -> translucent surface (color-mix 80%) +
backdrop-filter blur. Gated on data-frost so it never turns an opaque overlay
translucent by default; specificity 0,2,0 reliably overrides the component bg.
- buildDepth(planes) (pure) + ActiveEidos.applyDepth/clearDepth — retune any
plane cue (surface/shadow/halo/blur/scrim/z) at runtime, the depth sibling of
applyColorScheme / applyTypeScale. Exported from $uix/eidos.
Showcase: /temas/profundidad section Materiales — a frosted-glass panel over a
vivid color mesh (frost blur + shadow + halo).
The `scrim` cue stays an available token without a wired rule — modal backdrops
are component-managed.
Verified: npm run check 0 errors; eidos 185/188 (3 pre-existing `words` failures,
unrelated). New tests: frost emission + applyDepth. Regenerated generated/base.css.
Docs: DEPTH_ENGINE_RFC Fase 4 + token contract, THEMING 29.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
271a2f8ff0 |
feat(eidos): depth adoption — elevated components consume the channel (shadow + halo)
The Fase 2 rim halo now reaches real UI, not just the showcase. Each elevated
component's shadow signal (recipe tokens in recipes/base.ts + the few direct
box-shadow uses) now composes `var(--depth-{plane}-shadow), var(--depth-{plane}-halo)`.
Reaches: popover, dialog, drawer, dropdown/context/navigation-menu, menubar,
select, tooltip, card, combobox, command, link-preview, words.
Shadow signal only — z-index stays component-managed (the z bands are finer than
the 5 planos), so zero stacking risk. Verified: dialog keeps its own z-index 71
and composes drop shadow + oklab halo. Retuning a plane now retunes every
component on it.
Verified: npm run check 0 errors; eidos 183/186 (3 pre-existing `words` failures,
unrelated). Regenerated generated/base.css. THEMING 29 updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
0e0fbc05d7 |
feat(eidos): depth Fase 2 (oklab rim halo) + reference-grade /temas/profundidad
Depth engine — Fase 2 (mode-adaptive mezcla): - New `halo` cue per plane: a top-edge rim-light computed in oklab (color-mix(in oklab, white N%, transparent); 5/7/8% on raised/overlay/modal). The `[data-depth]` box-shadow now composes `shadow, halo`. Invisible on light surfaces (the drop shadow leads), the lift cue on dark surfaces (where the drop shadow barely shows) — the mode-adaptive answer to "shadow lies in dark", scoped to the depth channel (global --shadow-* untouched). - Wired through config-types (DepthPlane.halo) + render-css (declare + compose) + config validation + STATIC_DEPTH + regenerated generated/base.css. Showcase — /temas/profundidad to reference depth (4 -> 9 sections): matches Material elevation catalog breadth and adds the two axes it lacks (eventful + open cage): - Responde a cada estado — dynamic elevation, live interactive control - La escalera de planos — z-stack of the 5 planes - Catalogo de planos en reposo — the resting-elevation spec table, our vocabulary - Luz vs sombra — light/dark side-by-side showing the halo mechanism - Accesibilidad — never the only channel, reduced-motion, forced-colors, contrast - Fix: mirror data-theme onto <html> so :root depth tokens stay mode-aware Docs: DEPTH_ENGINE_RFC (Fase 2 + 5 done, token contract + halo), THEMING 29. Verified: npm run check 0 errors; depth tests 50/50 (updated the box-shadow assertion to the shadow,halo composition). Pre-existing `words` recipe-contract failures unrelated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
019b93d284 |
docs(eidos): THEMING §29 — depth channel (planes + eventful + jaula abierta)
User-facing summary of the depth system (DEPTH_ENGINE_RFC remains canonical): the two moments (data-depth resting plane + the present-rise/press-squeeze firma), the config-driven planes composing existing primitives, the jaula-abierta escape hatches, and the deferred refinements + component-adoption follow-up. Closes Fase 5 docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
4fe2ee27df |
feat(eidos): close typography hygiene — semantic tokens config-driven + font preloads
#2 Semantic leading/tracking config-driven: the per-role `--leading-{role}` (ui/prose/text/heading/display) + `--tracking-{role}` (badge/label/ui/prose/ heading/display) tokens were hardcoded in render-css; moved to `typography.semanticLeading` / `semanticTracking` (STATIC_TYPOGRAPHY), emitted config-driven + validated, so a theme can retune them. Byte-identical output (generated/base.css unchanged — same values, same order). #3 Font preloads: `collectFontPreloads(typography)` (pure) + `eidos.fontPreloads()` surface `<link rel=preload>` descriptors for families flagged `preload: true` (the engine emits CSS, not head markup), for the app `<svelte:head>`. Inert until a theme opts in. Docs: TYPOGRAPHY_ENGINE_RFC fases marked closed + Fase 4 (the two-zone scale is intentional — documented, not rewired); THEMING §10 — applyColorScheme + applyTypeScale system builders. `npm run check` 0 errors; new font-preload tests + config/generated tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
21b2329a66 |
feat(eidos): prefers-contrast: more — stronger neutral chrome a11y (P3-2 follow-up)
Completes the forced-colors a11y work. Users who request more contrast (macOS "Increase contrast", Windows, etc.) now get strengthened neutral chrome: borders bumped to neutral 7/8/9 (subtle/default/strong) and de-emphasized text to 12/11 (secondary/muted). Solid fills + primary text are already high-contrast, so they stay. renderPrefersContrastBlock emits a @media (prefers-contrast: more) block using `:root:root` (specificity 0,2,0) so it wins over the theme's :root regardless of stylesheet order. Values reference --primitive-neutral-* (resolve from the cascade; a theme omitting them just no-ops the declaration — graceful). Strictly additive (gated by the media query) and strictly STRONGER, so it can't regress the default look. Also marks audit P3-6 resolved: dispose() already routes documentElement access via dom (#lastAttrs.target + dom.apply), no direct document access remains. - generated/base.css regenerated. test: renderStaticCss emits the prefers-contrast block. docs: THEMING §28 + audit P3-2/P3-6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
4eab3306b8 |
feat(eidos): forced-colors focus a11y (P3-2) + role border ramp 6->7 (P3-3)
Closes the two color-quality items from THEMING_AUDIT P3.
P3-2 · forced-colors (Windows High Contrast): under @media (forced-colors: active) the
browser auto-maps borders/text/backgrounds to system colors BUT drops box-shadow — so
the box-shadow focus ring (--focus-ring) vanishes and keyboard focus disappears. The
foundation now always emits a system-colored outline fallback:
@media (forced-colors: active) {
:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
}
Components that already focus via outline (e.g. Button) keep theirs by specificity; this
is the fallback for the box-shadow ones. renderForcedColorsBlock in render-css.ts.
P3-3 · role border ramp: the per-role `border` slot moved step 6 -> 7. In Radix's
functional scale 6 is a subtle separator and 7 is the UI element border; step 6 read
washed-out on real element borders (outline/surface/controls). element/hover/active
(3/4/5) stay — Radix-canonical for component bg. DEFAULT_COLOR_ROLE_SLOT_STEPS.
- generated/base.css regenerated (forced-colors block + --color-{role}-border -> step 7).
- Verified in browser: --color-primary-border now resolves to primitive-7 (oklch 0.80
0.092 vs the softer step-6 0.86 0.072); checkbox borders render defined, not broken.
- test: renderStaticCss emits the forced-colors outline block.
- docs: THEMING §28 + audit P3-1/2/3 marked resolved + README ref row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
0bb03559a9 |
feat(eidos): wide-gamut-true generator — buildScheme/applyColorScheme emit oklch()
The theme builder now carries REAL wide-gamut, not just sRGB reformatted. generateScale
keeps raw OKLCH (no clamp), so a seed whose chroma exceeds sRGB renders more saturated
on P3 than its hex fallback.
- build-scheme.ts: result gains `wideGamut` (oklch() per opaque step) + `roles[].stepsOklch`;
`variables` stays hex (fallback + introspection). New `schemeDeclarations(result, {fallback})`
flattens to CSS lines — dual hex+oklch stack (default) or oklch-only (fallback:false,
for inline style where the CSSOM keeps one value per prop).
- ActiveEidos.#renderSchemeCss: emits the dual stack via schemeDeclarations → the applied
scheme block is wide-gamut on P3, sRGB-safe everywhere.
- index: export schemeDeclarations + SchemeDeclarationsOptions.
- temas/color demo: new "vivacidad P3" slider pushes the seed chroma past sRGB +
a "fuera de sRGB -> P3" badge (isInSrgbGamut). themeOverride now applies oklch
(wide-gamut). Verified: vivacity x1.70 -> primary-9 chroma 0.18 -> 0.31, badge on.
- tests: wide-gamut chroma retention (stepsOklch > hex fallback) + schemeDeclarations
dual/single; active-eidos scheme block asserts oklch(). 31/31 green.
- docs: THEMING §26/§27 + RFC §6.2.
Honest scope unchanged: the AUTHORED Radix palette stays exact sRGB (no regression).
Wide-gamut lives in the generator path (vivid seeds / OKLCH-authored themes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
909ab7f944 |
feat(eidos): wide-gamut OKLCH output, default-on (RFC Phase 2, strategy A)
Each palette step is now emitted twice: the hex as a universal fallback, then an
oklch() sibling that wins where supported (Chrome 111+/Safari 15.4+/Firefox 113+).
The token layer is now OKLCH-native and wide-gamut-ready, with NO @media and NO
config flag (it is the default behaviour).
- render-css `appendColorScaleDeclarations`: hex line + `oklch()` sibling per
`--scale-{name}-{step}`. Only opaque, parseable steps get the sibling; empty/
non-color values keep just the fallback. `--primitive-*`/`--color-*` are var()
refs (untouched); alpha scales stay color-mix/rgba.
- generated/base.css regenerated (+744 oklch sibling lines: 31 scales x 12 x 2 modes).
Honest scope: the shipped Radix palette is authored in sRGB hex, so its oklch()
siblings are sRGB-equivalent (verified: --scale-purple-9 -> oklch(0.5556 0.1829
305.86) paints #8e4ec6) -- identical today. The win is the OKLCH-native foundation:
an OKLCH-authored theme or a vivid generated scheme now renders wider on P3 with no
extra work. Making the SHIPPED palette visibly wide-gamut is Phase 3.
Tests: full eidos suite green except 3 pre-existing words-track failures (confirmed
unrelated via baseline). Docs: RFC §7 (status) + THEMING §27 + README ref row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
c4d2e34dbc |
feat(eidos): runtime theme builder API — eidos.applyColorScheme(seed)
RFC Phase 4: derive a whole-system color scheme from ONE brand seed at runtime.
Packages the demo-only builder into a first-class, tested API.
- build-scheme.ts (pure): buildScheme(seed, opts) composes the uix.color engine
(deriveScheme -> generateScale -> APCA on-solid -> compositing-inverse alpha)
into the `--primitive-{role}-*` (+ `--color-{role}-contrast`) override map.
seed -> { variables, roles }. No DOM. 6 tests.
- ActiveEidos.applyColorScheme(seed, opts) / clearColorScheme(): resolves donor
scales + background from the active theme, writes a managed `uix-eidos-scheme`
style block AFTER the theme block (wins the cascade), and RE-DERIVES on mode
change (follows light/dark). Returns BuildSchemeResult for introspection. opts:
variant (tonal|vibrant|monochrome) + temper (intent coherence, keeps hue) +
per-role overrides + selector. 4 tests (return value, intents, DOM block
ordering + clear, mode re-derivation).
- index.ts: export buildScheme + ApplyColorSchemeOptions + BuildScheme* types.
- temas/color demo: themeOverride now dogfoods buildScheme (drops the duplicated
emitRole/rgbaStr; identical output verified in-browser).
- generated/base.css: regenerated for the loss->plum role fix (binding layer
--primitive-loss-* now points at --scale-plum-*; keeps the contract test green).
- docs: THEMING.md SS26 + COLOR_ENGINE_RFC SS6.2 (status: landed) + README ref row.
Overriding the binding layer reprojects every --color-{role}-{slot} + the neutral
chrome downstream; the 31-scale palette stays put. Math in $color, composition in
eidos/lib (pure), DOM application in ActiveEidos.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
0d66e5a4e7 |
fix: address architectural audit findings + sync ecosystem docs
Audit: src/audit-opus-4-6-26.md. All non-words findings remediated. Code: - E1: navigation-menu indicator data-state visible -> open (render bug; the active underline was permanently invisible). Clears the only invalid lint selector. - SO1 + E2: raw `new ResizeObserver` -> ActiveDom.observeResize in carousel-provider and the canvas-text useContainerWidth hook (+ s-text / s-text-virtual-list pass eidos.dom). iframe/popup-safe, lifecycle-tracked. - A1: defineUixServices now registers `motion`, so attach-mode app.motion is real and the active-uix fallback becomes the true edge case (test guard updated). - A2/A4: contracts.ts pins `motion` + `announce` in ActiveUixServiceContract + publicSurface; dispose() comment corrected. - SO2: carousel drops the hardcoded `transform 300ms ease-out` (the recipe already handles it via [data-dragging]); also fixed the recipe's undefined `--duration-base` token -> `--duration-slow` (it was masked by the inline). - S1: HapticChannel reduced-motion via an injected ActiveDom port (mirrors SoundChannelDom) instead of global matchMedia. - T1: 10 sites repointed `$libs/dom` -> `$adom` (sema x5 + its tests x3, active-uix value import, arts/prefs). - M2 / S2 / S3: dead code removed (button `states:['idle','loading']`, SemaRuntimeChannelId, SEMA_VALENCED_FAMILY_LIST). Docs: - Motion-as-service reflected across the ecosystem: CLAUDE.md (aliases + arch + service note), arts/README, active_architecture, soma SOMA_ARCHITECTURE, eidos README, eidos-motion.md. - X1: CLAUDE.md "5 canonical channels" (false) -> the single canonical narrative (8 book channels; Sema runs 2 + visual meta-channel, Eidos materializes 5). - X2/X3/X4: sema/README (8 families + intentRequirement/intentGuidance split), types.ts JSDoc (SEMA_INTENT_POLICY -> SEMA_FAMILY_POLICY), engine.ts cascade 6->5, alias table ($frontend out, $lang->$langs, +$clipboard). - E4: codex_audit.md HISTORICO banner. Deferred: SU2 (test-only layering, not a build violation); Words M1/T5/E3 (WIP). Verify: npm run check -> 1 pre-existing error (grafito), 0 new; sema 152/152, contracts 31/32 (1 pre-existing words), carousel 4/4, motion 22/22. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
8090efc833 |
docs(theming): align THEMING.md + README with current color/scaling engine
Reconcile the theming reference with the engine as already committed (color-model redesign, scaling axis, P2 fixes) so the doc is internally consistent: - TOC: add §23 (scaling), §24 (P2 corrections), §25 (color model); fix the §21 entry to its resolved heading. - §4: intent->scale mapping was stale (risk->amber not orange, loss->plum not purple); note intents auto-derive via CANONICAL_INTENT_SCALES (identity = step 9, cross-ref §25); correct token counts (31-scale palette = 744 --scale-* tokens; 9 roles = 216 primitives). - §3 / anti-pattern G: "30 escalas" -> 31; reconcile "never add a scale" with §25.7 (a brand theme brings its own palette). - §21 / §22: mark the two-level color RFC as resolved in §25 (anchor model discarded); drop the stale present-tense "vigente" claim. - README reference table: add §23 / §24 / §25 rows. Docs only -- no engine or demo changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
4 months ago |
|
|
152d2ad960 |
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 <noreply@anthropic.com>
|
4 months ago |
|
|
66ce4f354d |
Theming: on-solid contrast by luminance (P2-2) + translucent role surfaces (P2-4)
Two audit P2 quality defects, fixed at engine level.
P2-2 - on-solid text illegible on light solids:
The `contrast` slot defaulted to `--color-content-on-solid` (white) for every
role. On light solids (amber/yellow, risk=orange ~2.3:1) white is sub-AA. The
engine now picks by WCAG contrast (gamma-linearized) of the role step-9: when
white fails (<3:1) it uses `--color-content-on-solid-contrast` (a dark, new
OPTIONAL `content.onSolidContrast` semantic, #1c1917 in base). Only risk flips
to dark in base (5.89:1); purple/red/teal/green keep white (convention, >=3:1).
An explicit `slots.contrast` override is still honored verbatim.
P2-4 - opaque tinted soft surfaces:
The soft variant tint (Button + Badge `{role}-soft-bg`) was opaque (step-1 track
+ opaque color-mix hover) so it did not composite over non-uniform backgrounds.
New derived tokens `--color-{role}-surface` (= a2) + `--color-{role}-surface-hover`
(= a3) are translucent by construction (compositing-inverse alpha). Button/Badge
soft consume them. Toast/Tabs untouched - they are cards, opacity is correct.
- config-types: optional onSolidContrast + CONTENT_COLOR_OPTIONAL_KEYS.
- config: content keySet allows the optional key; validator value-checks it.
- render-css: wcagContrastRatio/wcagRelativeLuminance; luminance pick; emit
on-solid-contrast + surface/surface-hover.
- contract: on-solid-contrast + surface tokens per role.
- themes/base: onSolidContrast #1c1917 (light + dark).
- recipes/base: Button + Badge soft-bg -> surface, soft-bg-hover -> surface-hover.
- docs: THEMING.md section 24 + section 22 item 2; audit P2-2/P2-4 resolved.
Verified: npm run check (0 new errors), vitest eidos (0 new regressions),
browser runtime (risk 5.89:1 dark text, surfaces translucent rgba).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
4 months ago |
|
|
bceaef41e0 |
Theming: add `scaling` zoom axis (Radix parity), separate from density
Introduce a global zoom axis independent of density, in parity with Radix
Themes' `scaling` (90/95/100/105/110%). Scaling zooms px metrics INCLUDING
typography (font-size, icon-size, space, control-height); density only moves
layout rhythm + control height and leaves text fixed. The two axes compose
multiplicatively.
- config-types: SCALING_KEYS / ScalingKey / DEFAULT_SCALING; DensityPrimitiveSet
drops the dead `scale` + `contentScale` (kept spaceScale, controlScale).
- primitives/static: STATIC_SCALING (0.9..1.1).
- render-css: appendScaledMetricDeclarations wraps metrics in
calc(<raw>[ * var(--density-x-scale)] * var(--scaling)); appendScalingDeclarations
emits --scaling-{key} + --scaling default; renderScalingBlocks emits
[data-scaling] blocks. line-height/radius/border/shadow excluded.
- config + contract: prune the removed density scalars.
- active-eidos: `scaling` / `scalingSource` options, getScaling() on the
preference source, data-scaling projection + dispose cleanup.
- docs: THEMING.md section 23 + 20.1 reconcile; README density/scaling; SCALING_RFC.md.
Verified: npm run check (0 new errors), vitest eidos (0 new regressions),
browser cascade at 90/100/110 scales font/space/control x0.9/x1.1 and leaves
radius/border fixed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
4 months ago |
|
|
c8fa6e87ed |
docs(theming): fix §19 reference to nonexistent ActiveEidos.setOverrides()
The runtime token-override API is setCssVariables() / clearCssVariables(); setOverrides() never existed. A dev copying §19 would hit a runtime error. (audit P2-5/A1) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
4 months ago |
|
|
218ccfcc5e |
Theming: untitled-ui demo theme, engine fixes, audit + P0/P1 fixes
- New untitled-ui demo theme + theming showcase route (web/routes/temas) - Engine: density tokens scale via calc(var(--density-*-scale)); contrast slot defaults to on-solid - Eidos theming audit (THEMING_AUDIT_2026-06-01.md) + two-tier color-model RFC (COLOR_MODEL_RFC.md) - P0: replace phantom foundation tokens in recipes + component CSS — shadows -> semantic scale (subtle/raised/overlay), add --space-7, --border-width-strong -> thick; neutral solid contrast -> step 12 (AA in light + dark) - P1: validate hex color values + per-theme semantic completeness; regression tests for contrast, density, dark output, and TSC multi-part/composition emission Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
4 months ago |
|
|
bd73fb98f3 |
feat(eidos): variants canon — EIDOS_VARIANTS + per-component lint
Variants son canon del eidos, NO del theme. Decisión arquitectónica
firmemente sostenida: el vocabulario de variants (solid/outline/ghost/
soft/surface/line/pills) está fijo a nivel del framework — paralelo
a las 8 sema families del libro. Theme = retintar lo perceptualmente
fijo; cambia QUÉ color es `affirm`, no QUÉ significa `outline`.
Cambios:
- lib/types.ts: nueva constante `EIDOS_VARIANTS` con los 5 archetypes
canónicos (control / selection / chip / marker / tabs). Los 5 union
types se derivan via `[number]` indexed access — valor y tipo no
pueden desincronizarse. Nueva `EIDOS_VARIANT_VALUES` Set flat con
todos los valores canónicos + utilidades cross-component (`plain`,
`subtle`).
- recipe-css-contract.test.ts: nuevo test "variant CSS selectors per
component match the declared type union". Por cada componente:
extrae el union type de `components/{c}/types.ts` (soporta literal
unions + archetype aliases; cae a advisory mode en Extract<> y
conditional types); compara con `[data-{c}][data-variant='X']`
selectores en `{c}.css`; reporta typos y unauthorized extensions
bidireccionalmente.
- THEMING.md §19: nueva sección "Variants son canon del eidos, NO
del theme" con argumentación (portabilidad, type safety, archetypes
perceptuales paralelos a sema families), tabla de las 3 capas de
la cebolla, referencia a `EIDOS_VARIANTS`, comparación con Radix
Themes 3.x / Mantine 7 / Chakra v3 / Ark / shadcn. TOC actualizado.
- eidos/README.md: tabla de referencia ampliada con §19.
- CLAUDE.md: hand-off "2026-05-27 #6 (variants canon)".
- CONTINUE.md: nota de la decisión arquitectónica.
Variants component-specific permitidos (Banner inline/overlay/
persistent, Spinner bars/dots/ring, Button 'plain'): viven en cada
`components/{c}/types.ts` y el lint los valida contra la CSS del
componente.
Tests: 101/101 pass en `src/uix/eidos`. `npm run check`: los mismos 6
errores pre-existentes (lib/_demo, soma/components/internal, web/
routes/active) — no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
9c6375c96e |
feat(eidos): TSC v2.2 (parts + composition) + universal theming coverage
Token Scope Contract universal — no más excepciones arquitectónicas.
Los 3 componentes que vivían fuera de TSC v2.1 (select, avatar,
toggle-group) ahora están dentro del contrato via dos extensiones nuevas.
TSC v2.2 extensiones (lib/config-types.ts + render-css.ts + config.ts):
- `parts: readonly string[]` en RecipeTokenMultiDeclaration — emite
selectores comma-separados (`[data-{c}-x], [data-{c}-y]`) para
componentes con data-color cascadeado per-part. Consumer: select.
- `composition: { foreignRecipe: { targetSelector, tokens } }` sibling
key — overrides cross-recipe scoped a la cascade del host. Consumer:
toggle-group modifica `--toggle-palette-*` en sus items.
Migraciones:
- select: 3 private `_accent-{track,border,text}` con parts: ['trigger',
'content'] + 7 cascades color:X each. Removed orphan `_accent-solid`
(CSS no consumía).
- avatar: 6 tokens via composite scopes `['variant:X', 'color:Y']` con
matrix helper inline. Badge usa parts: ['badge']. Reemplaza 24 bloques
CSS × 2 partes.
- toggle-group: composition block con 8 palette tokens × 4 colors.
Reemplaza 4 bloques CSS per-color.
Bug toggle-group post-composition (encontrado y arreglado):
Tras la composition migration, el cascade del toggle-group seguía roto
porque los tokens derivados (`--toggle-solid-on-bg`, `--toggle-outline-fg`,
etc.) viven en scope `[data-toggle]`. El `[data-toggle-group-item]` es
sibling (no descendant), así que `var(--toggle-solid-on-bg)` resolvía
undefined. Fix: inlined derivation expressions directamente en
`[data-toggle-group-item]` y sus variant cascades (solid/outline/ghost),
referenciando palette tokens en su propio scope local.
Validador + emisor + contract:
- `validateRecipeComposition` valida el shape `{ targetSelector, tokens }`
y rechaza composition entries con scope='root'.
- `stripCompositionKey` + `emitComposition` separan el pipeline.
- `appendRecipeContractTokens` skip-list para `composition` (no aparece
como fake `--{c}-composition` knob).
- `tokenKeys`/`tokenEntries` helpers en recipe-css-contract.test.ts
filtran composition en todos los iteradores.
Documentación:
- THEMING.md §18 reescrito como "Cobertura universal de TSC". §7
extendido con subsecciones "Multi-part scope" y "Cross-recipe
composition" + ejemplos completos. TOC actualizado.
- eidos/README.md tabla de referencia ampliada con TSC v2.2 + §18.
- CLAUDE.md gana hand-off "2026-05-27 #5" (TSC v2.2 + cobertura universal).
- CONTINUE.md reescrito al estado actual de la sesión.
Working tree también incluye sprint Words en paralelo (multiple authors):
slash menu, find/replace regex, code language picker, table audit,
toolbar family menu, code highlight engine.
Tests: 786/786 pass en src/uix/{eidos,morfo,soma,sema}. `npm run check`:
6 errores pre-existentes (lib/_demo, soma/components/internal,
web/routes/active) no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |