diff --git a/.claude/plugins/kurrent-design-system/.claude-plugin/plugin.json b/.claude/plugins/kurrent-design-system/.claude-plugin/plugin.json new file mode 100644 index 00000000..8312f3bc --- /dev/null +++ b/.claude/plugins/kurrent-design-system/.claude-plugin/plugin.json @@ -0,0 +1,5 @@ +{ + "name": "kurrent-design-system", + "version": "1.0.0", + "description": "Skill for building and aligning applications to the Kurrent Design System" +} diff --git a/.claude/plugins/kurrent-design-system/skills/kurrent-ds/SKILL.md b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/SKILL.md new file mode 100644 index 00000000..6d417c6b --- /dev/null +++ b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/SKILL.md @@ -0,0 +1,129 @@ +--- +name: kurrent-ds +description: This skill should be used when the user asks to "build a UI", "create a page", "add a form", "use Kurrent components", "align to Kurrent Design System", "migrate to Kurrent", "set up theming", "add a sidebar", "create a layout", "use design system components", "add icons", "replace hardcoded colors", or mentions Kurrent UI, @kurrent-ui packages, c2-/f2-/l2- components, or building web/desktop applications that should follow the Kurrent design language. +--- + +# Kurrent Design System + +Guidance for building and aligning web and desktop applications to the Kurrent Design System — a component library built on Stencil web components with comprehensive theming, form validation, layout primitives, and icon management. + +## Package Overview + +| Package | Scope | Purpose | +|---------|-------|---------| +| `@kurrent-ui/components` | Core UI | Buttons, tables, modals, tabs, toasts, icons, actions | +| `@kurrent-ui/fields` | Form inputs | Text, select, checkbox, radio, number, textarea | +| `@kurrent-ui/layout` | Page structure | Page shells, sidebars, headers, panels, breadcrumbs | +| `@kurrent-ui/forms` | Form logic | Validated form state, working copy data stores | +| `@kurrent-ui/theme` | Theming | Light/dark/high-contrast themes, CSS custom properties | +| `@kurrent-ui/utils` | Utilities | Shared helpers and type utilities | +| `@kurrent-ui/stores` | State | Stencil store primitives | +| `@kurrent-ui/router` | Routing | Stencil router with URL state management | +| `@kurrent-ui/editor` | Code editing | Monaco editor wrapper component | +| `@kurrent-ui/assets` | Static assets | CSS utilities and asset files | + +## Component Naming Convention + +Components use **web component** custom element tags with version-namespaced prefixes: + +- **`c2-*`** — Core components (`c2-button`, `c2-icon`, `c2-tabs`, `c2-modal`) +- **`f2-*`** — Field components with two levels: + - **Input level** (`f2-text-input`, `f2-select-input`, `f2-checkbox`) — raw interactive element, no label or validation + - **Field level** (`f2-text-field`, `f2-select-field`, `f2-switch-field`) — wraps input with label, validation messages, and documentation +- **`l2-*`** — Layout components (`l2-sidebar`, `l2-header`, `l2-breadcrumb`, `l2-panel`) + +**Important:** `Page` from `@kurrent-ui/layout` is a Stencil **functional component**, not a custom element. Use it only in Stencil TSX: ``. + +Some layout components accept **data props** (not child elements): +- `l2-nav` takes a `navTree` prop (array of `NavNode`) +- `l2-breadcrumb` takes a `crumbs` prop (array of `Crumb`) + +These are standard web components usable in **any framework** — HTML, React, Angular, Vue, Svelte, or Stencil/TSX. + +## Quick Decision Guide + +| Task | Action | +|------|--------| +| Setting up a new project | Read `references/getting-started.md` | +| Building page layouts | Read `references/layout.md` | +| Adding forms and validation | Read `references/fields.md` | +| Using buttons, tables, modals, tabs | Read `references/components.md` | +| Configuring themes and colors | Read `references/theming.md` | +| Aligning existing UI to Kurrent | Follow the migration protocol below | + +## Core Patterns + +### Shadow DOM & Styling + +Most components use Shadow DOM. Style them via: +1. **CSS custom properties** — Components expose `--variable-name` properties for customization +2. **CSS parts** — Use `::part(name)` to style internal elements +3. **Slots** — Named slots for content composition (`before`, `after`, `documentation`) + +### Theme Integration + +```typescript +import { theme } from '@kurrent-ui/theme'; +``` + +Apply theme-aware attributes on host elements: + +```tsx + +``` + +Four built-in themes: `light`, `dark`, `high_contrast_light`, `high_contrast_dark`. Auto-selection respects `prefers-color-scheme` and `prefers-contrast` media queries. + +### Form Pattern + +```typescript +import { createValidatedForm } from '@kurrent-ui/forms'; + +const form = createValidatedForm({ + name: { initialValue: '', validations: [required()] }, +}); +``` + +Fields emit `fieldchange` custom events with the new value in `event.detail`. Use `f2-*-field` components (field level) for forms with labels and validation, or `f2-*-input` components (input level) for custom layouts. + +### Icon Registration + +```typescript +import { iconStore } from '@kurrent-ui/components'; +// Register icons before use +iconStore.addIcons(/* icon data */); +``` + +Display with ``. + +## Migration Protocol: Aligning Existing UI to Kurrent + +When aligning an existing application to the Kurrent Design System: + +1. **Audit current UI** — Inventory all pages, forms, navigation, and interactive elements +2. **Install packages** — Add required `@kurrent-ui/*` packages (see `references/getting-started.md`) +3. **Set up theming first** — Initialize `@kurrent-ui/theme` and replace hardcoded colors with CSS custom properties (see `references/theming.md`) +4. **Replace layout structure** — Swap app shell, sidebar, header, and page containers with layout components (see `references/layout.md`) +5. **Replace interactive components** — Swap buttons, tables, modals, tabs with `c2-*` components (see `references/components.md`) +6. **Replace form elements** — Swap inputs, selects, checkboxes with `f2-*` fields and wire up form validation (see `references/fields.md`) +7. **Verify** — Check theming in all four modes, test responsive behavior, validate form flows + +## Additional Resources + +### Reference Files + +For detailed component catalogs, CSS tokens, and usage examples, consult: + +- **`references/getting-started.md`** — Installation, framework integration, project setup +- **`references/components.md`** — Full catalog of core components (c2-*) with props and usage +- **`references/fields.md`** — Form field components (f2-*), validation, and form patterns +- **`references/layout.md`** — Page structure components (l2-*), navigation, and layout patterns +- **`references/theming.md`** — Theme system, color scheme, CSS custom properties, theme API + +### Source of Truth + +The design system source code is the definitive reference. When in doubt about component APIs, read the component source files directly from the design-system repository: +- Core components: `packages/components/src/components/` +- Field components: `packages/fields/src/components/` +- Layout components: `packages/layout/src/components/` +- Theme definitions: `packages/theme/src/` diff --git a/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/components.md b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/components.md new file mode 100644 index 00000000..47c38191 --- /dev/null +++ b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/components.md @@ -0,0 +1,378 @@ +# Core Components (c2-*) + +Full catalog of components from `@kurrent-ui/components`. + +## Buttons + +### c2-button + +Primary interactive button. + +**Variants:** `default` | `filled` | `outline` | `minimal` | `link` | `delete` | `cancel` + +```html +Save +Cancel +Delete +Disabled +``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `variant` | `ButtonVariant` | Visual style | +| `disabled` | `boolean` | Disable interaction | + +**CSS Custom Properties:** +- `--primary-color`, `--secondary-color`, `--tertiary-color` +- `--background-color`, `--foreground-color`, `--border-color` +- `--border-radius`, `--border-width`, `--spacing` +- `--focus-color`, `--transition-duration` + +**CSS Parts:** `button` + +### c2-button-link + +Button styled as a navigable link. + +```html +Go to Settings +``` + +**Additional Props:** `url`, `external` (opens in new tab) + +### c2-button-with-confirmation + +Button that requires confirmation before executing action. + +```html + + Delete Item + +``` + +### c2-thinking-button + +Async action button that shows state transitions: default -> thinking -> complete/failed -> default. + +```tsx + { await deployService(); }} + defaultIcon={deployIcon} + thinkingIcon={spinnerIcon} + completeIcon={checkIcon} + failedIcon={errorIcon} +/> +``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `action` | `(e: MouseEvent) => Promise` | Async action to execute on click | +| `text` | `string` | Button label | +| `variant` | `string` | Button visual style | +| `disabled` | `boolean` | Disable interaction | +| `defaultIcon` | `IconDescription` | Icon in default state | +| `thinkingIcon` | `IconDescription` | Icon while action runs | +| `completeIcon` | `IconDescription` | Icon on success | +| `failedIcon` | `IconDescription` | Icon on failure | + +## Actions + +### c2-actions + +Container for action elements. + +```html + + Edit + View + +``` + +### c2-action + +A clickable action element (typically used in toolbars, dropdowns, or action bars). + +```html +Edit +``` + +### c2-action-link + +Action styled as a navigable link with an icon. + +```tsx + + View Stream + +``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `url` | `string` | Navigation URL | +| `icon` | `IconDescription` | Icon to display | +| `disabled` | `boolean` | Disable interaction | +| `dot` | `color` | Attention indicator dot | + +### c2-action-dropdown + +Action with a dropdown menu. + +```html + + More Actions + Duplicate + Archive + +``` + +### c2-action-with-confirmation + +Action requiring user confirmation before executing. + +## Modals + +### c2-modal + +General-purpose modal dialog with header, body, and footer slots. + +```html + + Edit User +
+ +
+
+ Save + Cancel +
+
+``` + +**Props:** + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `header` | `boolean` | `true` | Show header section | +| `footer` | `boolean` | `true` | Show footer section | + +**Slots:** `header`, default (body), `footer` + +**Events:** `requestClose` + +Typically used with `c2-portal` to render outside the component DOM tree. + +### c2-confirm-modal + +Pre-built confirmation dialog. + +```tsx + +``` + +## Tables + +### c2-table + +Data table with sorting, row selection, and customization. + +```tsx + row.name }, + { header: 'Status', cell: (row) => row.status }, + ]} + data={items} +/> +``` + +**Variants:** +- **c2-table** — Standard table +- **c2-table-nested** — Table with expandable nested rows +- **c2-table-virtualized** — Virtualized table for large datasets with optional detail rows + +**CSS Parts:** `table`, `header`, `row`, `cell` + +## Tabs + +### c2-tabs + +Tabbed content container. + +```html + +
Overview content
+
Details content
+
History content
+
+``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `panels` | `string[]` | Tab labels | +| `activeParam` | `string` | URL search param to sync active tab | + +## Icons + +### c2-icon + +Displays registered SVG icons. + +```html + + + +``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `icon` | `string \| [symbol, string]` | Icon name or namespaced tuple | +| `size` | `number` | Size in pixels | +| `angle` | `number` | Rotation angle | +| `spin` | `boolean` | Animate spinning (auto for "spinner") | +| `spinDirection` | `'clockwise' \| 'counter-clockwise'` | Spin direction | + +**CSS Parts:** `icon` + +## Feedback & Status + +### c2-badge + +Status badge / pill label. + +```html +Active +Failed +``` + +### c2-callout + +Informational callout block. + +```html + + This operation may take a while. + +``` + +**Variants:** `info` | `warning` | `error` | `success` + +### c2-toast + +Toast notification system. Triggered programmatically. + +```typescript +import { toast } from '@kurrent-ui/components'; + +toast.success({ title: 'Saved', message: 'Changes saved.' }); +toast.error({ title: 'Error', message: 'Something went wrong.' }); +toast.warning({ title: 'Warning', message: 'Check your input.' }); +toast.info({ title: 'Info', message: 'Processing complete.' }); +``` + +### c2-corner-banner + +Corner ribbon banner for status labels (e.g., "Beta", "New"). + +### c2-counter + +Numeric counter display. + +## Loading + +### c2-loading-dots + +Animated loading dots indicator. + +```html + +``` + +### c2-loading-text + +Loading placeholder text with animation. + +## Navigation & Flow + +### c2-pagination + +Page navigation for paginated data. + +```html + +``` + +### c2-progression + +Step progression indicator (wizard-style). + +### c2-wizard + +Multi-step wizard flow. + +## Utility + +### c2-popover + +Floating content anchored to a trigger element. + +```html + + +
Popover content
+
+``` + +### c2-portal + +Renders children into a portal (outside component DOM tree). Use for modals and overlays to avoid z-index and overflow issues. + +### c2-copy + +Copy-to-clipboard button. + +```html + +``` + +### c2-accordian + +Expandable/collapsible content section. + +```html + +
Expanded content here
+
+``` + +**Note:** The component tag is spelled `c2-accordian` (not "accordion") — this is intentional in the design system. + +### c2-resize-observer + +Utility component that observes and reports element size changes. diff --git a/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/fields.md b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/fields.md new file mode 100644 index 00000000..b112f637 --- /dev/null +++ b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/fields.md @@ -0,0 +1,348 @@ +# Field Components (f2-*) and Form Patterns + +Components from `@kurrent-ui/fields` and `@kurrent-ui/forms` for building validated forms. + +## Field vs Input: Two-Level Architecture + +Every form element has two levels: + +| Level | Naming | Includes | Use When | +|-------|--------|----------|----------| +| **Input** | `f2-*-input` (e.g., `f2-text-input`, `f2-select-input`) | Raw interactive element only | Building custom layouts, embedding in tables, or composing manually | +| **Field** | `f2-*-field` (e.g., `f2-text-field`, `f2-select-field`) | Input + label + validation messages + documentation | Standard forms with labels and validation | + +**Exceptions:** `f2-checkbox` and `f2-switch` are input-level tags (no `-input` suffix). Their field-level wrappers are `f2-checkbox-field` (if exists) and `f2-switch-field`. + +Always prefer **field-level** components in forms. Use **input-level** only for custom layouts. + +## Form Architecture + +### Creating a Validated Form + +```typescript +import { createValidatedForm } from '@kurrent-ui/forms'; + +const form = createValidatedForm({ + name: { + initialValue: '', + validations: [required('Name is required')], + }, + email: { + initialValue: '', + validations: [required(), email('Must be a valid email')], + }, + role: { + initialValue: 'viewer', + }, +}); +``` + +### Form Component Pattern (Stencil TSX) + +```tsx + + form.set('name', e.detail)} + /> + form.set('email', e.detail)} + /> + + + + Save + + + +``` + +### Event Pattern + +All field components emit `fieldchange` custom events with the new value in `event.detail`. + +In frameworks that don't natively handle custom events (e.g., React), attach listeners via `ref`: + +```tsx +// React example +const inputRef = useRef(null); + +useEffect(() => { + const el = inputRef.current; + const handler = (e) => setName(e.detail); + el?.addEventListener('fieldchange', handler); + return () => el?.removeEventListener('fieldchange', handler); +}, []); + +return ; +``` + +## Text Input Components + +### f2-text-input / f2-text-field + +Single-line text input. + +```html + + + + + +``` + +### f2-masked-text-input / f2-masked-text-field + +Text input with display masking (e.g., passwords, tokens). + +```html + +``` + +### f2-typeahead + +Text input with autocomplete suggestions. + +```html + +``` + +### f2-textarea-input / f2-textarea-field + +Multi-line text input. + +```html + +``` + +### f2-text-list-field + +List of text inputs for managing multiple values. + +## Selection Components + +### f2-select-input / f2-select-field + +Searchable dropdown select. + +```html + +``` + +### f2-multi-checkbox-field + +Group of checkboxes for selecting multiple values. + +```html + +``` + +## Toggle Components + +### f2-checkbox + +Single checkbox (input level). + +```html + + Accept terms + +``` + +### f2-switch / f2-switch-field + +Toggle switch. + +```html + + + + + +``` + +### f2-radio-card-input / f2-radio-card-field + +Radio selection styled as selectable cards. + +```html + +``` + +## Numeric Input + +### f2-number-input / f2-number-field + +Numeric input with optional step controls. + +```html + +``` + +## Form Structure Components + +### f2-form + +Form wrapper that handles submission. + +```html + + + +``` + +### f2-form-footer + +Footer area for form action buttons (submit, cancel). + +```html + + Save + Cancel + +``` + +### f2-form-section-divider + +Visual divider between form sections. + +### f2-validation-messages + +Displays validation error messages. Used automatically by field-level components, or manually with input-level components: + +```html + + +``` + +### f2-placeholder-field + +Placeholder skeleton for loading states in forms. + +## Common Input Props + +**Input-level components:** + +| Prop | Type | Description | +|------|------|-------------| +| `name` | `string` | Field identifier (required, reflected to attribute) | +| `value` | varies | Current value | +| `placeholder` | `string` | Placeholder text | +| `disabled` | `boolean` | Disable interaction | +| `readonly` | `boolean` | Read-only mode | +| `invalid` | `boolean` | Show error visual state | + +**Field-level components** (in addition to input props): + +| Prop | Type | Description | +|------|------|-------------| +| `label` | `string` | Field label | +| `messages` | `ValidationMessages` | Validation messages | +| `documentation` | `string` | Help text | +| `documentationLink` | `string` | Link for help text | +| `documentationLinkText` | `string` | Link text for help | + +## Common Form Patterns + +### Settings Form + +```tsx +const form = createValidatedForm({ + displayName: { initialValue: user.name, validations: [required()] }, + email: { initialValue: user.email, validations: [required(), email()] }, + notifications: { initialValue: user.notifications }, +}); + +render() { + return ( + save(form.data)}> + form.set('displayName', e.detail)} /> + form.set('email', e.detail)} /> + + + + form.set('notifications', e.detail)} /> + + + Save + form.reset()}>Reset + + + ); +} +``` + +### Filter Bar (Input Level) + +```tsx + updateFilter('status', e.detail)} +/> + updateFilter('search', e.detail)} +/> +``` diff --git a/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/getting-started.md b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/getting-started.md new file mode 100644 index 00000000..26d226d7 --- /dev/null +++ b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/getting-started.md @@ -0,0 +1,207 @@ +# Getting Started with Kurrent Design System + +## Installation + +Install the packages needed for the application: + +```bash +# Core — almost always needed +npm install @kurrent-ui/theme @kurrent-ui/components + +# Forms and fields +npm install @kurrent-ui/fields @kurrent-ui/forms + +# Layout shell (sidebar, header, panels) +npm install @kurrent-ui/layout + +# Optional +npm install @kurrent-ui/utils @kurrent-ui/router @kurrent-ui/editor @kurrent-ui/stores +``` + +## Framework Integration + +### Stencil / TSX (Native) + +Components are built with Stencil and work natively in Stencil projects. Import and use directly: + +```tsx +import { Component, h } from '@stencil/core'; +import { Page } from '@kurrent-ui/layout'; + +@Component({ tag: 'my-page', shadow: true }) +export class MyPage { + render() { + return ( + + Save + + ); + } +} +``` + +**Note:** `Page` is a Stencil functional component (not a custom element tag). Other layout components like `l2-header`, `l2-sidebar`, `l2-panel` are regular web components. + +### Plain HTML / Vanilla JS + +Load the component loaders and use as custom elements: + +```html + + + + + + + + +
+ Click me +
+``` + +**Note:** Data-driven components like `l2-nav` and `l2-breadcrumb` require setting props via JavaScript (e.g., `document.querySelector('l2-nav').navTree = [...]`). The `Page` functional component is only available in Stencil TSX. + +### React + +Web components work in React with some caveats: + +```tsx +import { defineCustomElements } from '@kurrent-ui/components/loader'; +import { theme } from '@kurrent-ui/theme'; + +// Call once at app startup +defineCustomElements(); +theme.select('auto'); + +function App() { + return ( +
+ alert('clicked')}> + Save + +
+ ); +} +``` + +**React caveats with web components:** +- Use `ref` + `addEventListener` for custom events like `fieldchange` (React doesn't natively support custom element events) +- Boolean attributes: pass `true`/`false` explicitly, not truthy/falsy strings +- Complex props (objects/arrays): use `ref` to set them via JavaScript, or JSON-serialize to attributes +- Data-driven components (`l2-nav`, `l2-breadcrumb`): must set props via `ref` + +### Angular + +Angular supports web components via `CUSTOM_ELEMENTS_SCHEMA`: + +```typescript +// app.module.ts +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; + +@NgModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], + // ... +}) +export class AppModule {} +``` + +```typescript +// main.ts +import { defineCustomElements as defineComponents } from '@kurrent-ui/components/loader'; +import { defineCustomElements as defineLayout } from '@kurrent-ui/layout/loader'; +import { theme } from '@kurrent-ui/theme'; + +defineComponents(); +defineLayout(); +theme.select('auto'); +``` + +### Vue + +Vue handles web components natively. Configure the compiler to skip Kurrent tags: + +```javascript +// vite.config.js +export default { + plugins: [ + vue({ + template: { + compilerOptions: { + isCustomElement: (tag) => + tag.startsWith('c2-') || tag.startsWith('f2-') || tag.startsWith('l2-'), + }, + }, + }), + ], +}; +``` + +## Theme Initialization + +Always initialize the theme early in the application lifecycle: + +```typescript +import { theme } from '@kurrent-ui/theme'; + +// Auto-detect from system preferences +theme.select('auto'); + +// Or force a specific theme +theme.select('dark'); +theme.select('light'); +theme.select('high_contrast_dark'); +theme.select('high_contrast_light'); +``` + +The theme system: +- Injects CSS custom properties into `:root` +- Persists selection in `localStorage` +- Supports `prefers-color-scheme` and `prefers-contrast` media queries +- Propagates to iframes via the `theme` attribute + +## Icon Setup + +Register icons before rendering any `c2-icon` components: + +```typescript +import { iconStore } from '@kurrent-ui/components'; + +// Register individual icons +iconStore.addIcons({ + name: 'chevron', + svg: '...', +}); + +// Or register a namespace of icons +import { K_COMPONENTS_ICON_NAMESPACE } from '@kurrent-ui/components'; +// Icons in this namespace are auto-registered +``` + +Use the `@kurrent-ui/icon-manager` CLI tool for managing project icons: + +```bash +npx @kurrent-ui/icon-manager --dir=./src/icons +``` + +## Key Principles + +1. **Use CSS custom properties for all colors** — never hardcode colors; always use `--color-*` tokens +2. **Initialize theme before first render** — call `theme.select()` in the entry point +3. **Register icons early** — before any `c2-icon` renders +4. **Use Shadow DOM parts for customization** — `::part(name)` for styling internals +5. **Compose with slots** — use named slots for content injection +6. **Prefer field-level components** — use `f2-*-field` in forms, `f2-*-input` only for custom layouts +7. **Set data props via JavaScript** — `l2-nav` and `l2-breadcrumb` take data props, not child elements diff --git a/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/layout.md b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/layout.md new file mode 100644 index 00000000..099c9f05 --- /dev/null +++ b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/layout.md @@ -0,0 +1,395 @@ +# Layout Components and Page Structure + +Components from `@kurrent-ui/layout` for building application shells and page structure. + +## Application Shell (Stencil TSX) + +A typical Kurrent application shell in Stencil: + +```tsx +import { Page } from '@kurrent-ui/layout'; +import type { NavTree, Crumb } from '@kurrent-ui/layout'; + +const navTree: NavTree = [ + { title: 'Dashboard', url: '/dashboard' }, + { title: 'Streams', url: '/streams' }, + { + title: 'Settings', + children: [ + { title: 'General', url: '/settings/general' }, + { title: 'Users', url: '/settings/users' }, + ], + }, +]; + +render() { + return [ + + + + Profile + Logout + + + , + + + + + Documentation + + , + + + {/* Page content */} + , + ]; +} +``` + +## Page Component (Functional Component) + +**Important:** `Page` is a Stencil **functional component** exported from `@kurrent-ui/layout`. It is NOT a custom element tag. Use it only in Stencil TSX. + +```tsx +import { Page } from '@kurrent-ui/layout'; +``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `pageTitle` | `string` | Document title and page heading | +| `crumbs` | `Crumb[]` | Breadcrumb trail data | +| `state` | `PageState` | `'loading'` \| `'ready'` \| `['error', unknown]` | +| `empty` | `boolean` | Show empty state | +| `renderEmptyState` | `FunctionalComponent` | Custom empty state renderer | +| `renderErrorState` | `FunctionalComponent` | Custom error state renderer | +| `renderLoadingState` | `FunctionalComponent \| false` | Custom loading renderer, or `false` to disable | +| `headerTitle` | `string \| false` | Override header text, or `false` to hide | +| `headerRight` | `FunctionalComponent` | Content for the right side of the page header | +| `progressBarId` | `string` | Loading bar ID (defaults to `'page'`) | + +**Usage with state management:** + +```tsx + + + +``` + +**For non-Stencil frameworks:** Build the page layout manually using `l2-header`, `l2-sidebar`, `l2-breadcrumb`, `l2-panel`, and standard HTML elements. The `Page` functional component handles wiring these together in Stencil. + +## Header + +### l2-header + +Application top bar with slot-based composition. + +```html + + + App Name + + +``` + +**Props:** + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `header` | `boolean` | `true` | Show/hide header section | +| `footer` | `boolean` | `true` | Show/hide footer section | + +**Slots:** `left`, `center`, `right`, `under`, `backdrop` + +**CSS Parts:** `header`, `left`, `center`, `right`, `under`, `backdrop` + +### l2-header-dropdown + +Dropdown menu in the header. + +```html + + Profile + Sign out + +``` + +### l2-logo + +Brand logo component. Place in header's `left` slot. + +## Sidebar Navigation + +### l2-sidebar + +Side navigation panel using slots. + +```html + + + +``` + +**Slots:** default (main content), `after` (content after aside) + +Auto-manages `--layout-sidebar-width` CSS variable based on measured width. + +### l2-nav + +Navigation component driven by a **data prop** (not child elements). + +```tsx +import type { NavTree } from '@kurrent-ui/layout'; + +const navTree: NavTree = [ + { title: 'Home', url: '/home' }, + { title: 'Streams', url: '/streams' }, + { + title: 'Admin', + children: [ + { title: 'Users', url: '/admin/users' }, + { title: 'Settings', url: '/admin/settings' }, + ], + }, +]; + + +``` + +**NavTree Types:** + +```typescript +type NavTree = NavNode[]; +type NavNode = NavParentNode | NavLeafNode; + +interface NavLeafNode { + title: string; + url: string; + disabled?: boolean; + external?: boolean; + match?: string; // custom active-match pattern + exact?: boolean; // exact URL match for active state +} + +interface NavParentNode { + title: string; + disabled?: boolean; + children: NavNode[]; +} +``` + +### l2-sidebar-dropdown + +Dropdown menu within the sidebar. + +```html + + Switch workspace + +``` + +## Content Containers + +### l2-panel + +Content panel with optional header. + +```html + + + Recent Events + Refresh + +
Panel content
+
+``` + +### l2-panel-header + +Header for panels. **Slots:** `title`, `actions` + +### l2-layout-section + +Section container for grouping related content. + +### l2-layout-hr + +Horizontal rule divider between sections. + +### l2-layout-auto-label + +Auto-labeled layout for key-value display. + +### l2-page-title + +Page title display component. + +## Breadcrumb + +### l2-breadcrumb + +Breadcrumb trail driven by a **data prop** (not child elements). + +```tsx +import type { Crumb } from '@kurrent-ui/layout'; + +const crumbs: Crumb[] = [ + { path: '/streams', name: 'Streams' }, + { path: '/orders', name: 'Orders' }, +]; + + +``` + +**Crumb Type:** + +```typescript +interface Crumb { + path: string; // relative path from previous crumb + name: string; // display text +} +``` + +**Props:** + +| Prop | Type | Description | +|------|------|-------------| +| `crumbs` | `Crumb[]` | Array of breadcrumb items | +| `noValidate` | `boolean` | Disable route validation warnings | + +## Navigation Components + +### l2-tab-bar + +Tab navigation bar for sub-sections of a page. + +```html + +``` + +### l2-toolbar + +Toolbar for page-level actions and filters. + +```html + + Create + + +``` + +## Theming Controls + +### l2-theme-dropdown + +Dropdown for switching between themes. Place in the header. + +```html + +``` + +### l2-theme-picker + +Full theme picker UI (expanded, not dropdown). + +## Status & Empty States + +### l2-display-error + +Error display for page-level errors. + +```html + +``` + +### l2-empty-state + +Empty state display when no data is available. + +```html + +``` + +### l2-loading-bar + +Global loading progress bar, typically at the top of the app. + +## Layout Utility Components + +| Component | Purpose | +|-----------|---------| +| `l2-layout-section` | Section grouping | +| `l2-layout-hr` | Horizontal divider | +| `l2-layout-auto-label` | Key-value auto-labeling | +| `l2-layout-link` | Layout-styled link | +| `l2-layout-button` | Layout-styled button | +| `l2-sized-panel` | Panel with fixed sizing | + +## Common Layout Patterns + +### Dashboard Page (Stencil TSX) + +```tsx + + + + + + + + Recent Activity + + + + +``` + +### Detail Page with Breadcrumbs (Stencil TSX) + +```tsx + + + + {tab === 'Events' && } + {tab === 'Settings' && } + +``` + +### Settings Page (Stencil TSX) + +```tsx + + + + General + + + + + + + Save + + + + +``` diff --git a/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/theming.md b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/theming.md new file mode 100644 index 00000000..612420ec --- /dev/null +++ b/.claude/plugins/kurrent-design-system/skills/kurrent-ds/references/theming.md @@ -0,0 +1,222 @@ +# Theme System + +The `@kurrent-ui/theme` package provides a comprehensive theming system with four built-in themes, CSS custom property injection, and automatic system preference detection. + +## Built-in Themes + +| Theme | `shade` | `contrast` | Media Match | +|-------|---------|------------|-------------| +| `light` | light | low | default | +| `dark` | dark | low | `prefers-color-scheme: dark` | +| `high_contrast_light` | light | high | `prefers-contrast: more` | +| `high_contrast_dark` | dark | high | Both dark + high contrast | + +## Theme API + +```typescript +import { theme } from '@kurrent-ui/theme'; + +// Selection +theme.select('auto'); // Auto-detect from system +theme.select('dark'); // Force specific theme +theme.select('high_contrast_light'); // Force high contrast light + +// Querying +theme.selected; // 'auto' | 'light' | 'dark' | 'high_contrast_light' | 'high_contrast_dark' +theme.name; // Resolved theme name (never 'auto') +theme.shade; // 'light' | 'dark' +theme.contrast; // 'high' | 'low' +theme.isDark(); // boolean +theme.isHighContrast(); // boolean + +// Color access +theme.colors; // Full color scheme object (BaseScheme) +theme.colors.background; +theme.colors.highlight; +theme.colors.error; + +// Change listener +const unsubscribe = theme.onThemeChange((newTheme) => { + console.log('Theme changed to:', newTheme.name); +}); +// Call unsubscribe() to remove listener +``` + +## Complete Color Token Reference + +All tokens are injected as CSS custom properties on `:root`. + +### Core Colors + +| Token | Purpose | Contrast Variant | +|-------|---------|-----------------| +| `--color-background` | Page/surface background | `--color-background-contrast` | +| `--color-foreground` | Primary body text | `--color-foreground-contrast` | +| `--color-title` | Heading text | `--color-title-contrast` | +| `--color-highlight` | Brand/accent color | `--color-highlight-contrast` | +| `--color-link` | Clickable link text | `--color-link-contrast` | +| `--color-focus` | Focus ring / outline | `--color-focus-contrast` | + +### Status Colors + +Each status color has a base, alt, and contrast variant: + +| Base Token | Alt Token | Contrast Token | Purpose | +|------------|-----------|----------------|---------| +| `--color-error` | `--color-error-alt` | `--color-error-contrast` | Errors, destructive | +| `--color-warning` | `--color-warning-alt` | `--color-warning-contrast` | Warnings, caution | +| `--color-success` | `--color-success-alt` | `--color-success-contrast` | Success, positive | +| `--color-info` | `--color-info-alt` | `--color-info-contrast` | Informational | + +### Shade Scale + +Grayscale steps for borders, dividers, and subtle backgrounds: + +| Token | Purpose | +|-------|---------| +| `--color-shade-10` | Lightest shade (subtle borders) | +| `--color-shade-20` | Light dividers | +| `--color-shade-30` | Medium borders | +| `--color-shade-40` | Medium-dark elements | +| `--color-shade-50` | Dark elements | +| `--color-shade-60` | Darkest shade (heavy borders) | + +### Special Tokens + +| Token | Purpose | +|-------|---------| +| `--color-overlay` | Overlay background (opaque) | +| `--color-overlay-alpha` | Overlay background (semi-transparent) | +| `--color-disabled` | Disabled element background | +| `--color-disabled-border` | Disabled element border | +| `--color-disabled-contrast` | Disabled element text | + +## Using Theme Colors in CSS + +Always use CSS custom properties instead of hardcoded colors: + +```css +/* CORRECT */ +.my-component { + background-color: var(--color-background); + color: var(--color-foreground); + border: 1px solid var(--color-shade-30); +} + +.my-component .title { + color: var(--color-title); +} + +.my-component .error { + color: var(--color-error); + background: var(--color-error-alt); +} + +.my-component:focus-visible { + outline: 2px solid var(--color-focus); +} + +/* INCORRECT — hardcoded colors break theme switching */ +.my-component { + background-color: #ffffff; + color: #333333; + border: 1px solid #e0e0e0; +} +``` + +## Theme-Aware Component Rendering + +In Stencil components, apply theme attributes for CSS-based theme adaptation: + +```tsx +import { theme } from '@kurrent-ui/theme'; + +@Component({ tag: 'my-component', shadow: true, styleUrl: 'my-component.css' }) +export class MyComponent { + render() { + return ( + + + + ); + } +} +``` + +Then in CSS: + +```css +:host { + background: var(--color-background); + color: var(--color-foreground); +} + +:host([dark]) { + /* Dark-specific overrides if needed */ +} + +:host([high-contrast]) { + /* High contrast overrides if needed */ +} +``` + +## Theme Persistence + +The theme system automatically persists the user's selection to `localStorage`. On page load: + +1. Check `localStorage` for saved preference +2. If `'auto'` or no saved preference, detect from system media queries +3. Apply resolved theme +4. Listen for system preference changes (if `'auto'`) + +## Iframe Theme Propagation + +For apps with iframes, the theme propagates automatically via a `theme` attribute. Child iframes receive the parent's theme selection. + +## Adding a Theme Picker to the UI + +Use the layout package's built-in components: + +```html + + + + + +``` + +These components handle selection, persistence, and visual feedback automatically. + +## Responding to Theme Changes + +Register a callback to react when the theme changes: + +```typescript +import { theme } from '@kurrent-ui/theme'; + +theme.onThemeChange((currentTheme) => { + // Update chart colors, canvas rendering, etc. + updateChartColors(currentTheme.colors); +}); +``` + +## Migration: Replacing Hardcoded Colors + +When migrating an existing app to the Kurrent theme system: + +1. Search for hardcoded color values (`#`, `rgb(`, `hsl(`, named colors) +2. Map each to the nearest `--color-*` token +3. Replace with `var(--color-token)` +4. Test in all four themes (light, dark, high-contrast light, high-contrast dark) + +Common mappings: +| Hardcoded | Replace With | +|-----------|-------------| +| White / `#fff` backgrounds | `var(--color-background)` | +| Black / dark text | `var(--color-foreground)` | +| Bold/heading text | `var(--color-title)` | +| Brand blue/purple | `var(--color-highlight)` | +| Red errors | `var(--color-error)` | +| Green success | `var(--color-success)` | +| Gray borders | `var(--color-shade-20)` to `var(--color-shade-40)` | +| Disabled gray | `var(--color-disabled)` |