Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"data": {
"meta": {
"adoptsFrom": {
"name": "ComponentListing",
"module": "@cardstack/catalog/catalog-app/listing/listing"
}
},
"type": "card",
"attributes": {
"name": "Stepper UI",
"summary": "The Stepper component provides a multi-step flow shell for first-run wizards, onboarding journeys, and setup checklists — a guideline book that walks the user through what to fill in, in what order, before they start using an app. It renders a vertical step rail (numbered dots, checkmark done states, active ring, connector lines) beside the active step's content pane, closed out by a Back / Skip / Next action bar built from boxel-ui Button. The host supplies step definitions and per-step content through named blocks while the component owns the step state machine: gating Next on per-step isComplete wired to host state, MUI-style optional steps that surface a Skip button, onStepChange enter hooks for lazy loading, and optional rail click-to-jump. It supports an inline bordered-card mode and a modal mode (scrim plus centered card) for first-run experiences, a header with kicker, title, and an outlined-circle close button, and a fully replaceable actions block. Theming is driven by the linked theme: every color, font, and radius resolves --stepper-* override knob, then theme semantic token (the --primary / --primary-foreground pair drives the accent fills, their on-fill content, and the Next button), then neutral Boxel-token defaults — link a Theme card or Brand Guide and the whole stepper restyles with no stepper-specific work.",
"cardInfo": {
"name": "Stepper UI",
"notes": null,
"summary": null,
"cardThumbnailURL": null
}
},
"relationships": {
"skills": {
"links": {
"self": null
}
},
"tags.0": {
"links": {
"self": "../../Tag/card"
}
},
"license": {
"links": {
"self": null
}
},
"specs.0": {
"links": {
"self": "../Spec/stepper"
}
},
"specs.1": {
"links": {
"self": "../Spec/stepper-playground-example"
}
},
"specs.2": {
"links": {
"self": "../../Spec/code-snippet"
}
},
"images.0": {
"links": {
"self": "../Screenshots/c76678a0-a2ee-4142-a3d7-a9f537df7c52-d5ab6927.png"
}
},
"publisher": {
"links": {
"self": null
}
},
"examples.0": {
"links": {
"self": "../example/StepperPlayground/c76678a0-a2ee-4142-a3d7-a9f537df7c52"
}
},
"categories.0": {
"links": {
"self": "../../Category/ui-components-design"
}
},
"cardInfo.theme": {
"links": {
"self": null
}
},
"cardInfo.cardThumbnail": {
"links": {
"self": "../Screenshots/c76678a0-a2ee-4142-a3d7-a9f537df7c52-d5ab6927.png"
}
}
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions aef6db-stepper/Spec/stepper-playground-example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"data": {
"meta": {
"adoptsFrom": {
"name": "Spec",
"module": "@cardstack/base/spec"
}
},
"type": "card",
"attributes": {
"ref": {
"name": "StepperPlayground",
"module": "../example/stepper-playground-example"
},
"readMe": "## Stepper Playground\n\nA config explorer for `<Stepper>`. Live preview on top, knobs for `@modal` (inline vs scrim + centered card) and `@allowStepJump` below it, then the generated invocation and the full API reference. Colors, fonts, and radius come from the linked theme (cardInfo.theme) via the semantic tokens (`--primary` / `--primary-foreground`, `--foreground`, `--muted`, `--card`, `--border`, `--radius`, `--font-sans`) — link a different Theme card and the whole stepper restyles with no stepper-specific work.\n\nThe live 4-step demo's completion gating is REAL: step 1 completes when you type a name, step 2 when you pick a workspace — exactly how a product wires `isComplete` to its own state. Step 3 sets `optional: true` so a Skip button appears (MUI-style); the steps before it are linear. The last step shows the `@finishLabel` / `@onFinish` primary button, and an event line above the stage prints every `onStepChange` / `onClose` / `onFinish` as it fires.\n\nThis is the **teaching example** for the Stepper API — the generated-code panel prints the exact invocation for the current knob combination.",
"cardInfo": {
"name": null,
"notes": null,
"summary": null,
"cardThumbnailURL": null
},
"specType": "card",
"cardTitle": "Stepper Playground",
"cardDescription": "A live config explorer for <Stepper> — modal and step-jump knobs over a real gated 4-step demo that follows the linked theme, with the generated invocation printed alongside. The teaching example for the Stepper API.",
"containedExamples": []
},
"relationships": {
"cardInfo.theme": {
"links": {
"self": null
}
},
"linkedExamples.0": {
"links": {
"self": "../example/StepperPlayground/c76678a0-a2ee-4142-a3d7-a9f537df7c52"
}
},
"cardInfo.cardThumbnail": {
"links": {
"self": null
}
}
}
}
}
45 changes: 45 additions & 0 deletions aef6db-stepper/Spec/stepper.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"data": {
"meta": {
"adoptsFrom": {
"name": "Spec",
"module": "@cardstack/base/spec"
}
},
"type": "card",
"attributes": {
"ref": {
"name": "default",
"module": "../stepper"
},
"readMe": "## Stepper\n\nA general multi-step flow shell — the \"guideline book\" that walks a user through a journey (a first-run wizard, an onboarding flow, a setup checklist) *before* they start using an app. Two-pane layout: a vertical step rail on the left (numbered dots, ✓ done state, active ring, connector lines) and the active step's content on the right, closed out by a Back / Skip / Next action bar built from boxel-ui `<Button>`.\n\nThe first consumer is the Table Seating Planner's setup wizard; the component carries no wedding-specific anything — every product supplies its own steps, content, and brand.\n\n### Ownership split\n\nThe **host** owns the step definitions (labels, completion state) and each step's content, supplied through the `<:step>` named block. The **Stepper** owns the step state machine, the rail's done/active painting, gating Next on `isComplete`, and the shell chrome (header, action bar, optional modal scrim). The component never closes itself — visibility stays with the host, exactly like Popover's `@open`.\n\n### Steps — `StepperStep[]`\n\n```ts\ninterface StepperStep {\n id: string; // dispatch key for the <:step> block\n label: string; // rail label ('Your event')\n summary?: string; // rail sub-line while pending; swaps to 'Completed' when done\n title?: string; // content-pane heading (defaults to label)\n description?: string; // content-pane sub-line\n icon?: ComponentLike; // lead icon circle above the title\n isComplete?: boolean; // gates Next + paints the rail ✓; omit = never gates\n optional?: boolean; // shows a Skip button on this step (MUI-style)\n}\n```\n\n- **Completion gating is host-wired**: point `isComplete` at your own state (`this.name.length > 0`, `this.guests.length > 0`) and Next unlocks/locks live.\n- **Skip is per-step opt-in** (`optional: true`), following the MUI Stepper convention — linear steps get no Skip button. `api.skip` remains available for custom action bars.\n\n### Args\n\n| Arg | Purpose |\n| --- | --- |\n| `@steps` | the `StepperStep[]` above |\n| `@modal` | wrap in a scrim + centered card (`position: absolute; inset: 0` — fills the nearest positioned ancestor). Default inline bordered card |\n| `@kicker` / `@title` | header eyebrow + brand name; header renders only when one of these (or the close button) is present |\n| `@onClose` / `@showClose` | ✕ close — an outlined 30px circle, no fill (same treatment as the seating planner's popover close). `@showClose` defaults to true whenever `@onClose` is set |\n| `@finishLabel` / `@onFinish` | the last step swaps Skip/Next for a single primary button labeled `finishLabel` (default 'Done') |\n| `@onStepChange` | fires `(step, index)` on every step entry — use for enter hooks (e.g. lazy-load data when the user reaches a step) |\n| `@initialStep` | start on a later step (resume) |\n| `@allowStepJump` | click rail items to jump between steps. Off by default so wizards stay linear |\n\n### Blocks\n\n- `<:step as |step api|>` — the active step's content; dispatch on `step.id`. The `api` bundle exposes `next` / `back` / `skip` / `goTo` plus `index` / `isFirst` / `isLast` / `canProceed` for hosts that want custom controls inside the content.\n- `<:actions as |api|>` — replaces the default action bar entirely.\n- `<:decoration>` — renders inside the card for brand art (the seating planner puts its gold corner mandala here).\n\n### Accent & contrast\n\nFills (done dots, connectors, the lead icon circle) paint with the accent; the content ON those fills (✓ glyph, icon) uses a separate foreground so it always reads:\n\n- The fills follow the linked theme's `--primary` with `--primary-foreground` as the on-fill content — themes author this pair as a contrast pairing. With no theme, the fallback is `--boxel-highlight` (bright green) with a dark on-fill color — correct WCAG pairing.\n- For a one-off brand override, set the `--stepper-accent` / `--stepper-accent-fg` pair on a host class (the seating planner sets gold + white).\n- Text on the light rail (active label, kicker) stays ink/muted — accent is for fills only, never light-background text.\n\n### Theming — the theme system drives it\n\nEvery visual value resolves through three scopes, strongest first:\n\n1. **Stepper-only knobs** — `--stepper-*` custom properties set on a host class restyle ONLY the stepper: `--stepper-accent` · `--stepper-accent-fg` · `--stepper-ink` · `--stepper-muted` · `--stepper-surface` (rail bg) · `--stepper-card-bg` · `--stepper-border` · `--stepper-connector` · `--stepper-primary-bg` / `--stepper-primary-fg` (Next button) · `--stepper-kicker-color` · `--stepper-heading-font` · `--stepper-body-font` · `--stepper-radius` · `--stepper-scrim-bg` · `--stepper-shadow`\n2. **Theme semantic tokens** — link a Theme card / Brand Guide and the stepper follows automatically: `--primary` / `--primary-foreground` drive the accent fills, their on-fill content, and the Next button; `--foreground`, `--muted`, `--muted-foreground`, `--card`, `--border`, `--radius`, and `--font-sans` drive text, surfaces, hairlines, corners, and type.\n3. **Built-in neutral defaults** (Boxel tokens) — used with no theme at all.\n\nThe seating planner's Parisian look (navy/gold, Cormorant + Jost) is a scope-1 override — see `wz-theme` in its setup-wizard for the full block.\n\n## Usage\n\nThe **Stepper Playground** example is the canonical reference — knobs for `@modal` and `@allowStepJump` over a live 4-step demo whose gating is real, with a generated-invocation panel; its colors follow the linked theme. The minimal shape:\n\n```gts\nimport Stepper from '../stepper';\nimport type { StepperStep } from '../stepper';\n\nget steps(): StepperStep[] {\n return [\n { id: 'event', label: 'Your event', summary: 'Event details',\n description: 'Tell us about it.', icon: CalendarIcon,\n isComplete: !!this.title, optional: true },\n { id: 'template', label: 'Template', summary: 'Choose a layout' },\n ];\n}\n\n<template>\n <Stepper\n @modal={{true}}\n @steps={{this.steps}}\n @kicker='Getting started'\n @title='My Product'\n @finishLabel='Start blank'\n @onClose={{this.dismiss}}\n @onFinish={{this.dismiss}}\n @onStepChange={{this.stepEntered}}\n >\n <:step as |step|>\n {{#if (eq step.id 'event')}} …event form… {{else}} …template list… {{/if}}\n </:step>\n </Stepper>\n</template>\n```\n\nCross-realm import: `@cardstack/catalog/aef6db-stepper/stepper`.",
"cardInfo": {
"name": null,
"notes": null,
"summary": null,
"cardThumbnailURL": null
},
"specType": "component",
"cardTitle": "Stepper",
"cardDescription": "A multi-step flow shell for first-run wizards and onboarding journeys: vertical step rail, per-step completion gating, MUI-style optional steps, boxel-ui buttons, and theme-driven styling (--primary/--primary-foreground pair) with --stepper-* override knobs.",
"containedExamples": []
},
"relationships": {
"cardInfo.theme": {
"links": {
"self": null
}
},
"linkedExamples": {
"links": {
"self": null
}
},
"cardInfo.cardThumbnail": {
"links": {
"self": null
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"data": {
"meta": {
"adoptsFrom": {
"name": "StepperPlayground",
"module": "@cardstack/catalog/aef6db-stepper/example/stepper-playground-example"
}
},
"type": "card",
"attributes": {
"title": "Stepper Playground Example",
"cardInfo": {
"name": "Stepper Playground Example",
"notes": null,
"summary": null,
"cardThumbnailURL": null
}
},
"relationships": {
"cardInfo.theme": {
"links": {
"self": null
}
},
"cardInfo.cardThumbnail": {
"links": {
"self": null
}
}
}
}
}
Loading
Loading