-
Notifications
You must be signed in to change notification settings - Fork 1
DesignSystem
The design system behind the write-once components: a complete token/component specification (authored with Claude Design, preserved in-repo at docs/design/Photon-Design-System.dc.html — the source of truth) implemented as typed C# tokens in eQuantic.UI.Primitives and consumed by every realization target.
-
Colors — every color is a paired light/dark
ColorToken; components never hold raw colors. Interactive variants resolve five sub-tokens (Base,OnBase,Pressed— a real token, not an overlay —Subtle,OnSubtle). Disabled is not a color: it's a 38% opacity group. -
Type scale — role-driven (
Display…BodyM,Caption,Label) with Dynamic Type clamps per role. -
Spacing (
Space.S1–S16, 4dp base, gap-owned — no margin exists), radius (Radius.Xs–Full, engine-clamped), icon sizes (§07 whitelist 16/20/24/32 — arbitrary sizes throw), touch (≥48dp hit contract), elevation (one analytic shadow per node), motion (durations + curves + spring).
- Token values are pinned; WCAG contrast is recomputed in tests for every claimed pair.
- Component metrics come from the spec tables (e.g. Button's size table: 32/40/48/56 heights) and are asserted on every axis: C# web realizer pins, native golden images (light + dark), transpiled-fixture execution in vitest.
- The style resolver rules (derived Outline/Ghost/Link variants, pressed-as-token-swap, focus double-ring) live in target-neutral C# (
ButtonStyles).
Client-side artifacts carrying design-system values are generated from the C# single source and byte-pinned in CI (a drift fails the build; env-var flows regenerate):
| Artifact | Generator | Regenerate with |
|---|---|---|
Normative stylesheet (custom properties, .eq-type-*, .eq-elevation-*, motion vars) |
PhotonCssGenerator |
(pure function — tested per value) |
design-system.generated.ts (tokens, theme object, Button size table) |
DesignSystemTsGenerator |
EQ_UPDATE_DESIGN_TS=1 |
icons.generated.ts (glyph path data) |
IconTsGenerator |
EQ_UPDATE_ICONS_TS=1 |
| Embedded transpiled component modules | live eqc output | EQ_UPDATE_TRANSPILED=1 |
The same rule powers hydration: SSR (C# realizer) and client lowering (TS) are held byte-identical by cross-pinned literals in both test suites.
A curated Icons enum (16 glyphs and growing) with the path data living once in the C# IconRegistry (24×24 single-path alpha masks): the web emits inline <svg fill="currentColor"> (the tint rides the color token exactly like text), the TS side consumes the generated module, and the future native glyph atlas rasterizes from the same registry. Outline ↔ filled are distinct glyphs; icons ignore Dynamic Type.
Authoring is 100% typed C# (BoxStyle, StyleDiff, tokens) — there is no CSS plane. Three laws govern the web realization:
- One semantics — the same style vocabulary drives dp values on Photon and CSS on web.
-
No expressiveness ceiling — Wrap, Grid, AspectRatio, AlignSelf, group Opacity, static Transform2D, Hover/Focus state diffs, window-size-class adaptivity (
AdaptiveNode), Sticky, ZIndex, both-axis scroll. -
No rewrite by construction — every regular declaration lowers to ONE deduplicated atomic class (
eq-+ FNV-1a hash ofprop:value); theme colors referencevar(--eq-color-*); SSR collects the page's rules into a single<style id="eq-atomic">the client adopts by identity (hydration = class equality, enforced end-to-end by the e2e identity test). ~118 rules / 4.8 KB covered the entire showroom.
Pseudo-states lower to pseudo-variant atomic rules (:hover/:focus-visible — zero JS); size classes to fixed media-gate classes. The C# StyleAtomizer and the TS style-atomizer.ts are byte-identical twins (cross-pinned fixture).
One interface (colors as light/dark ColorToken pairs, type roles, shape scale, elevation specs, disabled opacity), selected via AddUI(...).UseTheme(...) and bridged SSR→client. Two implementations ship: PhotonTheme (the default) and MaterialTheme (real Material 3 — MaterialTheme.Instance baseline or FromSeed(color) dynamic color via a CAM16/HCT port validated against Google's values). Shape is theme-driven; the same component tree rebrands with one line.