@awarebydefault/display-case 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/display-case.prompt.md +64 -0
- package/docs/ai-agents.md +126 -0
- package/docs/cli.md +99 -0
- package/docs/configuration.md +410 -0
- package/docs/documentation-panel.md +50 -0
- package/docs/examples/README.md +14 -0
- package/docs/examples/multi-variant.case.tsx +30 -0
- package/docs/examples/plain.case.tsx +22 -0
- package/docs/examples/tweak-control.placard.md +80 -0
- package/docs/examples/tweaks.case.tsx +39 -0
- package/docs/hierarchy.md +59 -0
- package/docs/quick-start.md +78 -0
- package/docs/style-engines.md +180 -0
- package/docs/testing.md +245 -0
- package/docs/theming.md +97 -0
- package/docs/tweaks.md +75 -0
- package/docs/writing-cases.md +144 -0
- package/docs/writing-placard-docs.md +194 -0
- package/package.json +113 -0
- package/skills/display-case-author-case/README.md +20 -0
- package/skills/display-case-author-case/SKILL.md +40 -0
- package/skills/display-case-author-placard-doc/README.md +24 -0
- package/skills/display-case-author-placard-doc/SKILL.md +65 -0
- package/skills/display-case-review/README.md +19 -0
- package/skills/display-case-review/SKILL.md +30 -0
- package/skills/display-case-snapshot/README.md +20 -0
- package/skills/display-case-snapshot/SKILL.md +29 -0
- package/src/checks/a11y-scanner.test.ts +240 -0
- package/src/checks/a11y-scanner.ts +410 -0
- package/src/checks/check-text.test.ts +53 -0
- package/src/checks/check-text.ts +78 -0
- package/src/checks/check.test.ts +194 -0
- package/src/checks/check.ts +473 -0
- package/src/checks/providers/pixelmatch-diff.test.ts +79 -0
- package/src/checks/providers/pixelmatch-diff.ts +30 -0
- package/src/checks/providers/playwright-driver.ts +104 -0
- package/src/checks/ssr-check.test.ts +73 -0
- package/src/checks/ssr-check.ts +96 -0
- package/src/checks/structure-check.cross-package.test.ts +165 -0
- package/src/checks/structure-check.test.ts +651 -0
- package/src/checks/structure-check.ts +988 -0
- package/src/checks/tokens-check.test.ts +159 -0
- package/src/checks/tokens-check.ts +162 -0
- package/src/cli.ts +218 -0
- package/src/commands/agents.test.ts +24 -0
- package/src/commands/agents.ts +28 -0
- package/src/commands/init-run.test.ts +123 -0
- package/src/commands/init.test.ts +63 -0
- package/src/commands/init.ts +412 -0
- package/src/commands/publish.test.ts +210 -0
- package/src/commands/publish.ts +292 -0
- package/src/core/affected.test.ts +99 -0
- package/src/core/affected.ts +144 -0
- package/src/core/catalog.test.ts +152 -0
- package/src/core/catalog.ts +92 -0
- package/src/core/discovery.test.ts +184 -0
- package/src/core/discovery.ts +250 -0
- package/src/core/manifest.ts +41 -0
- package/src/core/mdx-lite/__fixtures__/box-stub.tsx +7 -0
- package/src/core/mdx-lite/index.ts +393 -0
- package/src/core/mdx-lite/mdx-lite.test.ts +345 -0
- package/src/core/mdx-plugin.test.ts +60 -0
- package/src/core/mdx-plugin.ts +30 -0
- package/src/flow-step.test-d.ts +39 -0
- package/src/index.test.ts +100 -0
- package/src/index.ts +564 -0
- package/src/render/collect-styles.emotion.test.tsx +114 -0
- package/src/render/collect-styles.test.tsx +72 -0
- package/src/render/collect-styles.ts +33 -0
- package/src/render/documents.test.ts +184 -0
- package/src/render/documents.ts +88 -0
- package/src/render/render-node.test.tsx +160 -0
- package/src/render/render-node.tsx +133 -0
- package/src/render/ssr-primer.test.tsx +25 -0
- package/src/render/ssr-primer.tsx +54 -0
- package/src/render/ssr-render.test.tsx +142 -0
- package/src/render/ssr-render.tsx +63 -0
- package/src/render/ssr-shell.test.tsx +57 -0
- package/src/render/ssr-shell.tsx +54 -0
- package/src/server/prod-server.ts +237 -0
- package/src/server/server.test.ts +117 -0
- package/src/server/server.ts +1039 -0
- package/src/style-engine.test-d.ts +37 -0
- package/src/testing/test-helpers.ts +27 -0
- package/src/types/pixelmatch.d.ts +12 -0
- package/src/ui/browser-entry.tsx +51 -0
- package/src/ui/chrome.css +485 -0
- package/src/ui/design-system/README.md +88 -0
- package/src/ui/design-system/components/controls/Button.case.tsx +52 -0
- package/src/ui/design-system/components/controls/Button.css +89 -0
- package/src/ui/design-system/components/controls/Button.placard.md +14 -0
- package/src/ui/design-system/components/controls/Button.test.tsx +45 -0
- package/src/ui/design-system/components/controls/Button.tsx +41 -0
- package/src/ui/design-system/components/controls/IconButton.case.tsx +52 -0
- package/src/ui/design-system/components/controls/IconButton.css +67 -0
- package/src/ui/design-system/components/controls/IconButton.placard.md +13 -0
- package/src/ui/design-system/components/controls/IconButton.test.tsx +39 -0
- package/src/ui/design-system/components/controls/IconButton.tsx +47 -0
- package/src/ui/design-system/components/controls/Input.case.tsx +50 -0
- package/src/ui/design-system/components/controls/Input.css +52 -0
- package/src/ui/design-system/components/controls/Input.placard.md +12 -0
- package/src/ui/design-system/components/controls/Input.test.tsx +43 -0
- package/src/ui/design-system/components/controls/Input.tsx +45 -0
- package/src/ui/design-system/components/controls/Select.case.tsx +48 -0
- package/src/ui/design-system/components/controls/Select.css +44 -0
- package/src/ui/design-system/components/controls/Select.placard.md +15 -0
- package/src/ui/design-system/components/controls/Select.test.tsx +57 -0
- package/src/ui/design-system/components/controls/Select.tsx +58 -0
- package/src/ui/design-system/components/controls/SelectMenu.case.tsx +100 -0
- package/src/ui/design-system/components/controls/SelectMenu.css +72 -0
- package/src/ui/design-system/components/controls/SelectMenu.placard.md +18 -0
- package/src/ui/design-system/components/controls/SelectMenu.test.tsx +66 -0
- package/src/ui/design-system/components/controls/SelectMenu.tsx +377 -0
- package/src/ui/design-system/components/index.ts +66 -0
- package/src/ui/design-system/components/primer-specimen/ColorRamp.case.tsx +44 -0
- package/src/ui/design-system/components/primer-specimen/ColorRamp.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/ColorRamp.tsx +51 -0
- package/src/ui/design-system/components/primer-specimen/DefinitionList.case.tsx +38 -0
- package/src/ui/design-system/components/primer-specimen/DefinitionList.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/DefinitionList.tsx +41 -0
- package/src/ui/design-system/components/primer-specimen/FontFamilies.case.tsx +24 -0
- package/src/ui/design-system/components/primer-specimen/FontFamilies.placard.md +12 -0
- package/src/ui/design-system/components/primer-specimen/FontFamilies.tsx +41 -0
- package/src/ui/design-system/components/primer-specimen/GlyphGrid.case.tsx +27 -0
- package/src/ui/design-system/components/primer-specimen/GlyphGrid.placard.md +13 -0
- package/src/ui/design-system/components/primer-specimen/GlyphGrid.tsx +34 -0
- package/src/ui/design-system/components/primer-specimen/LayoutMock.case.tsx +36 -0
- package/src/ui/design-system/components/primer-specimen/LayoutMock.placard.md +7 -0
- package/src/ui/design-system/components/primer-specimen/LayoutMock.tsx +36 -0
- package/src/ui/design-system/components/primer-specimen/SpacingScale.case.tsx +20 -0
- package/src/ui/design-system/components/primer-specimen/SpacingScale.placard.md +12 -0
- package/src/ui/design-system/components/primer-specimen/SpacingScale.tsx +33 -0
- package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.case.tsx +56 -0
- package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.placard.md +17 -0
- package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.tsx +45 -0
- package/src/ui/design-system/components/primer-specimen/StatusList.case.tsx +17 -0
- package/src/ui/design-system/components/primer-specimen/StatusList.placard.md +16 -0
- package/src/ui/design-system/components/primer-specimen/StatusList.tsx +39 -0
- package/src/ui/design-system/components/primer-specimen/SwatchGrid.case.tsx +26 -0
- package/src/ui/design-system/components/primer-specimen/SwatchGrid.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/SwatchGrid.tsx +42 -0
- package/src/ui/design-system/components/primer-specimen/TypeScale.case.tsx +23 -0
- package/src/ui/design-system/components/primer-specimen/TypeScale.placard.md +14 -0
- package/src/ui/design-system/components/primer-specimen/TypeScale.tsx +34 -0
- package/src/ui/design-system/components/primer-specimen/WeightSpecimen.case.tsx +28 -0
- package/src/ui/design-system/components/primer-specimen/WeightSpecimen.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/WeightSpecimen.tsx +46 -0
- package/src/ui/design-system/components/primer-specimen/index.ts +31 -0
- package/src/ui/design-system/components/primer-specimen/styles.css +476 -0
- package/src/ui/design-system/components/shell/A11yPage.case.tsx +237 -0
- package/src/ui/design-system/components/shell/A11yPage.placard.md +15 -0
- package/src/ui/design-system/components/shell/CaseTemplate.case.tsx +32 -0
- package/src/ui/design-system/components/shell/CaseTemplate.placard.md +5 -0
- package/src/ui/design-system/components/shell/CasesPage.case.tsx +141 -0
- package/src/ui/design-system/components/shell/CasesPage.placard.md +12 -0
- package/src/ui/design-system/components/shell/PrimerPage.case.tsx +22 -0
- package/src/ui/design-system/components/shell/PrimerPage.placard.md +3 -0
- package/src/ui/design-system/components/shell/PrimerTemplate.case.tsx +22 -0
- package/src/ui/design-system/components/shell/PrimerTemplate.placard.md +5 -0
- package/src/ui/design-system/components/shell/ShellView.case.tsx +57 -0
- package/src/ui/design-system/components/shell/ShellView.placard.md +5 -0
- package/src/ui/design-system/components/shell/ShellView.tsx +678 -0
- package/src/ui/design-system/components/shell/shell-fixtures.tsx +727 -0
- package/src/ui/design-system/components/showcase/A11yBadge.case.tsx +46 -0
- package/src/ui/design-system/components/showcase/A11yBadge.css +27 -0
- package/src/ui/design-system/components/showcase/A11yBadge.placard.md +11 -0
- package/src/ui/design-system/components/showcase/A11yBadge.test.tsx +31 -0
- package/src/ui/design-system/components/showcase/A11yBadge.tsx +41 -0
- package/src/ui/design-system/components/showcase/A11yPanel.case.tsx +121 -0
- package/src/ui/design-system/components/showcase/A11yPanel.css +198 -0
- package/src/ui/design-system/components/showcase/A11yPanel.placard.md +19 -0
- package/src/ui/design-system/components/showcase/A11yPanel.test.tsx +81 -0
- package/src/ui/design-system/components/showcase/A11yPanel.tsx +144 -0
- package/src/ui/design-system/components/showcase/Chip.case.tsx +48 -0
- package/src/ui/design-system/components/showcase/Chip.css +51 -0
- package/src/ui/design-system/components/showcase/Chip.placard.md +13 -0
- package/src/ui/design-system/components/showcase/Chip.test.tsx +46 -0
- package/src/ui/design-system/components/showcase/Chip.tsx +54 -0
- package/src/ui/design-system/components/showcase/Eyebrow.case.tsx +30 -0
- package/src/ui/design-system/components/showcase/Eyebrow.css +16 -0
- package/src/ui/design-system/components/showcase/Eyebrow.placard.md +10 -0
- package/src/ui/design-system/components/showcase/Eyebrow.test.tsx +38 -0
- package/src/ui/design-system/components/showcase/Eyebrow.tsx +29 -0
- package/src/ui/design-system/components/showcase/FlowNav.case.tsx +35 -0
- package/src/ui/design-system/components/showcase/FlowNav.css +29 -0
- package/src/ui/design-system/components/showcase/FlowNav.placard.md +13 -0
- package/src/ui/design-system/components/showcase/FlowNav.test.tsx +48 -0
- package/src/ui/design-system/components/showcase/FlowNav.tsx +58 -0
- package/src/ui/design-system/components/showcase/ImpactTag.case.tsx +19 -0
- package/src/ui/design-system/components/showcase/ImpactTag.css +36 -0
- package/src/ui/design-system/components/showcase/ImpactTag.placard.md +14 -0
- package/src/ui/design-system/components/showcase/ImpactTag.test.tsx +40 -0
- package/src/ui/design-system/components/showcase/ImpactTag.tsx +35 -0
- package/src/ui/design-system/components/showcase/NavItem.case.tsx +86 -0
- package/src/ui/design-system/components/showcase/NavItem.css +111 -0
- package/src/ui/design-system/components/showcase/NavItem.placard.md +13 -0
- package/src/ui/design-system/components/showcase/NavItem.test.tsx +65 -0
- package/src/ui/design-system/components/showcase/NavItem.tsx +95 -0
- package/src/ui/design-system/components/showcase/RenderAddress.case.tsx +21 -0
- package/src/ui/design-system/components/showcase/RenderAddress.css +35 -0
- package/src/ui/design-system/components/showcase/RenderAddress.placard.md +7 -0
- package/src/ui/design-system/components/showcase/RenderAddress.test.tsx +26 -0
- package/src/ui/design-system/components/showcase/RenderAddress.tsx +43 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.case.tsx +84 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.css +61 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.placard.md +21 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.test.tsx +81 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.tsx +75 -0
- package/src/ui/design-system/components/showcase/Sidebar.case.tsx +67 -0
- package/src/ui/design-system/components/showcase/Sidebar.css +6 -0
- package/src/ui/design-system/components/showcase/Sidebar.placard.md +14 -0
- package/src/ui/design-system/components/showcase/Sidebar.test.tsx +32 -0
- package/src/ui/design-system/components/showcase/Sidebar.tsx +30 -0
- package/src/ui/design-system/components/showcase/Stage.case.tsx +51 -0
- package/src/ui/design-system/components/showcase/Stage.css +91 -0
- package/src/ui/design-system/components/showcase/Stage.placard.md +15 -0
- package/src/ui/design-system/components/showcase/Stage.test.tsx +84 -0
- package/src/ui/design-system/components/showcase/Stage.tsx +97 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.case.tsx +81 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.css +169 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.placard.md +20 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.tsx +230 -0
- package/src/ui/design-system/components/showcase/Wordmark.case.tsx +42 -0
- package/src/ui/design-system/components/showcase/Wordmark.css +31 -0
- package/src/ui/design-system/components/showcase/Wordmark.placard.md +10 -0
- package/src/ui/design-system/components/showcase/Wordmark.test.tsx +22 -0
- package/src/ui/design-system/components/showcase/Wordmark.tsx +22 -0
- package/src/ui/design-system/primer-specimens/brand.tsx +26 -0
- package/src/ui/design-system/primer-specimens/colors.tsx +83 -0
- package/src/ui/design-system/primer-specimens/components.tsx +308 -0
- package/src/ui/design-system/primer-specimens/foundations.tsx +71 -0
- package/src/ui/design-system/primer-specimens/index.ts +25 -0
- package/src/ui/design-system/primer-specimens/showcase.tsx +68 -0
- package/src/ui/design-system/primer-specimens/spacing.tsx +101 -0
- package/src/ui/design-system/primer-specimens/type.tsx +75 -0
- package/src/ui/design-system/primer.mdx +236 -0
- package/src/ui/design-system/styles.css +14 -0
- package/src/ui/design-system/tokens/colors.css +172 -0
- package/src/ui/design-system/tokens/fonts.css +18 -0
- package/src/ui/design-system/tokens/spacing.css +48 -0
- package/src/ui/design-system/tokens/typography.css +49 -0
- package/src/ui/markdown.test.tsx +54 -0
- package/src/ui/markdown.tsx +19 -0
- package/src/ui/primer-mount.tsx +76 -0
- package/src/ui/primer.css +175 -0
- package/src/ui/primer.tsx +277 -0
- package/src/ui/render-mount.tsx +284 -0
- package/src/ui/shell-core.test.ts +340 -0
- package/src/ui/shell-core.ts +295 -0
- package/src/ui/shell.tsx +60 -0
- package/src/ui/test-ids.ts +53 -0
- package/src/ui/use-shell.ts +1230 -0
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
// display-case: no-case — shared static fixtures for the chrome's page/template/
|
|
2
|
+
// flow exhibits, not a showcased component of its own.
|
|
3
|
+
//
|
|
4
|
+
// These build a complete, static {@link ShellViewModel} (the same shape
|
|
5
|
+
// {@link useShell} produces live) so the pure {@link ShellView} can be exhibited
|
|
6
|
+
// as a template (placeholder slots), a page (real content slotted in), and a
|
|
7
|
+
// flow (Primer ↔ Cases) — Display Case dogfooding its own layout end to end.
|
|
8
|
+
import type { ReactNode } from 'react'
|
|
9
|
+
import { slugify } from '../../../../core/catalog'
|
|
10
|
+
import type {
|
|
11
|
+
Manifest,
|
|
12
|
+
ManifestCase,
|
|
13
|
+
ManifestComponent,
|
|
14
|
+
} from '../../../../core/manifest'
|
|
15
|
+
import type { A11yViolation, TweakSchema } from '../../../../index'
|
|
16
|
+
import { Display } from '../../../primer'
|
|
17
|
+
import { groupByLevel, groupPrimerSections } from '../../../shell-core'
|
|
18
|
+
import type { A11ySurface, ShellViewModel } from '../../../use-shell'
|
|
19
|
+
import { Button, Chip } from '..'
|
|
20
|
+
|
|
21
|
+
const noop = () => {}
|
|
22
|
+
const nullRef = { current: null }
|
|
23
|
+
|
|
24
|
+
function mkCase(
|
|
25
|
+
componentId: string,
|
|
26
|
+
name: string,
|
|
27
|
+
opts: { tweaks?: TweakSchema; transitions?: string[] } = {},
|
|
28
|
+
): ManifestCase {
|
|
29
|
+
const id = slugify(name)
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
name,
|
|
33
|
+
browseUrl: `/c/${componentId}/${id}`,
|
|
34
|
+
renderUrl: `/render/${componentId}/${id}`,
|
|
35
|
+
tweaks: opts.tweaks ?? null,
|
|
36
|
+
transitions: opts.transitions ?? [],
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function mkComponent(
|
|
41
|
+
c: Pick<ManifestComponent, 'id' | 'name' | 'level'> &
|
|
42
|
+
Partial<ManifestComponent> & { cases: ManifestCase[] },
|
|
43
|
+
): ManifestComponent {
|
|
44
|
+
return {
|
|
45
|
+
isFlow: false,
|
|
46
|
+
caseFile: `src/ui/design-system/components/${c.id}.case.tsx`,
|
|
47
|
+
placardDoc: null,
|
|
48
|
+
...c,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const PLACEHOLDER_TWEAKS: TweakSchema = {
|
|
53
|
+
property: { kind: 'text', default: 'value' },
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The real Button Playground schema (mirrors controls/Button.case.tsx), so the
|
|
57
|
+
// Button page's tweaks exhibits show the actual controls — and their default
|
|
58
|
+
// values — that drive the Playground button on the stage.
|
|
59
|
+
export const BUTTON_PLAYGROUND_TWEAKS: TweakSchema = {
|
|
60
|
+
label: { kind: 'text', default: 'Button' },
|
|
61
|
+
variant: {
|
|
62
|
+
kind: 'choice',
|
|
63
|
+
options: ['ghost', 'primary', 'accent', 'subtle'],
|
|
64
|
+
default: 'ghost',
|
|
65
|
+
},
|
|
66
|
+
size: { kind: 'choice', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
67
|
+
pressed: { kind: 'boolean', default: false },
|
|
68
|
+
disabled: { kind: 'boolean', default: false },
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* A representative manifest spanning every hierarchy level, so the exhibited
|
|
73
|
+
* chrome's nav rail shows the full Atoms → Flows ladder (just like a real
|
|
74
|
+
* Display Case). It is data only — the exhibits slot their own live content onto
|
|
75
|
+
* the stage rather than loading these `renderUrl`s.
|
|
76
|
+
*/
|
|
77
|
+
export const mockManifest: Manifest = {
|
|
78
|
+
title: 'Display Case',
|
|
79
|
+
primer: true,
|
|
80
|
+
landing: 'primer',
|
|
81
|
+
components: [
|
|
82
|
+
mkComponent({
|
|
83
|
+
id: 'button',
|
|
84
|
+
name: 'Button',
|
|
85
|
+
level: 'atom',
|
|
86
|
+
placardDoc: 'src/ui/design-system/components/showcase/Button.placard.md',
|
|
87
|
+
cases: [
|
|
88
|
+
mkCase('button', 'Playground', { tweaks: BUTTON_PLAYGROUND_TWEAKS }),
|
|
89
|
+
mkCase('button', 'Variants'),
|
|
90
|
+
mkCase('button', 'Sizes'),
|
|
91
|
+
],
|
|
92
|
+
}),
|
|
93
|
+
mkComponent({
|
|
94
|
+
id: 'input',
|
|
95
|
+
name: 'Input',
|
|
96
|
+
level: 'atom',
|
|
97
|
+
cases: [mkCase('input', 'Default'), mkCase('input', 'Sizes')],
|
|
98
|
+
}),
|
|
99
|
+
mkComponent({
|
|
100
|
+
id: 'render-address',
|
|
101
|
+
name: 'RenderAddress',
|
|
102
|
+
level: 'molecule',
|
|
103
|
+
cases: [mkCase('render-address', 'Default')],
|
|
104
|
+
}),
|
|
105
|
+
mkComponent({
|
|
106
|
+
id: 'tweaks-panel',
|
|
107
|
+
name: 'TweaksPanel',
|
|
108
|
+
level: 'molecule',
|
|
109
|
+
cases: [
|
|
110
|
+
mkCase('tweaks-panel', 'Playground', { tweaks: PLACEHOLDER_TWEAKS }),
|
|
111
|
+
mkCase('tweaks-panel', 'Docked'),
|
|
112
|
+
],
|
|
113
|
+
}),
|
|
114
|
+
mkComponent({
|
|
115
|
+
id: 'sidebar',
|
|
116
|
+
name: 'Sidebar',
|
|
117
|
+
level: 'organism',
|
|
118
|
+
cases: [mkCase('sidebar', 'Default')],
|
|
119
|
+
}),
|
|
120
|
+
mkComponent({
|
|
121
|
+
id: 'case-template',
|
|
122
|
+
name: 'Case template',
|
|
123
|
+
level: 'template',
|
|
124
|
+
cases: [mkCase('case-template', 'Default')],
|
|
125
|
+
}),
|
|
126
|
+
mkComponent({
|
|
127
|
+
id: 'cases-page',
|
|
128
|
+
name: 'Cases page',
|
|
129
|
+
level: 'page',
|
|
130
|
+
cases: [mkCase('cases-page', 'Default')],
|
|
131
|
+
}),
|
|
132
|
+
mkComponent({
|
|
133
|
+
id: 'primer-page',
|
|
134
|
+
name: 'Primer page',
|
|
135
|
+
level: 'page',
|
|
136
|
+
cases: [mkCase('primer-page', 'Default')],
|
|
137
|
+
}),
|
|
138
|
+
mkComponent({
|
|
139
|
+
id: 'a11y-page',
|
|
140
|
+
name: 'A11y page',
|
|
141
|
+
level: 'page',
|
|
142
|
+
cases: [mkCase('a11y-page', 'Default')],
|
|
143
|
+
}),
|
|
144
|
+
mkComponent({
|
|
145
|
+
id: 'primer-to-cases',
|
|
146
|
+
name: 'Primer to Cases',
|
|
147
|
+
level: 'flow',
|
|
148
|
+
isFlow: true,
|
|
149
|
+
cases: [
|
|
150
|
+
mkCase('primer-to-cases', 'Primer view', {
|
|
151
|
+
transitions: [slugify('Cases view')],
|
|
152
|
+
}),
|
|
153
|
+
mkCase('primer-to-cases', 'Cases view', {
|
|
154
|
+
transitions: [slugify('Primer view')],
|
|
155
|
+
}),
|
|
156
|
+
],
|
|
157
|
+
}),
|
|
158
|
+
// A representative product flow, so the Cases view's "Flow" exhibit shows
|
|
159
|
+
// the FlowNav stepper over a real-looking sequence of steps.
|
|
160
|
+
mkComponent({
|
|
161
|
+
id: 'sign-in',
|
|
162
|
+
name: 'Sign-in',
|
|
163
|
+
level: 'flow',
|
|
164
|
+
isFlow: true,
|
|
165
|
+
cases: [
|
|
166
|
+
mkCase('sign-in', 'Request link', {
|
|
167
|
+
transitions: [slugify('Check email')],
|
|
168
|
+
}),
|
|
169
|
+
mkCase('sign-in', 'Check email', {
|
|
170
|
+
transitions: [slugify('Confirmed')],
|
|
171
|
+
}),
|
|
172
|
+
mkCase('sign-in', 'Confirmed'),
|
|
173
|
+
],
|
|
174
|
+
}),
|
|
175
|
+
],
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// A static Primer table of contents for the primer-mode exhibits.
|
|
179
|
+
const MOCK_PRIMER_SECTIONS = [
|
|
180
|
+
{ id: 'heading-foundations', title: 'Foundations', kind: 'heading' as const },
|
|
181
|
+
{ id: 'section-color', title: 'Color', kind: 'display' as const },
|
|
182
|
+
{ id: 'section-type', title: 'Type scale', kind: 'display' as const },
|
|
183
|
+
{ id: 'heading-components', title: 'Components', kind: 'heading' as const },
|
|
184
|
+
{ id: 'section-button', title: 'Button', kind: 'display' as const },
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
// A "Case template" component carrying a tweak schema and a placard-doc, so an
|
|
188
|
+
// exhibit that selects it shows every layout piece at once — stage, tweaks
|
|
189
|
+
// panel, and docs panel. The plain entry in `mockManifest` keeps the nav rail
|
|
190
|
+
// honest; this richer twin (same id) is what the template/page exhibits put on
|
|
191
|
+
// the stage.
|
|
192
|
+
const richCaseComponent: ManifestComponent = mkComponent({
|
|
193
|
+
id: 'case-template',
|
|
194
|
+
name: 'Case template',
|
|
195
|
+
level: 'template',
|
|
196
|
+
placardDoc: 'src/ui/design-system/components/shell/CaseTemplate.placard.md',
|
|
197
|
+
cases: [mkCase('case-template', 'Default', { tweaks: PLACEHOLDER_TWEAKS })],
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
/** Selection override that puts the rich "Case template" exhibit on the stage. */
|
|
201
|
+
export function caseTemplateSelection(): Partial<ShellViewModel> {
|
|
202
|
+
const activeCase = richCaseComponent.cases[0]
|
|
203
|
+
const sel = {
|
|
204
|
+
componentId: richCaseComponent.id,
|
|
205
|
+
caseId: activeCase.id,
|
|
206
|
+
tweaks: {},
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
component: richCaseComponent,
|
|
210
|
+
activeCase,
|
|
211
|
+
sel,
|
|
212
|
+
shownSel: sel,
|
|
213
|
+
expanded: new Set([richCaseComponent.id]),
|
|
214
|
+
addressUrl: `https://display-case.dev${activeCase.renderUrl}?theme=light`,
|
|
215
|
+
docOpen: true,
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Placeholder prose for the docs panel in the Case-template exhibit. */
|
|
220
|
+
export const PLACEHOLDER_DOC = `## Documentation
|
|
221
|
+
|
|
222
|
+
A page's documentation panel renders the component's \`*.placard.md\` here —
|
|
223
|
+
usage notes, examples, and the props an agent needs to use it correctly.
|
|
224
|
+
|
|
225
|
+
- First, the **why**: what this piece is for.
|
|
226
|
+
- Then, the **how**: the props and a worked example.`
|
|
227
|
+
|
|
228
|
+
/** Pick a component + case out of a manifest and the selection that targets it. */
|
|
229
|
+
export function selectIn(
|
|
230
|
+
manifest: Manifest,
|
|
231
|
+
componentId: string,
|
|
232
|
+
caseId?: string,
|
|
233
|
+
) {
|
|
234
|
+
const component =
|
|
235
|
+
manifest.components.find((c) => c.id === componentId) ?? null
|
|
236
|
+
const activeCase =
|
|
237
|
+
component?.cases.find((c) => c.id === caseId) ?? component?.cases[0] ?? null
|
|
238
|
+
const sel =
|
|
239
|
+
component && activeCase
|
|
240
|
+
? { componentId: component.id, caseId: activeCase.id, tweaks: {} }
|
|
241
|
+
: null
|
|
242
|
+
return {
|
|
243
|
+
component,
|
|
244
|
+
activeCase,
|
|
245
|
+
sel,
|
|
246
|
+
shownSel: sel,
|
|
247
|
+
expanded: new Set(component ? [component.id] : []),
|
|
248
|
+
// A fixed origin (not the ephemeral dev-server port) keeps the exhibit's
|
|
249
|
+
// address bar deterministic for visual-regression snapshots.
|
|
250
|
+
addressUrl: activeCase
|
|
251
|
+
? `https://display-case.dev${activeCase.renderUrl}?theme=light`
|
|
252
|
+
: '',
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Real violations taken from an actual `display-case check --a11y` run over
|
|
257
|
+
// Display Case's own TweaksPanel case — so the exhibit reads like a real audit,
|
|
258
|
+
// with axe's real severities, not lorem ipsum.
|
|
259
|
+
const MOCK_VIOLATIONS: A11yViolation[] = [
|
|
260
|
+
{
|
|
261
|
+
id: 'color-contrast',
|
|
262
|
+
help: 'Elements must meet minimum color contrast ratio thresholds',
|
|
263
|
+
nodes: 3,
|
|
264
|
+
impact: 'serious',
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
id: 'label',
|
|
268
|
+
help: 'Form elements must have labels',
|
|
269
|
+
nodes: 1,
|
|
270
|
+
impact: 'critical',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: 'select-name',
|
|
274
|
+
help: 'Select element must have an accessible name',
|
|
275
|
+
nodes: 1,
|
|
276
|
+
impact: 'serious',
|
|
277
|
+
},
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* A static {@link A11ySurface} for the a11y-surfacing exhibit: per-variant nav
|
|
282
|
+
* markers across a few library components (so the rail shows which have issues at
|
|
283
|
+
* a glance) plus the selected variant's violation list (the stage's a11y panel).
|
|
284
|
+
* The selected variant's count lines up with the panel's list, so the nav marker
|
|
285
|
+
* and the panel tell one consistent story.
|
|
286
|
+
*/
|
|
287
|
+
export function mockA11y(): A11ySurface {
|
|
288
|
+
return {
|
|
289
|
+
byVariant: {
|
|
290
|
+
button: { playground: 3 },
|
|
291
|
+
input: { default: 3 },
|
|
292
|
+
'render-address': { default: 1 },
|
|
293
|
+
'tweaks-panel': { docked: 2 },
|
|
294
|
+
},
|
|
295
|
+
current: MOCK_VIOLATIONS,
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// A deliberately long audit — more violations than the height-capped panel can
|
|
300
|
+
// show at once — to exercise its internal scroll (with the sticky header).
|
|
301
|
+
const MANY_VIOLATIONS: A11yViolation[] = [
|
|
302
|
+
{
|
|
303
|
+
id: 'color-contrast',
|
|
304
|
+
help: 'Elements must meet minimum color contrast ratio thresholds',
|
|
305
|
+
nodes: 7,
|
|
306
|
+
impact: 'serious',
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
id: 'label',
|
|
310
|
+
help: 'Form elements must have labels',
|
|
311
|
+
nodes: 4,
|
|
312
|
+
impact: 'critical',
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
id: 'link-name',
|
|
316
|
+
help: 'Links must have discernible text',
|
|
317
|
+
nodes: 3,
|
|
318
|
+
impact: 'serious',
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: 'button-name',
|
|
322
|
+
help: 'Buttons must have discernible text',
|
|
323
|
+
nodes: 2,
|
|
324
|
+
impact: 'critical',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
id: 'image-alt',
|
|
328
|
+
help: 'Images must have alternate text',
|
|
329
|
+
nodes: 5,
|
|
330
|
+
impact: 'critical',
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
id: 'aria-required-attr',
|
|
334
|
+
help: 'Required ARIA attributes must be provided',
|
|
335
|
+
nodes: 1,
|
|
336
|
+
impact: 'critical',
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
id: 'aria-valid-attr-value',
|
|
340
|
+
help: 'ARIA attributes must conform to valid values',
|
|
341
|
+
nodes: 2,
|
|
342
|
+
impact: 'serious',
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
id: 'duplicate-id',
|
|
346
|
+
help: 'id attribute values must be unique',
|
|
347
|
+
nodes: 3,
|
|
348
|
+
impact: 'minor',
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: 'heading-order',
|
|
352
|
+
help: 'Heading levels should only increase by one',
|
|
353
|
+
nodes: 1,
|
|
354
|
+
impact: 'moderate',
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: 'list',
|
|
358
|
+
help: 'Lists must only directly contain li elements',
|
|
359
|
+
nodes: 2,
|
|
360
|
+
impact: 'serious',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
id: 'tabindex',
|
|
364
|
+
help: 'Elements should not have a tabindex greater than zero',
|
|
365
|
+
nodes: 4,
|
|
366
|
+
impact: 'serious',
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
id: 'region',
|
|
370
|
+
help: 'All page content should be contained by landmarks',
|
|
371
|
+
nodes: 6,
|
|
372
|
+
impact: 'moderate',
|
|
373
|
+
},
|
|
374
|
+
]
|
|
375
|
+
|
|
376
|
+
/** Like {@link mockA11y}, but with a violation list long enough to overflow the
|
|
377
|
+
* panel — for the page-case variant that proves the scroll + sticky header. */
|
|
378
|
+
export function mockA11yScrolling(): A11ySurface {
|
|
379
|
+
return {
|
|
380
|
+
byVariant: {
|
|
381
|
+
input: { default: MANY_VIOLATIONS.length },
|
|
382
|
+
'render-address': { default: 1 },
|
|
383
|
+
},
|
|
384
|
+
current: MANY_VIOLATIONS,
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* A static {@link A11ySurface} that shows the per-variant nav breakdown: `button`
|
|
390
|
+
* is selected (and expanded) with its three variants carrying different counts —
|
|
391
|
+
* Playground 2, Variants 5, Sizes clean — so the parent row shows a plain dot
|
|
392
|
+
* while the per-variant numbers sit on the case rows. Other components stay
|
|
393
|
+
* collapsed, showing their summed counts for contrast. The panel lists the
|
|
394
|
+
* selected variant (`button` / Variants → 5 violations).
|
|
395
|
+
*/
|
|
396
|
+
export function mockA11yPerVariant(): A11ySurface {
|
|
397
|
+
return {
|
|
398
|
+
byVariant: {
|
|
399
|
+
button: { playground: 2, variants: 5 },
|
|
400
|
+
input: { default: 3 },
|
|
401
|
+
'render-address': { default: 1 },
|
|
402
|
+
},
|
|
403
|
+
current: MANY_VIOLATIONS.slice(0, 5),
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* A static {@link A11ySurface} for the single-case-leaf situation: `RenderAddress`
|
|
409
|
+
* is a one-variant component, so it renders as a leaf (no chevron, no case rows).
|
|
410
|
+
* With no children to defer to, its lone variant's count sits directly on the
|
|
411
|
+
* leaf row — never a dot. The page case selects it, so the marker shows on the
|
|
412
|
+
* selected (marigold) row. Multi-case `button` stays collapsed for contrast.
|
|
413
|
+
*/
|
|
414
|
+
export function mockA11yLeaf(): A11ySurface {
|
|
415
|
+
return {
|
|
416
|
+
byVariant: {
|
|
417
|
+
button: { playground: 2, variants: 5 },
|
|
418
|
+
input: { default: 3 },
|
|
419
|
+
'render-address': { default: 2 },
|
|
420
|
+
},
|
|
421
|
+
current: MANY_VIOLATIONS.slice(0, 2),
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** A11y configured but the active variant's scan is still in flight: the panel
|
|
426
|
+
* shows its calm "Scanning…" state, and no nav markers have landed yet. */
|
|
427
|
+
export function mockA11yPending(): A11ySurface {
|
|
428
|
+
return { byVariant: {}, current: 'pending' }
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** A11y configured and everything is clean: no nav markers anywhere and the
|
|
432
|
+
* panel shows its reassuring all-green pass state. */
|
|
433
|
+
export function mockA11yClean(): A11ySurface {
|
|
434
|
+
return { byVariant: {}, current: [] }
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Build a complete, static {@link ShellViewModel}. Defaults paint a calm,
|
|
439
|
+
* fully-revealed library view of {@link mockManifest}; pass `overrides` to set
|
|
440
|
+
* the mode, the selected exhibit, the stage geometry, or wire `setMode` to a
|
|
441
|
+
* flow's `goto`. Handlers default to no-ops and the live-frame refs to null —
|
|
442
|
+
* an exhibit drives the stage through the `renderFrame` / `primerFrame` slots,
|
|
443
|
+
* not the iframes.
|
|
444
|
+
*/
|
|
445
|
+
export function makeModel(
|
|
446
|
+
overrides: Partial<ShellViewModel> = {},
|
|
447
|
+
): ShellViewModel {
|
|
448
|
+
const picked = selectIn(mockManifest, 'button', 'playground')
|
|
449
|
+
const base: ShellViewModel = {
|
|
450
|
+
manifest: mockManifest,
|
|
451
|
+
theme: 'light',
|
|
452
|
+
setTheme: noop,
|
|
453
|
+
navCollapsed: false,
|
|
454
|
+
setNavCollapsed: noop,
|
|
455
|
+
mode: 'library',
|
|
456
|
+
setMode: noop,
|
|
457
|
+
shownMode: 'library',
|
|
458
|
+
modeFadeStyle: { opacity: 1 },
|
|
459
|
+
sizeId: 'full',
|
|
460
|
+
setSizeId: noop,
|
|
461
|
+
manualZoom: 1,
|
|
462
|
+
setManualZoom: noop,
|
|
463
|
+
showGrid: true,
|
|
464
|
+
setShowGrid: noop,
|
|
465
|
+
widthInputValue: '',
|
|
466
|
+
fixed: null,
|
|
467
|
+
fitted: false,
|
|
468
|
+
scale: 1,
|
|
469
|
+
sizeMeta: 'Responsive',
|
|
470
|
+
editDim: noop,
|
|
471
|
+
rotateDims: noop,
|
|
472
|
+
stageDecor: true,
|
|
473
|
+
component: picked.component,
|
|
474
|
+
activeCase: picked.activeCase,
|
|
475
|
+
addressUrl: picked.addressUrl,
|
|
476
|
+
shownSel: picked.shownSel,
|
|
477
|
+
sel: picked.sel,
|
|
478
|
+
docOpen: false,
|
|
479
|
+
changeDocsOpen: noop,
|
|
480
|
+
docText: null,
|
|
481
|
+
docWidth: 352,
|
|
482
|
+
startDocResize: noop,
|
|
483
|
+
onDocResizeKey: noop,
|
|
484
|
+
tweaksFloating: false,
|
|
485
|
+
setTweaksFloating: noop,
|
|
486
|
+
navScrollRef: nullRef,
|
|
487
|
+
navBodyRef: nullRef,
|
|
488
|
+
groups: groupByLevel(mockManifest.components),
|
|
489
|
+
expanded: picked.expanded,
|
|
490
|
+
toggleExpanded: noop,
|
|
491
|
+
selectComponent: noop,
|
|
492
|
+
select: noop,
|
|
493
|
+
primerGroups: groupPrimerSections(MOCK_PRIMER_SECTIONS),
|
|
494
|
+
primerActive: MOCK_PRIMER_SECTIONS[0].id,
|
|
495
|
+
// Accordion: one TOC group open at a time, tracking the active section
|
|
496
|
+
// (see useShell — the scrollspy effect that drives primerExpanded).
|
|
497
|
+
primerExpanded: new Set(['heading-foundations']),
|
|
498
|
+
togglePrimerGroup: noop,
|
|
499
|
+
scrollToSection: noop,
|
|
500
|
+
attachPreview: noop,
|
|
501
|
+
padX: 32,
|
|
502
|
+
padY: 32,
|
|
503
|
+
stageShown: true,
|
|
504
|
+
boxW: 320,
|
|
505
|
+
boxH: 200,
|
|
506
|
+
frameRef: nullRef,
|
|
507
|
+
frameSrc: null,
|
|
508
|
+
targetW: 320,
|
|
509
|
+
renderH: 200,
|
|
510
|
+
primerRef: nullRef,
|
|
511
|
+
primerSrc: null,
|
|
512
|
+
}
|
|
513
|
+
return { ...base, ...overrides }
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/** A dashed placeholder standing in for a component on the stage (templates). */
|
|
517
|
+
export function PlaceholderExhibit({
|
|
518
|
+
label = 'Component',
|
|
519
|
+
}: {
|
|
520
|
+
label?: string
|
|
521
|
+
}): ReactNode {
|
|
522
|
+
return (
|
|
523
|
+
<div
|
|
524
|
+
style={{
|
|
525
|
+
display: 'grid',
|
|
526
|
+
placeItems: 'center',
|
|
527
|
+
width: '100%',
|
|
528
|
+
height: '100%',
|
|
529
|
+
minHeight: '120px',
|
|
530
|
+
minWidth: '180px',
|
|
531
|
+
border: '1px dashed var(--dc-border)',
|
|
532
|
+
borderRadius: 'var(--dc-radius-md)',
|
|
533
|
+
color: 'var(--dc-fg-subtle)',
|
|
534
|
+
fontFamily: 'var(--dc-font-mono)',
|
|
535
|
+
fontSize: 'var(--dc-text-sm)',
|
|
536
|
+
}}>
|
|
537
|
+
{label}
|
|
538
|
+
</div>
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/** Center a live exhibit inside the stage's frame box (pages). */
|
|
543
|
+
export function StageSlot({ children }: { children: ReactNode }): ReactNode {
|
|
544
|
+
return (
|
|
545
|
+
<div
|
|
546
|
+
style={{
|
|
547
|
+
display: 'grid',
|
|
548
|
+
placeItems: 'center',
|
|
549
|
+
width: '100%',
|
|
550
|
+
height: '100%',
|
|
551
|
+
}}>
|
|
552
|
+
{children}
|
|
553
|
+
</div>
|
|
554
|
+
)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* A full-bleed app screen for the Cases view's "Page" exhibit. A page-level
|
|
559
|
+
* component flips `stageDecor` off, so the stage drops its grid and padding and
|
|
560
|
+
* the exhibit fills the frame edge to edge — this screen shows that fill: a top
|
|
561
|
+
* bar and a body that reach the borders, no centred vitrine.
|
|
562
|
+
*/
|
|
563
|
+
export function PageScreen(): ReactNode {
|
|
564
|
+
return (
|
|
565
|
+
<div
|
|
566
|
+
style={{
|
|
567
|
+
display: 'flex',
|
|
568
|
+
flexDirection: 'column',
|
|
569
|
+
width: '100%',
|
|
570
|
+
height: '100%',
|
|
571
|
+
background: 'var(--dc-bg)',
|
|
572
|
+
color: 'var(--dc-fg)',
|
|
573
|
+
fontFamily: 'var(--dc-font-sans)',
|
|
574
|
+
fontSize: 'var(--dc-text-sm)',
|
|
575
|
+
}}>
|
|
576
|
+
<div
|
|
577
|
+
style={{
|
|
578
|
+
display: 'flex',
|
|
579
|
+
alignItems: 'center',
|
|
580
|
+
gap: 'var(--dc-space-3)',
|
|
581
|
+
padding: 'var(--dc-space-3) var(--dc-space-4)',
|
|
582
|
+
borderBottom: '1px solid var(--dc-border)',
|
|
583
|
+
}}>
|
|
584
|
+
<strong>Acme</strong>
|
|
585
|
+
<span style={{ marginLeft: 'auto', color: 'var(--dc-fg-muted)' }}>
|
|
586
|
+
Dashboard
|
|
587
|
+
</span>
|
|
588
|
+
<Chip variant="accent">Live</Chip>
|
|
589
|
+
</div>
|
|
590
|
+
<div
|
|
591
|
+
style={{
|
|
592
|
+
flex: 1,
|
|
593
|
+
display: 'flex',
|
|
594
|
+
flexDirection: 'column',
|
|
595
|
+
gap: 'var(--dc-space-3)',
|
|
596
|
+
padding: 'var(--dc-space-4)',
|
|
597
|
+
}}>
|
|
598
|
+
<div
|
|
599
|
+
style={{
|
|
600
|
+
height: '0.9rem',
|
|
601
|
+
width: '55%',
|
|
602
|
+
borderRadius: 'var(--dc-radius-sm)',
|
|
603
|
+
background: 'var(--dc-bg-subtle)',
|
|
604
|
+
}}
|
|
605
|
+
/>
|
|
606
|
+
<div
|
|
607
|
+
style={{
|
|
608
|
+
flex: 1,
|
|
609
|
+
borderRadius: 'var(--dc-radius-md)',
|
|
610
|
+
border: '1px solid var(--dc-border)',
|
|
611
|
+
background: 'var(--dc-surface)',
|
|
612
|
+
}}
|
|
613
|
+
/>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* A single flow step for the Cases view's "Flow" exhibit. A flow component shows
|
|
621
|
+
* the FlowNav stepper above the stage and fills it edge to edge; this centred
|
|
622
|
+
* step card is what one stop in that sequence looks like.
|
|
623
|
+
*/
|
|
624
|
+
export function FlowStep(): ReactNode {
|
|
625
|
+
return (
|
|
626
|
+
<div
|
|
627
|
+
style={{
|
|
628
|
+
display: 'grid',
|
|
629
|
+
placeItems: 'center',
|
|
630
|
+
width: '100%',
|
|
631
|
+
height: '100%',
|
|
632
|
+
background: 'var(--dc-bg)',
|
|
633
|
+
}}>
|
|
634
|
+
<div
|
|
635
|
+
style={{
|
|
636
|
+
display: 'flex',
|
|
637
|
+
flexDirection: 'column',
|
|
638
|
+
gap: 'var(--dc-space-3)',
|
|
639
|
+
width: '220px',
|
|
640
|
+
padding: 'var(--dc-space-6)',
|
|
641
|
+
border: '1px solid var(--dc-border)',
|
|
642
|
+
borderRadius: 'var(--dc-radius-md)',
|
|
643
|
+
background: 'var(--dc-surface)',
|
|
644
|
+
fontFamily: 'var(--dc-font-sans)',
|
|
645
|
+
}}>
|
|
646
|
+
<span
|
|
647
|
+
style={{
|
|
648
|
+
fontSize: 'var(--dc-text-sm)',
|
|
649
|
+
color: 'var(--dc-fg-muted)',
|
|
650
|
+
}}>
|
|
651
|
+
Step 1 of 3
|
|
652
|
+
</span>
|
|
653
|
+
<strong>Request a sign-in link</strong>
|
|
654
|
+
<Button variant="accent">Send magic link</Button>
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
)
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/** A faithful Primer reading page — real prose and live {@link Display}
|
|
661
|
+
* specimens — for the Primer *page* exhibit (vs the skeleton template). */
|
|
662
|
+
export function RealPrimer(): ReactNode {
|
|
663
|
+
return (
|
|
664
|
+
<div className="dc-primer">
|
|
665
|
+
<div className="dc-primer-inner">
|
|
666
|
+
<h1>Display Case</h1>
|
|
667
|
+
<p>
|
|
668
|
+
The Primer is long-form wall text: a reading page that orients you in
|
|
669
|
+
a design system before you browse its cases, with live specimens
|
|
670
|
+
embedded inline.
|
|
671
|
+
</p>
|
|
672
|
+
<h2>Components</h2>
|
|
673
|
+
<Display title="Button" subtitle="The quiet bordered control">
|
|
674
|
+
<Button>Save changes</Button>
|
|
675
|
+
<Button variant="accent">Publish</Button>
|
|
676
|
+
<Button variant="ghost">Cancel</Button>
|
|
677
|
+
</Display>
|
|
678
|
+
<Display title="Chip" subtitle="A small status pill">
|
|
679
|
+
<Chip>Default</Chip>
|
|
680
|
+
<Chip variant="accent">Accent</Chip>
|
|
681
|
+
<Chip variant="solid">Solid</Chip>
|
|
682
|
+
</Display>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
)
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/** A skeleton standing in for the Primer reading page (Primer template). */
|
|
689
|
+
export function PlaceholderPrimer(): ReactNode {
|
|
690
|
+
const line = (w: string, h = '0.9rem') => (
|
|
691
|
+
<div
|
|
692
|
+
style={{
|
|
693
|
+
width: w,
|
|
694
|
+
height: h,
|
|
695
|
+
marginBottom: '1rem',
|
|
696
|
+
borderRadius: 'var(--dc-radius-sm)',
|
|
697
|
+
background: 'var(--dc-bg-subtle)',
|
|
698
|
+
border: '1px solid var(--dc-border)',
|
|
699
|
+
}}
|
|
700
|
+
/>
|
|
701
|
+
)
|
|
702
|
+
return (
|
|
703
|
+
<div className="dc-primer">
|
|
704
|
+
{/* The plain block `.dc-primer-inner`. The bars use absolute widths (not
|
|
705
|
+
percentages) so the inner takes its width from them — a primer of only
|
|
706
|
+
percentage-width boxes has no intrinsic width and would collapse. */}
|
|
707
|
+
<div className="dc-primer-inner">
|
|
708
|
+
{line('14rem', '1.6rem')}
|
|
709
|
+
{line('34rem')}
|
|
710
|
+
{line('31rem')}
|
|
711
|
+
{line('24rem')}
|
|
712
|
+
<div
|
|
713
|
+
style={{
|
|
714
|
+
width: '34rem',
|
|
715
|
+
maxWidth: '100%',
|
|
716
|
+
height: '8rem',
|
|
717
|
+
marginBottom: '1rem',
|
|
718
|
+
borderRadius: 'var(--dc-radius-md)',
|
|
719
|
+
border: '1px dashed var(--dc-border)',
|
|
720
|
+
}}
|
|
721
|
+
/>
|
|
722
|
+
{line('100%')}
|
|
723
|
+
{line('84%')}
|
|
724
|
+
</div>
|
|
725
|
+
</div>
|
|
726
|
+
)
|
|
727
|
+
}
|