@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.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +309 -0
  3. package/display-case.prompt.md +64 -0
  4. package/docs/ai-agents.md +126 -0
  5. package/docs/cli.md +99 -0
  6. package/docs/configuration.md +410 -0
  7. package/docs/documentation-panel.md +50 -0
  8. package/docs/examples/README.md +14 -0
  9. package/docs/examples/multi-variant.case.tsx +30 -0
  10. package/docs/examples/plain.case.tsx +22 -0
  11. package/docs/examples/tweak-control.placard.md +80 -0
  12. package/docs/examples/tweaks.case.tsx +39 -0
  13. package/docs/hierarchy.md +59 -0
  14. package/docs/quick-start.md +78 -0
  15. package/docs/style-engines.md +180 -0
  16. package/docs/testing.md +245 -0
  17. package/docs/theming.md +97 -0
  18. package/docs/tweaks.md +75 -0
  19. package/docs/writing-cases.md +144 -0
  20. package/docs/writing-placard-docs.md +194 -0
  21. package/package.json +113 -0
  22. package/skills/display-case-author-case/README.md +20 -0
  23. package/skills/display-case-author-case/SKILL.md +40 -0
  24. package/skills/display-case-author-placard-doc/README.md +24 -0
  25. package/skills/display-case-author-placard-doc/SKILL.md +65 -0
  26. package/skills/display-case-review/README.md +19 -0
  27. package/skills/display-case-review/SKILL.md +30 -0
  28. package/skills/display-case-snapshot/README.md +20 -0
  29. package/skills/display-case-snapshot/SKILL.md +29 -0
  30. package/src/checks/a11y-scanner.test.ts +240 -0
  31. package/src/checks/a11y-scanner.ts +410 -0
  32. package/src/checks/check-text.test.ts +53 -0
  33. package/src/checks/check-text.ts +78 -0
  34. package/src/checks/check.test.ts +194 -0
  35. package/src/checks/check.ts +473 -0
  36. package/src/checks/providers/pixelmatch-diff.test.ts +79 -0
  37. package/src/checks/providers/pixelmatch-diff.ts +30 -0
  38. package/src/checks/providers/playwright-driver.ts +104 -0
  39. package/src/checks/ssr-check.test.ts +73 -0
  40. package/src/checks/ssr-check.ts +96 -0
  41. package/src/checks/structure-check.cross-package.test.ts +165 -0
  42. package/src/checks/structure-check.test.ts +651 -0
  43. package/src/checks/structure-check.ts +988 -0
  44. package/src/checks/tokens-check.test.ts +159 -0
  45. package/src/checks/tokens-check.ts +162 -0
  46. package/src/cli.ts +218 -0
  47. package/src/commands/agents.test.ts +24 -0
  48. package/src/commands/agents.ts +28 -0
  49. package/src/commands/init-run.test.ts +123 -0
  50. package/src/commands/init.test.ts +63 -0
  51. package/src/commands/init.ts +412 -0
  52. package/src/commands/publish.test.ts +210 -0
  53. package/src/commands/publish.ts +292 -0
  54. package/src/core/affected.test.ts +99 -0
  55. package/src/core/affected.ts +144 -0
  56. package/src/core/catalog.test.ts +152 -0
  57. package/src/core/catalog.ts +92 -0
  58. package/src/core/discovery.test.ts +184 -0
  59. package/src/core/discovery.ts +250 -0
  60. package/src/core/manifest.ts +41 -0
  61. package/src/core/mdx-lite/__fixtures__/box-stub.tsx +7 -0
  62. package/src/core/mdx-lite/index.ts +393 -0
  63. package/src/core/mdx-lite/mdx-lite.test.ts +345 -0
  64. package/src/core/mdx-plugin.test.ts +60 -0
  65. package/src/core/mdx-plugin.ts +30 -0
  66. package/src/flow-step.test-d.ts +39 -0
  67. package/src/index.test.ts +100 -0
  68. package/src/index.ts +564 -0
  69. package/src/render/collect-styles.emotion.test.tsx +114 -0
  70. package/src/render/collect-styles.test.tsx +72 -0
  71. package/src/render/collect-styles.ts +33 -0
  72. package/src/render/documents.test.ts +184 -0
  73. package/src/render/documents.ts +88 -0
  74. package/src/render/render-node.test.tsx +160 -0
  75. package/src/render/render-node.tsx +133 -0
  76. package/src/render/ssr-primer.test.tsx +25 -0
  77. package/src/render/ssr-primer.tsx +54 -0
  78. package/src/render/ssr-render.test.tsx +142 -0
  79. package/src/render/ssr-render.tsx +63 -0
  80. package/src/render/ssr-shell.test.tsx +57 -0
  81. package/src/render/ssr-shell.tsx +54 -0
  82. package/src/server/prod-server.ts +237 -0
  83. package/src/server/server.test.ts +117 -0
  84. package/src/server/server.ts +1039 -0
  85. package/src/style-engine.test-d.ts +37 -0
  86. package/src/testing/test-helpers.ts +27 -0
  87. package/src/types/pixelmatch.d.ts +12 -0
  88. package/src/ui/browser-entry.tsx +51 -0
  89. package/src/ui/chrome.css +485 -0
  90. package/src/ui/design-system/README.md +88 -0
  91. package/src/ui/design-system/components/controls/Button.case.tsx +52 -0
  92. package/src/ui/design-system/components/controls/Button.css +89 -0
  93. package/src/ui/design-system/components/controls/Button.placard.md +14 -0
  94. package/src/ui/design-system/components/controls/Button.test.tsx +45 -0
  95. package/src/ui/design-system/components/controls/Button.tsx +41 -0
  96. package/src/ui/design-system/components/controls/IconButton.case.tsx +52 -0
  97. package/src/ui/design-system/components/controls/IconButton.css +67 -0
  98. package/src/ui/design-system/components/controls/IconButton.placard.md +13 -0
  99. package/src/ui/design-system/components/controls/IconButton.test.tsx +39 -0
  100. package/src/ui/design-system/components/controls/IconButton.tsx +47 -0
  101. package/src/ui/design-system/components/controls/Input.case.tsx +50 -0
  102. package/src/ui/design-system/components/controls/Input.css +52 -0
  103. package/src/ui/design-system/components/controls/Input.placard.md +12 -0
  104. package/src/ui/design-system/components/controls/Input.test.tsx +43 -0
  105. package/src/ui/design-system/components/controls/Input.tsx +45 -0
  106. package/src/ui/design-system/components/controls/Select.case.tsx +48 -0
  107. package/src/ui/design-system/components/controls/Select.css +44 -0
  108. package/src/ui/design-system/components/controls/Select.placard.md +15 -0
  109. package/src/ui/design-system/components/controls/Select.test.tsx +57 -0
  110. package/src/ui/design-system/components/controls/Select.tsx +58 -0
  111. package/src/ui/design-system/components/controls/SelectMenu.case.tsx +100 -0
  112. package/src/ui/design-system/components/controls/SelectMenu.css +72 -0
  113. package/src/ui/design-system/components/controls/SelectMenu.placard.md +18 -0
  114. package/src/ui/design-system/components/controls/SelectMenu.test.tsx +66 -0
  115. package/src/ui/design-system/components/controls/SelectMenu.tsx +377 -0
  116. package/src/ui/design-system/components/index.ts +66 -0
  117. package/src/ui/design-system/components/primer-specimen/ColorRamp.case.tsx +44 -0
  118. package/src/ui/design-system/components/primer-specimen/ColorRamp.placard.md +15 -0
  119. package/src/ui/design-system/components/primer-specimen/ColorRamp.tsx +51 -0
  120. package/src/ui/design-system/components/primer-specimen/DefinitionList.case.tsx +38 -0
  121. package/src/ui/design-system/components/primer-specimen/DefinitionList.placard.md +15 -0
  122. package/src/ui/design-system/components/primer-specimen/DefinitionList.tsx +41 -0
  123. package/src/ui/design-system/components/primer-specimen/FontFamilies.case.tsx +24 -0
  124. package/src/ui/design-system/components/primer-specimen/FontFamilies.placard.md +12 -0
  125. package/src/ui/design-system/components/primer-specimen/FontFamilies.tsx +41 -0
  126. package/src/ui/design-system/components/primer-specimen/GlyphGrid.case.tsx +27 -0
  127. package/src/ui/design-system/components/primer-specimen/GlyphGrid.placard.md +13 -0
  128. package/src/ui/design-system/components/primer-specimen/GlyphGrid.tsx +34 -0
  129. package/src/ui/design-system/components/primer-specimen/LayoutMock.case.tsx +36 -0
  130. package/src/ui/design-system/components/primer-specimen/LayoutMock.placard.md +7 -0
  131. package/src/ui/design-system/components/primer-specimen/LayoutMock.tsx +36 -0
  132. package/src/ui/design-system/components/primer-specimen/SpacingScale.case.tsx +20 -0
  133. package/src/ui/design-system/components/primer-specimen/SpacingScale.placard.md +12 -0
  134. package/src/ui/design-system/components/primer-specimen/SpacingScale.tsx +33 -0
  135. package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.case.tsx +56 -0
  136. package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.placard.md +17 -0
  137. package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.tsx +45 -0
  138. package/src/ui/design-system/components/primer-specimen/StatusList.case.tsx +17 -0
  139. package/src/ui/design-system/components/primer-specimen/StatusList.placard.md +16 -0
  140. package/src/ui/design-system/components/primer-specimen/StatusList.tsx +39 -0
  141. package/src/ui/design-system/components/primer-specimen/SwatchGrid.case.tsx +26 -0
  142. package/src/ui/design-system/components/primer-specimen/SwatchGrid.placard.md +15 -0
  143. package/src/ui/design-system/components/primer-specimen/SwatchGrid.tsx +42 -0
  144. package/src/ui/design-system/components/primer-specimen/TypeScale.case.tsx +23 -0
  145. package/src/ui/design-system/components/primer-specimen/TypeScale.placard.md +14 -0
  146. package/src/ui/design-system/components/primer-specimen/TypeScale.tsx +34 -0
  147. package/src/ui/design-system/components/primer-specimen/WeightSpecimen.case.tsx +28 -0
  148. package/src/ui/design-system/components/primer-specimen/WeightSpecimen.placard.md +15 -0
  149. package/src/ui/design-system/components/primer-specimen/WeightSpecimen.tsx +46 -0
  150. package/src/ui/design-system/components/primer-specimen/index.ts +31 -0
  151. package/src/ui/design-system/components/primer-specimen/styles.css +476 -0
  152. package/src/ui/design-system/components/shell/A11yPage.case.tsx +237 -0
  153. package/src/ui/design-system/components/shell/A11yPage.placard.md +15 -0
  154. package/src/ui/design-system/components/shell/CaseTemplate.case.tsx +32 -0
  155. package/src/ui/design-system/components/shell/CaseTemplate.placard.md +5 -0
  156. package/src/ui/design-system/components/shell/CasesPage.case.tsx +141 -0
  157. package/src/ui/design-system/components/shell/CasesPage.placard.md +12 -0
  158. package/src/ui/design-system/components/shell/PrimerPage.case.tsx +22 -0
  159. package/src/ui/design-system/components/shell/PrimerPage.placard.md +3 -0
  160. package/src/ui/design-system/components/shell/PrimerTemplate.case.tsx +22 -0
  161. package/src/ui/design-system/components/shell/PrimerTemplate.placard.md +5 -0
  162. package/src/ui/design-system/components/shell/ShellView.case.tsx +57 -0
  163. package/src/ui/design-system/components/shell/ShellView.placard.md +5 -0
  164. package/src/ui/design-system/components/shell/ShellView.tsx +678 -0
  165. package/src/ui/design-system/components/shell/shell-fixtures.tsx +727 -0
  166. package/src/ui/design-system/components/showcase/A11yBadge.case.tsx +46 -0
  167. package/src/ui/design-system/components/showcase/A11yBadge.css +27 -0
  168. package/src/ui/design-system/components/showcase/A11yBadge.placard.md +11 -0
  169. package/src/ui/design-system/components/showcase/A11yBadge.test.tsx +31 -0
  170. package/src/ui/design-system/components/showcase/A11yBadge.tsx +41 -0
  171. package/src/ui/design-system/components/showcase/A11yPanel.case.tsx +121 -0
  172. package/src/ui/design-system/components/showcase/A11yPanel.css +198 -0
  173. package/src/ui/design-system/components/showcase/A11yPanel.placard.md +19 -0
  174. package/src/ui/design-system/components/showcase/A11yPanel.test.tsx +81 -0
  175. package/src/ui/design-system/components/showcase/A11yPanel.tsx +144 -0
  176. package/src/ui/design-system/components/showcase/Chip.case.tsx +48 -0
  177. package/src/ui/design-system/components/showcase/Chip.css +51 -0
  178. package/src/ui/design-system/components/showcase/Chip.placard.md +13 -0
  179. package/src/ui/design-system/components/showcase/Chip.test.tsx +46 -0
  180. package/src/ui/design-system/components/showcase/Chip.tsx +54 -0
  181. package/src/ui/design-system/components/showcase/Eyebrow.case.tsx +30 -0
  182. package/src/ui/design-system/components/showcase/Eyebrow.css +16 -0
  183. package/src/ui/design-system/components/showcase/Eyebrow.placard.md +10 -0
  184. package/src/ui/design-system/components/showcase/Eyebrow.test.tsx +38 -0
  185. package/src/ui/design-system/components/showcase/Eyebrow.tsx +29 -0
  186. package/src/ui/design-system/components/showcase/FlowNav.case.tsx +35 -0
  187. package/src/ui/design-system/components/showcase/FlowNav.css +29 -0
  188. package/src/ui/design-system/components/showcase/FlowNav.placard.md +13 -0
  189. package/src/ui/design-system/components/showcase/FlowNav.test.tsx +48 -0
  190. package/src/ui/design-system/components/showcase/FlowNav.tsx +58 -0
  191. package/src/ui/design-system/components/showcase/ImpactTag.case.tsx +19 -0
  192. package/src/ui/design-system/components/showcase/ImpactTag.css +36 -0
  193. package/src/ui/design-system/components/showcase/ImpactTag.placard.md +14 -0
  194. package/src/ui/design-system/components/showcase/ImpactTag.test.tsx +40 -0
  195. package/src/ui/design-system/components/showcase/ImpactTag.tsx +35 -0
  196. package/src/ui/design-system/components/showcase/NavItem.case.tsx +86 -0
  197. package/src/ui/design-system/components/showcase/NavItem.css +111 -0
  198. package/src/ui/design-system/components/showcase/NavItem.placard.md +13 -0
  199. package/src/ui/design-system/components/showcase/NavItem.test.tsx +65 -0
  200. package/src/ui/design-system/components/showcase/NavItem.tsx +95 -0
  201. package/src/ui/design-system/components/showcase/RenderAddress.case.tsx +21 -0
  202. package/src/ui/design-system/components/showcase/RenderAddress.css +35 -0
  203. package/src/ui/design-system/components/showcase/RenderAddress.placard.md +7 -0
  204. package/src/ui/design-system/components/showcase/RenderAddress.test.tsx +26 -0
  205. package/src/ui/design-system/components/showcase/RenderAddress.tsx +43 -0
  206. package/src/ui/design-system/components/showcase/SegmentedToggle.case.tsx +84 -0
  207. package/src/ui/design-system/components/showcase/SegmentedToggle.css +61 -0
  208. package/src/ui/design-system/components/showcase/SegmentedToggle.placard.md +21 -0
  209. package/src/ui/design-system/components/showcase/SegmentedToggle.test.tsx +81 -0
  210. package/src/ui/design-system/components/showcase/SegmentedToggle.tsx +75 -0
  211. package/src/ui/design-system/components/showcase/Sidebar.case.tsx +67 -0
  212. package/src/ui/design-system/components/showcase/Sidebar.css +6 -0
  213. package/src/ui/design-system/components/showcase/Sidebar.placard.md +14 -0
  214. package/src/ui/design-system/components/showcase/Sidebar.test.tsx +32 -0
  215. package/src/ui/design-system/components/showcase/Sidebar.tsx +30 -0
  216. package/src/ui/design-system/components/showcase/Stage.case.tsx +51 -0
  217. package/src/ui/design-system/components/showcase/Stage.css +91 -0
  218. package/src/ui/design-system/components/showcase/Stage.placard.md +15 -0
  219. package/src/ui/design-system/components/showcase/Stage.test.tsx +84 -0
  220. package/src/ui/design-system/components/showcase/Stage.tsx +97 -0
  221. package/src/ui/design-system/components/showcase/TweaksPanel.case.tsx +81 -0
  222. package/src/ui/design-system/components/showcase/TweaksPanel.css +169 -0
  223. package/src/ui/design-system/components/showcase/TweaksPanel.placard.md +20 -0
  224. package/src/ui/design-system/components/showcase/TweaksPanel.tsx +230 -0
  225. package/src/ui/design-system/components/showcase/Wordmark.case.tsx +42 -0
  226. package/src/ui/design-system/components/showcase/Wordmark.css +31 -0
  227. package/src/ui/design-system/components/showcase/Wordmark.placard.md +10 -0
  228. package/src/ui/design-system/components/showcase/Wordmark.test.tsx +22 -0
  229. package/src/ui/design-system/components/showcase/Wordmark.tsx +22 -0
  230. package/src/ui/design-system/primer-specimens/brand.tsx +26 -0
  231. package/src/ui/design-system/primer-specimens/colors.tsx +83 -0
  232. package/src/ui/design-system/primer-specimens/components.tsx +308 -0
  233. package/src/ui/design-system/primer-specimens/foundations.tsx +71 -0
  234. package/src/ui/design-system/primer-specimens/index.ts +25 -0
  235. package/src/ui/design-system/primer-specimens/showcase.tsx +68 -0
  236. package/src/ui/design-system/primer-specimens/spacing.tsx +101 -0
  237. package/src/ui/design-system/primer-specimens/type.tsx +75 -0
  238. package/src/ui/design-system/primer.mdx +236 -0
  239. package/src/ui/design-system/styles.css +14 -0
  240. package/src/ui/design-system/tokens/colors.css +172 -0
  241. package/src/ui/design-system/tokens/fonts.css +18 -0
  242. package/src/ui/design-system/tokens/spacing.css +48 -0
  243. package/src/ui/design-system/tokens/typography.css +49 -0
  244. package/src/ui/markdown.test.tsx +54 -0
  245. package/src/ui/markdown.tsx +19 -0
  246. package/src/ui/primer-mount.tsx +76 -0
  247. package/src/ui/primer.css +175 -0
  248. package/src/ui/primer.tsx +277 -0
  249. package/src/ui/render-mount.tsx +284 -0
  250. package/src/ui/shell-core.test.ts +340 -0
  251. package/src/ui/shell-core.ts +295 -0
  252. package/src/ui/shell.tsx +60 -0
  253. package/src/ui/test-ids.ts +53 -0
  254. package/src/ui/use-shell.ts +1230 -0
@@ -0,0 +1,42 @@
1
+ import { defineCases, tweak } from '@awarebydefault/display-case'
2
+ import { Wordmark } from './Wordmark'
3
+
4
+ export default defineCases(
5
+ 'Wordmark',
6
+ {
7
+ Playground: {
8
+ tweaks: {
9
+ text: tweak.text('Display Case'),
10
+ fontSize: tweak.number(1.5),
11
+ maxWidth: tweak.number(0),
12
+ },
13
+ render: (t) => (
14
+ <Wordmark
15
+ style={{
16
+ fontSize: `${t.fontSize}rem`,
17
+ maxWidth: t.maxWidth ? `${t.maxWidth}rem` : undefined,
18
+ }}>
19
+ {t.text}
20
+ </Wordmark>
21
+ ),
22
+ },
23
+ Default: () => (
24
+ <Wordmark style={{ fontSize: '1.5rem' }}>Display Case</Wordmark>
25
+ ),
26
+ Sizes: () => (
27
+ <div style={{ display: 'flex', alignItems: 'flex-start', gap: 24 }}>
28
+ <Wordmark style={{ fontSize: '0.875rem' }}>Small</Wordmark>
29
+ <Wordmark style={{ fontSize: '1.25rem' }}>Medium</Wordmark>
30
+ <Wordmark style={{ fontSize: '2rem' }}>Large</Wordmark>
31
+ </div>
32
+ ),
33
+ // The brackets stay pinned to the ends and stretch to the full text height
34
+ // as the text wraps inside them — they never wrap along with it.
35
+ Wrapping: () => (
36
+ <Wordmark style={{ fontSize: '1.5rem', maxWidth: '6rem' }}>
37
+ Display Case
38
+ </Wordmark>
39
+ ),
40
+ },
41
+ { level: 'atom' },
42
+ )
@@ -0,0 +1,31 @@
1
+ .dcui-wordmark {
2
+ display: inline-flex;
3
+ align-items: stretch;
4
+ gap: 0.4em;
5
+ font-weight: var(--dc-weight-semibold);
6
+ letter-spacing: var(--dc-tracking-tight);
7
+ line-height: 1.25;
8
+ min-width: 0;
9
+ }
10
+ .dcui-wordmark-text {
11
+ min-width: 0;
12
+ overflow-wrap: break-word;
13
+ text-align: center;
14
+ }
15
+ .dcui-wordmark::before,
16
+ .dcui-wordmark::after {
17
+ content: "";
18
+ flex: 0 0 auto;
19
+ align-self: stretch;
20
+ width: 0.3em;
21
+ /* Stroke scales sub-linearly with the text: the em term lets it thicken gently
22
+ as the text grows (not 1:1 with font-size, which gets heavy at large sizes),
23
+ while the 2px floor keeps it from ever going thinner than the base hairline. */
24
+ border: max(2px, calc(1.25px + 0.05em)) solid var(--dc-brand);
25
+ }
26
+ .dcui-wordmark::before {
27
+ border-right: 0;
28
+ }
29
+ .dcui-wordmark::after {
30
+ border-left: 0;
31
+ }
@@ -0,0 +1,10 @@
1
+ **Wordmark** — the bracketed wordmark, Display Case's own title; reach for it as the brand title, not as decoration.
2
+
3
+ ```tsx
4
+ <Wordmark style={{ fontSize: '1.5rem' }}>Display Case</Wordmark>
5
+ ```
6
+
7
+ The text wraps inside a pair of marigold brackets and the whole mark scales with `font-size` on the element.
8
+
9
+ - **children**: the wordmark text
10
+ - spreads remaining props onto the `<span>`
@@ -0,0 +1,22 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+ import { Wordmark } from './Wordmark'
4
+
5
+ describe('Wordmark', () => {
6
+ test('wraps the text in the bracketed wordmark shell', () => {
7
+ const html = renderToStaticMarkup(<Wordmark>Display Case</Wordmark>)
8
+ expect(html).toContain('class="dcui-wordmark"')
9
+ expect(html).toContain('class="dcui-wordmark-text"')
10
+ expect(html).toContain('Display Case')
11
+ })
12
+
13
+ test('forwards arbitrary attributes to the root element', () => {
14
+ const html = renderToStaticMarkup(
15
+ <Wordmark id="brand" title="Display Case">
16
+ DC
17
+ </Wordmark>,
18
+ )
19
+ expect(html).toContain('id="brand"')
20
+ expect(html).toContain('title="Display Case"')
21
+ })
22
+ })
@@ -0,0 +1,22 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react'
2
+
3
+ /**
4
+ * Display Case — Wordmark
5
+ * The bracketed wordmark. The text wraps *inside* a pair of marigold brackets
6
+ * drawn with borders (not glyphs) as flex items pinned to the ends, so they stay
7
+ * put instead of wrapping with the text and stretch vertically to the full text
8
+ * height — one line or many. Scales with `font-size` (everything is em-based).
9
+ * Display Case's own title and the charm of the identity — never decoration.
10
+ */
11
+
12
+ export interface WordmarkProps extends HTMLAttributes<HTMLElement> {
13
+ children?: ReactNode
14
+ }
15
+
16
+ export function Wordmark({ children, ...rest }: WordmarkProps) {
17
+ return (
18
+ <span className="dcui-wordmark" {...rest}>
19
+ <span className="dcui-wordmark-text">{children}</span>
20
+ </span>
21
+ )
22
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Brand specimen for Display Case's own Primer — the icon vocabulary. Display
3
+ * Case has no icon font, no SVG set, and no emoji: its entire vocabulary is
4
+ * Unicode glyphs rendered in the UI font.
5
+ *
6
+ * A thin, document-specific wrapper: the glyph data lives here; the reusable
7
+ * {@link GlyphGrid} primitive (under `components/primer-specimen/`) renders it.
8
+ */
9
+ import { GlyphGrid, type GlyphSpec } from '../components/primer-specimen'
10
+
11
+ const GLYPHS: GlyphSpec[] = [
12
+ { glyph: '☰', use: 'Toggle nav' },
13
+ { glyph: '▸', use: 'Disclosure' },
14
+ { glyph: '⟲', use: 'Rotate' },
15
+ { glyph: '✕', use: 'Close' },
16
+ { glyph: '★', use: 'Emphasis' },
17
+ { glyph: '←', use: 'Prev' },
18
+ { glyph: '→', use: 'Next' },
19
+ { glyph: '−', use: 'Zoom out' },
20
+ { glyph: '+', use: 'Zoom in' },
21
+ { glyph: '×', use: 'Dimension' },
22
+ ]
23
+
24
+ export function Glyphs() {
25
+ return <GlyphGrid glyphs={GLYPHS} columns={5} />
26
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Colour specimens for Display Case's own Primer — the marigold accent ramp,
3
+ * the warm paper neutral ramp, the semantic role swatches (which re-paint under
4
+ * a forced `data-theme` scope), and the status hues reserved for check output.
5
+ *
6
+ * These are thin, document-specific wrappers: the Display-Case-specific data
7
+ * lives here, and the reusable {@link ColorRamp}/{@link SwatchGrid}/
8
+ * {@link StatusList} primitives (under `components/primer-specimen/`) do the
9
+ * rendering. Each chip references its `--dc-*` custom property as a complete
10
+ * literal (`var(--dc-marigold-600)`) so the swatches track the live theme *and*
11
+ * the token-conformance check can statically resolve every reference (a
12
+ * templated `var(--dc-${name})` cannot be resolved, so the full string is stored
13
+ * in the data).
14
+ */
15
+ import {
16
+ ColorRamp,
17
+ type ColorStop,
18
+ type StatusItem,
19
+ StatusList,
20
+ type Swatch,
21
+ SwatchGrid,
22
+ } from '../components/primer-specimen'
23
+
24
+ const MARIGOLD: ColorStop[] = [
25
+ { name: 'marigold-200', color: 'var(--dc-marigold-200)', caption: '#fbe3bb' },
26
+ { name: 'marigold-300', color: 'var(--dc-marigold-300)', caption: '#f6c878' },
27
+ { name: 'marigold-400', color: 'var(--dc-marigold-400)', caption: '#f0a23b' },
28
+ { name: 'marigold-500', color: 'var(--dc-marigold-500)', caption: '#e0820b' },
29
+ {
30
+ name: 'marigold-600',
31
+ color: 'var(--dc-marigold-600)',
32
+ caption: '#c2690a',
33
+ star: true,
34
+ },
35
+ { name: 'marigold-700', color: 'var(--dc-marigold-700)', caption: '#9a4f0a' },
36
+ ]
37
+
38
+ const PAPER: ColorStop[] = [
39
+ { name: 'paper-50', color: 'var(--dc-paper-50)', caption: '#fbfaf6' },
40
+ { name: 'paper-100', color: 'var(--dc-paper-100)', caption: '#f4f1e9' },
41
+ { name: 'paper-200', color: 'var(--dc-paper-200)', caption: '#e6e0d4' },
42
+ { name: 'paper-300', color: 'var(--dc-paper-300)', caption: '#d6cebe' },
43
+ { name: 'paper-400', color: 'var(--dc-paper-400)', caption: '#b3a896' },
44
+ { name: 'paper-500', color: 'var(--dc-paper-500)', caption: '#8a8073' },
45
+ { name: 'paper-600', color: 'var(--dc-paper-600)', caption: '#6b6259' },
46
+ { name: 'paper-700', color: 'var(--dc-paper-700)', caption: '#4a423a' },
47
+ { name: 'paper-800', color: 'var(--dc-paper-800)', caption: '#2e2822' },
48
+ { name: 'paper-900', color: 'var(--dc-paper-900)', caption: '#211d18' },
49
+ { name: 'paper-950', color: 'var(--dc-paper-950)', caption: '#15110d' },
50
+ ]
51
+
52
+ const SEMANTIC: Swatch[] = [
53
+ { color: 'var(--dc-bg)', token: 'bg', role: 'canvas' },
54
+ { color: 'var(--dc-bg-subtle)', token: 'bg-subtle', role: 'sidebar' },
55
+ { color: 'var(--dc-surface)', token: 'surface', role: 'inputs' },
56
+ { color: 'var(--dc-border)', token: 'border', role: 'hairline' },
57
+ { color: 'var(--dc-fg)', token: 'fg', role: 'text' },
58
+ { color: 'var(--dc-fg-muted)', token: 'fg-muted', role: 'labels' },
59
+ { color: 'var(--dc-brand)', token: 'brand', role: 'accent' },
60
+ { color: 'var(--dc-brand-subtle)', token: 'brand-subtle', role: 'wash' },
61
+ ]
62
+
63
+ const STATUS: StatusItem[] = [
64
+ { color: 'var(--dc-success)', name: 'success', caption: 'green-600' },
65
+ { color: 'var(--dc-warning)', name: 'warning', caption: 'amber-500' },
66
+ { color: 'var(--dc-danger)', name: 'danger', caption: 'red-600' },
67
+ ]
68
+
69
+ export function MarigoldRamp() {
70
+ return <ColorRamp stops={MARIGOLD} chipHeight={56} />
71
+ }
72
+
73
+ export function PaperRamp() {
74
+ return <ColorRamp stops={PAPER} chipHeight={48} />
75
+ }
76
+
77
+ export function SemanticSwatches() {
78
+ return <SwatchGrid swatches={SEMANTIC} columns={4} />
79
+ }
80
+
81
+ export function StatusHues() {
82
+ return <StatusList items={STATUS} />
83
+ }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Components overview — the three grouped specimens for the Primer's
3
+ * "Components" section. Each maps to one `components/` subfolder and lays its
4
+ * members out as labelled rows (a mono tag on the left, live specimens on the
5
+ * right):
6
+ *
7
+ * · ControlsOverview — the input atoms (`components/controls/`).
8
+ * · ShowcaseOverview — the shell molecules & organisms (`components/showcase/`).
9
+ * · PrimerOverview — the Primer-authoring primitives (`components/primer-specimen/`).
10
+ *
11
+ * Like the other showcase specimens, these compose the design-system components
12
+ * directly, so they track the live theme. The labelled-row chrome
13
+ * (`dcpl-overview` / `dcpl-ovrow` / `dcpl-ovlabel`) is defined in
14
+ * `components/primer-specimen/styles.ts`.
15
+ */
16
+ import { type ReactNode, useState } from 'react'
17
+ import {
18
+ Button,
19
+ Chip,
20
+ Eyebrow,
21
+ FlowNav,
22
+ IconButton,
23
+ Input,
24
+ NavItem,
25
+ RenderAddress,
26
+ Select,
27
+ SelectMenu,
28
+ Sidebar,
29
+ Stage,
30
+ TweaksPanel,
31
+ } from '../components'
32
+ import {
33
+ type BoxSpec,
34
+ GlyphGrid,
35
+ type SpaceStep,
36
+ SpacingScale,
37
+ SpecimenBoxRow,
38
+ type Swatch,
39
+ SwatchGrid,
40
+ } from '../components/primer-specimen'
41
+
42
+ /** One labelled row inside an overview: mono tag left, specimens right. */
43
+ function OverviewRow({
44
+ label,
45
+ align,
46
+ children,
47
+ }: {
48
+ label: string
49
+ /** Top-align the tag when the row holds a tall specimen (a panel, a tree). */
50
+ align?: 'start'
51
+ children: ReactNode
52
+ }) {
53
+ return (
54
+ <div className="dcpl-ovrow" data-align={align}>
55
+ <div className="dcpl-ovlabel">{label}</div>
56
+ <div className="dcpl-ovitems">{children}</div>
57
+ </div>
58
+ )
59
+ }
60
+
61
+ /** The input atoms — `components/controls/`. */
62
+ export function ControlsOverview() {
63
+ // SelectMenu is controlled — the row owns its committed value.
64
+ const [device, setDevice] = useState('Desktop')
65
+ return (
66
+ <div className="dcpl-overview">
67
+ <OverviewRow label="Button">
68
+ <Button>Ghost</Button>
69
+ <Button variant="primary">Primary</Button>
70
+ <Button variant="accent">Accent</Button>
71
+ <Button variant="subtle">Subtle</Button>
72
+ <Button size="sm">Small</Button>
73
+ <Button disabled>Disabled</Button>
74
+ </OverviewRow>
75
+ <OverviewRow label="Icon">
76
+ <IconButton glyph="☰" label="Nav" />
77
+ <IconButton glyph="⟲" label="Rotate" />
78
+ <IconButton glyph="✕" label="Close" active />
79
+ <IconButton glyph="+" label="Zoom in" variant="bare" />
80
+ <IconButton glyph="-" label="Zoom out" variant="bare" />
81
+ </OverviewRow>
82
+ <OverviewRow label="Input">
83
+ <Input placeholder="Search cases…" style={{ width: '11rem' }} />
84
+ <Input
85
+ type="number"
86
+ defaultValue={1280}
87
+ suffix="px"
88
+ style={{ width: '6rem' }}
89
+ />
90
+ <Input placeholder="t. opacity" style={{ width: '8rem' }} />
91
+ </OverviewRow>
92
+ <OverviewRow label="Select">
93
+ <Select
94
+ defaultValue="Full"
95
+ options={[
96
+ { label: 'Responsive', options: ['Full', 'Desktop', 'Mobile'] },
97
+ { label: 'Devices', options: ['1080p', 'iPhone 15'] },
98
+ ]}
99
+ />
100
+ <Select size="sm" options={['light', 'dark']} />
101
+ <SelectMenu
102
+ aria-label="Device"
103
+ options={['Desktop', 'Tablet', 'Mobile']}
104
+ value={device}
105
+ onChange={setDevice}
106
+ />
107
+ </OverviewRow>
108
+ </div>
109
+ )
110
+ }
111
+
112
+ const FLOW_STEPS = [
113
+ { id: 'Request link', label: 'Request link' },
114
+ { id: 'Check email', label: 'Check email' },
115
+ { id: 'Signed in', label: 'Signed in' },
116
+ ]
117
+
118
+ const TWEAK_ITEMS = [
119
+ {
120
+ label: 'label',
121
+ control: <Input size="sm" defaultValue="Save" style={{ width: '8rem' }} />,
122
+ },
123
+ {
124
+ label: 'kind',
125
+ control: <Select size="sm" options={['choice', 'text']} />,
126
+ },
127
+ {
128
+ label: 'disabled',
129
+ control: <input type="checkbox" aria-label="disabled" defaultChecked />,
130
+ },
131
+ ]
132
+
133
+ const FLOAT_ITEMS = [
134
+ { label: 'kind', control: <Select size="sm" options={['choice', 'text']} /> },
135
+ {
136
+ label: 'disabled',
137
+ control: <input type="checkbox" aria-label="disabled" />,
138
+ },
139
+ ]
140
+
141
+ /** A labelled showcase section — a mono label sitting above its specimen. */
142
+ function Section({ label, children }: { label: string; children: ReactNode }) {
143
+ return (
144
+ <section className="dcpl-sc-block">
145
+ <div className="dcpl-ovlabel">{label}</div>
146
+ {children}
147
+ </section>
148
+ )
149
+ }
150
+
151
+ /** The shell molecules & organisms — `components/showcase/`. */
152
+ export function ShowcaseOverview() {
153
+ const [active, setActive] = useState('Check email')
154
+ return (
155
+ <div className="dcpl-sc">
156
+ <div className="dcpl-sc-cols" data-pair="">
157
+ <div className="dcpl-sc-stack">
158
+ <Section label="Sidebar / NavItem">
159
+ <Sidebar style={{ width: '15rem' }}>
160
+ <NavItem
161
+ kind="component"
162
+ label="Button"
163
+ count={4}
164
+ current
165
+ expanded
166
+ onToggle={() => {}}
167
+ onSelect={() => {}}
168
+ />
169
+ <NavItem
170
+ kind="case"
171
+ label="Playground"
172
+ current
173
+ onSelect={() => {}}
174
+ />
175
+ <NavItem kind="case" label="Disabled" onSelect={() => {}} />
176
+ <NavItem
177
+ kind="component"
178
+ label="Stage"
179
+ count={3}
180
+ onToggle={() => {}}
181
+ onSelect={() => {}}
182
+ />
183
+ </Sidebar>
184
+ </Section>
185
+ <Section label="Eyebrow">
186
+ <div
187
+ style={{
188
+ display: 'flex',
189
+ flexDirection: 'column',
190
+ gap: '0.5rem',
191
+ alignItems: 'flex-start',
192
+ }}>
193
+ <Eyebrow>Components</Eyebrow>
194
+ <Eyebrow tone="strong">Documentation</Eyebrow>
195
+ <Eyebrow tone="accent">Tweaks</Eyebrow>
196
+ </div>
197
+ </Section>
198
+ </div>
199
+ <Section label="Stage">
200
+ <Stage
201
+ caption="Playground"
202
+ meta="390 × 844"
203
+ frame="fill"
204
+ grid
205
+ corners
206
+ style={{ width: '100%', flex: 1, minHeight: 0 }}>
207
+ <Chip variant="accent">exhibit goes here</Chip>
208
+ </Stage>
209
+ </Section>
210
+ </div>
211
+ <Section label="Chip">
212
+ <div className="dcpl-ovitems">
213
+ <Chip>atom</Chip>
214
+ <Chip>molecule</Chip>
215
+ <Chip variant="accent">flow</Chip>
216
+ <Chip variant="solid">page</Chip>
217
+ <Chip current index="2">
218
+ Check email
219
+ </Chip>
220
+ </div>
221
+ </Section>
222
+ <Section label="FlowNav">
223
+ <FlowNav steps={FLOW_STEPS} activeId={active} onSelect={setActive} />
224
+ </Section>
225
+ <Section label="TweaksPanel — docked / floating">
226
+ <div className="dcpl-sc-tweaks">
227
+ <TweaksPanel
228
+ url="?t.kind=choice&t.disabled=1"
229
+ items={TWEAK_ITEMS}
230
+ onToggleMode={() => {}}
231
+ />
232
+ <div className="dcpl-sc-float">
233
+ {'tall exhibit — pan & zoom'}
234
+ <TweaksPanel
235
+ mode="floating"
236
+ url="?t.kind=choice"
237
+ items={FLOAT_ITEMS}
238
+ onToggleMode={() => {}}
239
+ />
240
+ </div>
241
+ </div>
242
+ </Section>
243
+ <Section label="RenderAddress">
244
+ <RenderAddress url="/render/button/playground?theme=light&t.variant=accent" />
245
+ </Section>
246
+ </div>
247
+ )
248
+ }
249
+
250
+ const SWATCHES: Swatch[] = [
251
+ { token: 'brand', color: 'var(--dc-brand)', role: 'accent' },
252
+ { token: 'fg', color: 'var(--dc-fg)', role: 'text' },
253
+ { token: 'surface', color: 'var(--dc-surface)', role: 'inputs' },
254
+ { token: 'border', color: 'var(--dc-border)', role: 'hairline' },
255
+ ]
256
+
257
+ const SPACE: SpaceStep[] = [
258
+ { token: 'space-2', value: '4px', width: 4 },
259
+ { token: 'space-4', value: '8px', width: 8 },
260
+ { token: 'space-8', value: '16px', width: 16 },
261
+ { token: 'space-16', value: '32px', width: 32 },
262
+ ]
263
+
264
+ const GLYPHS = [
265
+ { glyph: '☰', use: 'nav' },
266
+ { glyph: '⟲', use: 'reset' },
267
+ { glyph: '✕', use: 'close' },
268
+ { glyph: '+', use: 'zoom in' },
269
+ { glyph: '-', use: 'zoom out' },
270
+ ]
271
+
272
+ const RADII: BoxSpec[] = [
273
+ {
274
+ label: 'sm',
275
+ note: '5px · controls',
276
+ boxStyle: { borderRadius: 'var(--dc-radius-sm)' },
277
+ },
278
+ {
279
+ label: 'md',
280
+ note: '8px · panels',
281
+ boxStyle: { borderRadius: 'var(--dc-radius-md)' },
282
+ },
283
+ {
284
+ label: 'full',
285
+ note: 'pills · dots',
286
+ boxStyle: { borderRadius: 'var(--dc-radius-full)', width: '48px' },
287
+ },
288
+ ]
289
+
290
+ /** The Primer-authoring primitives — `components/primer-specimen/`. */
291
+ export function PrimerOverview() {
292
+ return (
293
+ <div className="dcpl-overview">
294
+ <OverviewRow label="Swatches" align="start">
295
+ <SwatchGrid swatches={SWATCHES} columns={4} />
296
+ </OverviewRow>
297
+ <OverviewRow label="Spacing" align="start">
298
+ <SpacingScale steps={SPACE} />
299
+ </OverviewRow>
300
+ <OverviewRow label="Glyphs" align="start">
301
+ <GlyphGrid glyphs={GLYPHS} columns={5} />
302
+ </OverviewRow>
303
+ <OverviewRow label="Boxes" align="start">
304
+ <SpecimenBoxRow items={RADII} />
305
+ </OverviewRow>
306
+ </div>
307
+ )
308
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Visual-foundation & content specimens for Display Case's own Primer — the
3
+ * content-voice definition list, the live interaction-states row, and the
4
+ * three-region layout mock.
5
+ *
6
+ * The definition list and layout mock are thin wrappers over the reusable
7
+ * {@link DefinitionList}/{@link LayoutMock} primitives (under
8
+ * `components/primer-specimen/`). The states row is built from the system's own
9
+ * components, so it tracks the live theme.
10
+ */
11
+ import { Button, Chip, Input } from '../components'
12
+ import {
13
+ type DefEntry,
14
+ DefinitionList,
15
+ LayoutMock as SpecimenLayoutMock,
16
+ } from '../components/primer-specimen'
17
+
18
+ const FUNDAMENTALS: DefEntry[] = [
19
+ {
20
+ term: 'Voice',
21
+ description:
22
+ 'Plain, confident, technical-but-warm. It explains why, briefly, then moves on — like a thoughtful README from an engineer who respects your time.',
23
+ },
24
+ {
25
+ term: 'Person',
26
+ description:
27
+ 'Addresses you. Refers to itself as Display Case or it — never we in UI copy.',
28
+ },
29
+ {
30
+ term: 'Casing',
31
+ description:
32
+ 'Sentence case everywhere. The one exception is the eyebrow label: UPPERCASE mono with wide tracking.',
33
+ },
34
+ {
35
+ term: 'Length',
36
+ description:
37
+ 'Terse. Buttons are one or two words; labels are a single token, often the literal prop name in mono.',
38
+ },
39
+ {
40
+ term: 'Numbers',
41
+ description:
42
+ 'Shown in mono, exact, no fuss — 1280 × 800, 100%, /render/button/playground.',
43
+ },
44
+ { term: 'Emoji', description: "Not used in the UI. Don't reach for them." },
45
+ ]
46
+
47
+ export function DefList() {
48
+ return <DefinitionList entries={FUNDAMENTALS} />
49
+ }
50
+
51
+ export function StatesRow() {
52
+ return (
53
+ <div className="dcpl-row">
54
+ <Button>Default</Button>
55
+ <Button variant="accent">Selected</Button>
56
+ <Chip current>active case</Chip>
57
+ <Input placeholder="focus me" style={{ width: '9rem' }} />
58
+ <Button disabled>Disabled</Button>
59
+ </div>
60
+ )
61
+ }
62
+
63
+ export function LayoutMock() {
64
+ return (
65
+ <SpecimenLayoutMock
66
+ header="header"
67
+ sidebar="sidebar"
68
+ main="main · the stage"
69
+ />
70
+ )
71
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Primer specimens — Display Case's own document-specific specimens for its
3
+ * Primer wall text (colour ramps, type scale, spacing, brand, states, render
4
+ * address). These are thin wrappers: each supplies Display-Case-specific data to
5
+ * a reusable primitive under `components/primer-specimen/` (or, for the live
6
+ * states/flow/tweaks demos, composes the design-system components directly).
7
+ *
8
+ * They live outside `components/` so they aren't subject to the showcase
9
+ * coverage lint, and they're imported only by `primer.mdx`. Anyone building
10
+ * their own Primer should import the generic primitives from
11
+ * `components/primer-specimen` and feed them their own data — these wrappers
12
+ * are the worked example.
13
+ */
14
+
15
+ export { Glyphs } from './brand'
16
+ export { MarigoldRamp, PaperRamp, SemanticSwatches, StatusHues } from './colors'
17
+ export {
18
+ ControlsOverview,
19
+ PrimerOverview,
20
+ ShowcaseOverview,
21
+ } from './components'
22
+ export { DefList, LayoutMock, StatesRow } from './foundations'
23
+ export { FlowNavDemo, RenderAddress, TweaksPanelDemo } from './showcase'
24
+ export { ElevationRow, RadiusRow, SpacingScale } from './spacing'
25
+ export { FontFamilies, TypeScale, Weights } from './type'