@sondalab/ui-kit
v0.7.2
Published
Sondalab design tokens as CSS custom properties + the agentic core: component catalog, compliance audit (sl-audit), and author/migrate/adopt workflows.
Readme
@sondalab/ui-kit
Sondalab design tokens as CSS custom properties (--sl-*) plus a CSS-only component layer (.sl-*). No build step, no runtime JS — import the stylesheets and theme via a data-sl-theme attribute.
@import "@sondalab/ui-kit/tokens.css"; /* shared: type, spacing, radii, motion, shadow, z */
@import "@sondalab/ui-kit/components.css"; /* .sl-* components (reads role-vars, see below) */
@import "@sondalab/ui-kit/themes/light.css"; /* [data-sl-theme="light"] surfaces, text, borders, status, accent */
@import "@sondalab/ui-kit/themes/dark.css";
@import "@sondalab/ui-kit/themes/high-contrast.css";<html data-sl-theme="dark"> … </html>Per-product accent. The bundled accent is the Sondalab default (amber --sl-accent-default, teal --sl-accent-depth). A product keeps its own signature by overriding the accent tokens after the import:
[data-sl-theme="dark"] { --sl-accent-default: #2ee6c0; --sl-focus-ring: #2ee6c0; }
[data-sl-theme="light"] { --sl-accent-default: #0e9c84; --sl-focus-ring: #0e9c84; }Fonts (load separately, e.g. Google Fonts): Fraunces (display), Instrument Sans (body), Martian Mono (mono).
Components (components.css)
Primitives: .sl-eyebrow, .sl-tag (--plain), .sl-btn (--primary / --ghost / --sm), .sl-card (__title / __body), .sl-badge (--success / --warning / --danger / --info), .sl-field (__label / __input), .sl-kbd, .sl-code, .sl-link, .sl-rule (--labeled).
Complex (composed shells — no behaviour JS; the consumer wires interaction): .sl-callout (--success/--warning/--danger/--info), .sl-table (--numeric; wrap in an overflow-x:auto container), .sl-dialog (visual shell for the native <dialog> — drive with .showModal()/.close()), .sl-tabs (__list/__tab — supply your own ARIA + panel switching), .sl-tooltip (CSS-only via data-sl-tooltip).
Colour contract — role-vars (--slc-*)
Components never read theme tokens directly (those resolve only under [data-sl-theme]). They read role-vars that default through a fallback chain to the --sl-* token, then to a brand literal. Tier A products (full data-sl-theme, e.g. spexr) need zero wiring — the role-vars pick up the live theme automatically. Tier B products (value-pinned, e.g. daos, introspect) map the role-vars once to their own colour layer. That block is the entire integration surface:
:root {
--slc-accent: var(--your-accent);
--slc-accent-hover: var(--your-accent-hover);
--slc-accent-active: var(--your-accent-active);
--slc-accent-subtle: var(--your-accent-tint); /* ~12% accent over surface */
--slc-on-accent: var(--your-on-accent); /* text on a filled accent */
--slc-surface: var(--your-surface);
--slc-raised: var(--your-raised);
--slc-overlay: var(--your-overlay); /* dialog backdrop */
--slc-text: var(--your-text);
--slc-text-secondary: var(--your-text-2);
--slc-text-muted: var(--your-text-muted);
--slc-border: var(--your-border);
--slc-border-subtle: var(--your-border-subtle);
--slc-border-strong: var(--your-border-strong);
--slc-focus: var(--your-accent);
--slc-success: var(--your-success); --slc-warning: var(--your-warning);
--slc-danger: var(--your-danger); --slc-info: var(--your-info);
}Inversion bands. --slc-border defaults to an alpha-over-canvas value; inside a band whose background is the strongest neutral (.invert), that alpha sits on the wrong ground and the hairline disappears. Re-derive it at the band from the band's foreground — no new token:
.invert { --slc-border: color-mix(in srgb, currentColor 22%, transparent); }The full reference implementation — every component in all three themes — is showcase/index.html (§04).
Generated tokens (tokens.css, themes/*.css) come from the canonical sondalab.tokens.json — do not hand-edit them. components.css is hand-authored.
