@charcuterie/ui 4.5.0 → 4.6.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 (226) hide show
  1. package/README.md +7 -2
  2. package/dist/Card/Card.d.ts +5 -2
  3. package/dist/Card/Card.d.ts.map +1 -1
  4. package/dist/Card/Card.js +23 -3
  5. package/dist/Card/Card.js.map +1 -1
  6. package/dist/Overlay/OverlayPanel.d.ts.map +1 -1
  7. package/dist/Overlay/OverlayPanel.js +54 -2
  8. package/dist/Overlay/OverlayPanel.js.map +1 -1
  9. package/dist/Overlay/OverlayStack.d.ts +5 -0
  10. package/dist/Overlay/OverlayStack.d.ts.map +1 -1
  11. package/dist/Overlay/OverlayStack.js +2 -0
  12. package/dist/Overlay/OverlayStack.js.map +1 -1
  13. package/dist/Toast/ToastRegion.d.ts +61 -0
  14. package/dist/Toast/ToastRegion.d.ts.map +1 -1
  15. package/dist/Toast/ToastRegion.js +80 -3
  16. package/dist/Toast/ToastRegion.js.map +1 -1
  17. package/dist/Toolbar/useToolbarOverflow.d.ts.map +1 -1
  18. package/dist/Toolbar/useToolbarOverflow.js +39 -0
  19. package/dist/Toolbar/useToolbarOverflow.js.map +1 -1
  20. package/package.json +3 -2
  21. package/src/Accordion/Accordion.mdx +1 -1
  22. package/src/Accordion/Accordion.stories.tsx +3 -1
  23. package/src/Accordion/Accordion.test.tsx +4 -4
  24. package/src/ActionTiles/ActionTiles.mdx +1 -1
  25. package/src/ActionTiles/ActionTiles.stories.tsx +3 -1
  26. package/src/ActionTiles/ActionTiles.test.tsx +3 -3
  27. package/src/AdaptiveGrid/AdaptiveGrid.mdx +1 -1
  28. package/src/AdaptiveGrid/AdaptiveGrid.stories.tsx +3 -1
  29. package/src/AdaptiveGrid/AdaptiveGrid.test.tsx +5 -5
  30. package/src/Alert/Alert.mdx +1 -1
  31. package/src/Alert/Alert.stories.tsx +3 -1
  32. package/src/Alert/Alert.test.tsx +2 -2
  33. package/src/Avatar/Avatar.mdx +1 -1
  34. package/src/Avatar/Avatar.stories.tsx +4 -1
  35. package/src/Avatar/Avatar.test.tsx +2 -2
  36. package/src/Badge/Badge.mdx +1 -1
  37. package/src/Badge/Badge.stories.tsx +3 -1
  38. package/src/Badge/Badge.test.tsx +3 -3
  39. package/src/BadgeButton/BadgeButton.mdx +1 -1
  40. package/src/BadgeButton/BadgeButton.stories.tsx +3 -1
  41. package/src/BadgeButton/BadgeButton.test.tsx +2 -2
  42. package/src/Board/Board.mdx +1 -1
  43. package/src/Board/Board.stories.tsx +4 -1
  44. package/src/Board/Board.test.tsx +2 -2
  45. package/src/Button/Button.mdx +1 -1
  46. package/src/Button/Button.stories.tsx +3 -1
  47. package/src/Button/Button.test.tsx +2 -2
  48. package/src/ButtonLink/ButtonLink.mdx +1 -1
  49. package/src/ButtonLink/ButtonLink.stories.tsx +3 -1
  50. package/src/ButtonLink/ButtonLink.test.tsx +3 -3
  51. package/src/Card/Card.mdx +21 -1
  52. package/src/Card/Card.stories.tsx +91 -1
  53. package/src/Card/Card.test.tsx +60 -3
  54. package/src/Card/Card.tsx +24 -2
  55. package/src/Checkbox/Checkbox.mdx +1 -1
  56. package/src/Checkbox/Checkbox.stories.tsx +3 -1
  57. package/src/Checkbox/Checkbox.test.tsx +4 -4
  58. package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.mdx +1 -1
  59. package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.stories.tsx +3 -1
  60. package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.test.tsx +5 -5
  61. package/src/ColorSchemeToggle/ColorSchemeToggle.mdx +1 -1
  62. package/src/ColorSchemeToggle/ColorSchemeToggle.stories.tsx +3 -1
  63. package/src/ColorSchemeToggle/ColorSchemeToggle.test.tsx +5 -5
  64. package/src/Combobox/Combobox.mdx +1 -1
  65. package/src/Combobox/Combobox.stories.tsx +3 -1
  66. package/src/Combobox/Combobox.test.tsx +2 -2
  67. package/src/CopyButton/CopyButton.mdx +1 -1
  68. package/src/CopyButton/CopyButton.stories.tsx +4 -1
  69. package/src/CopyButton/CopyButton.test.tsx +3 -3
  70. package/src/DataTable/DataTable.mdx +1 -1
  71. package/src/DataTable/DataTable.stories.tsx +3 -1
  72. package/src/DataTable/DataTable.test.tsx +3 -3
  73. package/src/DatePicker/DatePicker.mdx +1 -1
  74. package/src/DatePicker/DatePicker.stories.tsx +3 -1
  75. package/src/DatePicker/DatePicker.test.tsx +3 -3
  76. package/src/DatePicker/plainDate.test.ts +21 -3
  77. package/src/Dialog/Dialog.mdx +1 -1
  78. package/src/Dialog/Dialog.stories.tsx +3 -1
  79. package/src/Dialog/Dialog.test.tsx +2 -2
  80. package/src/DropRail/DropRail.mdx +1 -1
  81. package/src/DropRail/DropRail.stories.tsx +4 -1
  82. package/src/DropRail/DropRail.test.tsx +4 -4
  83. package/src/EmptyState/EmptyState.mdx +1 -1
  84. package/src/EmptyState/EmptyState.stories.tsx +3 -1
  85. package/src/EmptyState/EmptyState.test.tsx +2 -2
  86. package/src/Field/Field.mdx +1 -1
  87. package/src/Field/Field.stories.tsx +3 -1
  88. package/src/Field/Field.test.tsx +4 -4
  89. package/src/FileDropZone/FileDropZone.mdx +1 -1
  90. package/src/FileDropZone/FileDropZone.stories.tsx +3 -1
  91. package/src/FileDropZone/FileDropZone.test.tsx +3 -3
  92. package/src/Header/Header.mdx +1 -1
  93. package/src/Header/Header.stories.tsx +3 -1
  94. package/src/IconButton/IconButton.mdx +1 -1
  95. package/src/IconButton/IconButton.stories.tsx +3 -1
  96. package/src/IconButton/IconButton.test.tsx +2 -2
  97. package/src/Lightbox/Lightbox.mdx +1 -1
  98. package/src/Lightbox/Lightbox.stories.tsx +3 -1
  99. package/src/Lightbox/Lightbox.test.tsx +2 -2
  100. package/src/Listbox/Listbox.mdx +1 -1
  101. package/src/Listbox/Listbox.stories.tsx +3 -1
  102. package/src/Listbox/Listbox.test.tsx +5 -5
  103. package/src/LiveStatusIndicator/LiveStatusIndicator.mdx +1 -1
  104. package/src/LiveStatusIndicator/LiveStatusIndicator.stories.tsx +3 -1
  105. package/src/LiveStatusIndicator/LiveStatusIndicator.test.tsx +2 -2
  106. package/src/LogViewer/LogViewer.mdx +1 -1
  107. package/src/LogViewer/LogViewer.stories.tsx +3 -1
  108. package/src/LogViewer/LogViewer.test.tsx +2 -2
  109. package/src/Main/Main.mdx +1 -1
  110. package/src/Main/Main.stories.tsx +3 -1
  111. package/src/Main/Main.test.tsx +3 -3
  112. package/src/MarkdownEditor/MarkdownEditor.mdx +1 -1
  113. package/src/MarkdownEditor/MarkdownEditor.stories.tsx +3 -1
  114. package/src/MarkdownEditor/MarkdownEditor.test.tsx +4 -4
  115. package/src/MarkdownLine/MarkdownLine.mdx +1 -1
  116. package/src/MarkdownLine/MarkdownLine.stories.tsx +4 -1
  117. package/src/MarkdownLine/MarkdownLine.test.tsx +3 -3
  118. package/src/MediaTile/MediaTile.stories.tsx +3 -1
  119. package/src/MediaTile/MediaTile.test.tsx +2 -2
  120. package/src/Menu/Menu.mdx +1 -1
  121. package/src/Menu/Menu.stories.tsx +3 -1
  122. package/src/Modal/Modal.mdx +1 -1
  123. package/src/Modal/Modal.stories.tsx +3 -1
  124. package/src/Modal/Modal.test.tsx +3 -3
  125. package/src/Nav/Nav.mdx +1 -1
  126. package/src/Nav/Nav.stories.tsx +3 -1
  127. package/src/Nav/Nav.test.tsx +6 -6
  128. package/src/NavBar/NavBar.mdx +1 -1
  129. package/src/NavBar/NavBar.stories.tsx +3 -1
  130. package/src/NavBar/NavBar.test.tsx +3 -3
  131. package/src/Overlay/OverlayPanel.tsx +63 -2
  132. package/src/Overlay/OverlayStack.tsx +7 -1
  133. package/src/Picker/Picker.mdx +1 -1
  134. package/src/Picker/Picker.stories.tsx +3 -1
  135. package/src/Picker/Picker.test.tsx +2 -2
  136. package/src/Popover/Popover.mdx +1 -1
  137. package/src/Popover/Popover.stories.tsx +3 -1
  138. package/src/Popover/Popover.test.tsx +2 -2
  139. package/src/PortraitTiles/PortraitTiles.mdx +1 -1
  140. package/src/PortraitTiles/PortraitTiles.stories.tsx +3 -1
  141. package/src/PortraitTiles/PortraitTiles.test.tsx +5 -5
  142. package/src/ProgressBar/ProgressBar.mdx +1 -1
  143. package/src/ProgressBar/ProgressBar.stories.tsx +3 -1
  144. package/src/ProgressBar/ProgressBar.test.tsx +2 -2
  145. package/src/QueryBuilder/QueryBuilder.mdx +1 -1
  146. package/src/QueryBuilder/QueryBuilder.stories.tsx +3 -1
  147. package/src/QueryBuilder/QueryBuilder.test.tsx +2 -2
  148. package/src/RadioGroup/RadioGroup.mdx +1 -1
  149. package/src/RadioGroup/RadioGroup.stories.tsx +3 -1
  150. package/src/RadioGroup/RadioGroup.test.tsx +2 -2
  151. package/src/Rail/Rail.mdx +1 -1
  152. package/src/Rail/Rail.stories.tsx +3 -1
  153. package/src/Rail/Rail.test.tsx +2 -2
  154. package/src/RangeSlider/RangeSlider.mdx +1 -1
  155. package/src/RangeSlider/RangeSlider.stories.tsx +3 -1
  156. package/src/RangeSlider/RangeSlider.test.tsx +7 -3
  157. package/src/ReorderList/ReorderList.mdx +1 -1
  158. package/src/ReorderList/ReorderList.stories.tsx +3 -1
  159. package/src/ReorderList/ReorderList.test.tsx +7 -7
  160. package/src/RouterLink/UnstyledLink.stories.tsx +4 -1
  161. package/src/RouterLink/UnstyledLink.test.tsx +2 -2
  162. package/src/SearchInput/SearchInput.mdx +1 -1
  163. package/src/SearchInput/SearchInput.stories.tsx +3 -1
  164. package/src/SegmentedControl/SegmentedControl.mdx +1 -1
  165. package/src/SegmentedControl/SegmentedControl.stories.tsx +3 -1
  166. package/src/SegmentedControl/SegmentedControl.test.tsx +2 -2
  167. package/src/Select/Select.mdx +1 -1
  168. package/src/Select/Select.stories.tsx +3 -1
  169. package/src/Select/Select.test.tsx +4 -4
  170. package/src/Shell/Shell.mdx +1 -1
  171. package/src/Shell/Shell.stories.tsx +3 -1
  172. package/src/Shell/Shell.test.tsx +2 -2
  173. package/src/Skeleton/Skeleton.mdx +1 -1
  174. package/src/Skeleton/Skeleton.stories.tsx +3 -1
  175. package/src/Skeleton/Skeleton.test.tsx +2 -2
  176. package/src/Slider/Slider.mdx +1 -1
  177. package/src/Slider/Slider.stories.tsx +3 -1
  178. package/src/Slider/Slider.test.tsx +2 -2
  179. package/src/SortableTableHeader/SortableTableHeader.mdx +1 -1
  180. package/src/SortableTableHeader/SortableTableHeader.stories.tsx +3 -1
  181. package/src/SortableTableHeader/SortableTableHeader.test.tsx +3 -3
  182. package/src/Spinner/Spinner.mdx +1 -1
  183. package/src/Spinner/Spinner.stories.tsx +3 -1
  184. package/src/Spinner/Spinner.test.tsx +2 -2
  185. package/src/Stepper/Stepper.mdx +1 -1
  186. package/src/Stepper/Stepper.stories.tsx +4 -1
  187. package/src/Stepper/Stepper.test.tsx +7 -7
  188. package/src/Swatch/Swatch.mdx +1 -1
  189. package/src/Swatch/Swatch.stories.tsx +4 -1
  190. package/src/Swatch/Swatch.test.tsx +3 -3
  191. package/src/Switch/Switch.mdx +1 -1
  192. package/src/Switch/Switch.stories.tsx +3 -1
  193. package/src/Switch/Switch.test.tsx +2 -2
  194. package/src/Tabs/Tabs.mdx +1 -1
  195. package/src/Tabs/Tabs.stories.tsx +3 -1
  196. package/src/Tabs/Tabs.test.tsx +3 -3
  197. package/src/TextLink/TextLink.mdx +1 -1
  198. package/src/TextLink/TextLink.stories.tsx +3 -1
  199. package/src/TextLink/TextLink.test.tsx +4 -4
  200. package/src/TimecodeInput/TimecodeInput.mdx +1 -1
  201. package/src/TimecodeInput/TimecodeInput.stories.tsx +3 -1
  202. package/src/Toast/Toast.mdx +1 -1
  203. package/src/Toast/Toast.stories.tsx +157 -1
  204. package/src/Toast/Toast.test.tsx +2 -2
  205. package/src/Toast/ToastRegion.test.tsx +172 -0
  206. package/src/Toast/ToastRegion.tsx +120 -32
  207. package/src/Toolbar/Toolbar.mdx +1 -1
  208. package/src/Toolbar/Toolbar.stories.tsx +3 -1
  209. package/src/Toolbar/Toolbar.test.tsx +89 -5
  210. package/src/Toolbar/useToolbarOverflow.ts +43 -0
  211. package/src/Tooltip/Tooltip.mdx +1 -1
  212. package/src/Tooltip/Tooltip.stories.tsx +3 -1
  213. package/src/Tooltip/Tooltip.test.tsx +2 -2
  214. package/src/VirtualizedGrid/VirtualizedGrid.mdx +1 -1
  215. package/src/VirtualizedGrid/VirtualizedGrid.stories.tsx +4 -1
  216. package/src/VirtualizedGrid/VirtualizedGrid.test.tsx +5 -5
  217. package/src/VisuallyHidden/VisuallyHidden.mdx +1 -1
  218. package/src/VisuallyHidden/VisuallyHidden.stories.tsx +3 -1
  219. package/src/markdownEditorCodeMirror/MarkdownEditorCodeMirror.mdx +1 -1
  220. package/src/markdownEditorCodeMirror/MarkdownEditorCodeMirror.stories.tsx +3 -1
  221. package/src/markdownEditorCodeMirror/MarkdownEditorCodeMirror.test.tsx +3 -3
  222. package/src/markdownEditorCodeMirror/MarkdownView.mdx +1 -1
  223. package/src/markdownEditorCodeMirror/MarkdownView.stories.tsx +4 -1
  224. package/src/markdownEditorCodeMirror/MarkdownView.test.tsx +44 -20
  225. package/src/reactRouter/ReactRouterAdapter.stories.tsx +3 -1
  226. package/src/reactRouter/ReactRouterAdapter.test.tsx +2 -2
@@ -11,7 +11,7 @@ const {
11
11
  AllStates,
12
12
  AutoHues,
13
13
  BesideTheRadioTile,
14
- Default,
14
+ Playground,
15
15
  Interactive,
16
16
  Links,
17
17
  NamedHues,
@@ -41,7 +41,7 @@ const getAccentEdgeLayer = (boxShadow: string) =>
41
41
 
42
42
  test("it is a named group of pressable tiles", async () => {
43
43
  const { canvas, canvasElement } =
44
- await mountStory(Default)
44
+ await mountStory(Playground)
45
45
 
46
46
  const group = expectAgentDrivable(canvas, {
47
47
  name: "Queue type",
@@ -64,7 +64,7 @@ test("it is a named group of pressable tiles", async () => {
64
64
  })
65
65
 
66
66
  test("a tile's hint is part of its accessible name", async () => {
67
- const { canvas } = await mountStory(Default)
67
+ const { canvas } = await mountStory(Playground)
68
68
 
69
69
  // The reason the hint is rendered inside the tile rather than
70
70
  // beside it: a hint a screen reader never reads is a hint half the
@@ -14,7 +14,7 @@ That is the opposite of every wrapping grid in the fleet today. `auto-fill, minm
14
14
  takes every column the width allows, which is how you end up with seven items strung
15
15
  across an ultrawide and nothing below the fold.
16
16
 
17
- <Canvas of={AdaptiveGridStories.Default} />
17
+ <Canvas of={AdaptiveGridStories.Playground} />
18
18
 
19
19
  ## Props
20
20
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
  import { useState } from "react"
3
4
 
@@ -89,7 +90,8 @@ type Story = StoryObj<typeof meta>
89
90
  * carry nine — and the content cap widens from 56rem to 72rem to
90
91
  * hold them.
91
92
  */
92
- export const Default: Story = {
93
+ export const Playground: Story = {
94
+ parameters: playgroundParameters,
93
95
  args: { blockSizeResolver: fixedBlockSize(1080) },
94
96
  }
95
97
 
@@ -36,7 +36,7 @@ import * as stories from "./AdaptiveGrid.stories.tsx"
36
36
  * all.
37
37
  */
38
38
 
39
- const { AllStates, AllVariants, Default, Responsive } =
39
+ const { AllStates, AllVariants, Playground, Responsive } =
40
40
  composeStories(stories)
41
41
 
42
42
  /**
@@ -109,7 +109,7 @@ test("the grid re-columns when its container resizes", async () => {
109
109
  // need two stacks; at 700px wide only one column fits, and at
110
110
  // 1280px the second one it wanted is finally allowed.
111
111
  const { canvasElement } = await mountAtInlineSize(
112
- Default,
112
+ Playground,
113
113
  700,
114
114
  )
115
115
 
@@ -147,7 +147,7 @@ test("height buys the column, and width only caps it", async () => {
147
147
 
148
148
  test("the content cap widens with the columns", async () => {
149
149
  const { canvasElement } = await mountAtInlineSize(
150
- Default,
150
+ Playground,
151
151
  1280,
152
152
  )
153
153
 
@@ -163,7 +163,7 @@ test("the content cap widens with the columns", async () => {
163
163
 
164
164
  test("the measured box is never the capped box", async () => {
165
165
  const { canvasElement } = await mountAtInlineSize(
166
- Default,
166
+ Playground,
167
167
  1280,
168
168
  )
169
169
 
@@ -203,7 +203,7 @@ test("one item is one column at a reading measure", async () => {
203
203
 
204
204
  test("a long unbroken string does not push a track wide", async () => {
205
205
  const { canvasElement } = await mountAtInlineSize(
206
- Default,
206
+ Playground,
207
207
  1280,
208
208
  )
209
209
 
@@ -11,7 +11,7 @@ four times — `TowerAlerts`, `UsbAlertBanner`, `LoadedDiscsBanner`, `VerdictBad
11
11
  of those carry a byte-identical `TONE_CLASS` map of hardcoded hexes with no light mode.
12
12
  mux-magic spells the same idea a third way in `statusClassMap`.
13
13
 
14
- <Canvas of={AlertStories.Default} />
14
+ <Canvas of={AlertStories.Playground} />
15
15
 
16
16
  ## Props
17
17
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
 
3
4
  import {
@@ -47,7 +48,8 @@ type Story = StoryObj<typeof meta>
47
48
  * rip-deck's grouped tower alert, verbatim: one trouble, the bays it
48
49
  * touches, and whether the house speakers already said it out loud.
49
50
  */
50
- export const Default: Story = {
51
+ export const Playground: Story = {
52
+ parameters: playgroundParameters,
51
53
  args: {
52
54
  description: "4 bays · 3, 4, 5, 6 · confirmed",
53
55
  heading:
@@ -7,7 +7,7 @@ import { mountStory } from "../mountStory.testHelpers.ts"
7
7
  import { expectAgentDrivable } from "../testing/index.ts"
8
8
  import * as stories from "./Alert.stories.tsx"
9
9
 
10
- const { AllStates, Default, Interactive, Responsive } =
10
+ const { AllStates, Playground, Interactive, Responsive } =
11
11
  composeStories(stories)
12
12
 
13
13
  test("a labelled alert is a landmark an agent can scope to", async () => {
@@ -34,7 +34,7 @@ test("a labelled alert is a landmark an agent can scope to", async () => {
34
34
 
35
35
  test("an unlabelled alert is not a landmark", async () => {
36
36
  const { canvas, canvasElement } =
37
- await mountStory(Default)
37
+ await mountStory(Playground)
38
38
 
39
39
  // A block, deliberately. Nine bay cards each holding a named
40
40
  // region called "Part of the tower-wide problem above." is axe's
@@ -10,7 +10,7 @@ A person, as a coloured chip — a glyph or an initial, with the name attached w
10
10
  assistive technology and a hover can reach it. It exists to **delete a printed name**: a
11
11
  board whose cards all say "Owner" has spent a column on a word that a colour says faster.
12
12
 
13
- <Canvas of={AvatarStories.Default} />
13
+ <Canvas of={AvatarStories.Playground} />
14
14
 
15
15
  ## Props
16
16
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
 
3
4
  import { categoricalArgType } from "../argTypes.storyHelpers.ts"
@@ -75,7 +76,9 @@ type Story = StoryObj<typeof meta>
75
76
  * a screen reader and on hover for a pointer, and it is not printed
76
77
  * anywhere — `getByRole("img", { name: "Ada Lovelace" })` resolves.
77
78
  */
78
- export const Default: Story = {}
79
+ export const Playground: Story = {
80
+ parameters: playgroundParameters,
81
+ }
79
82
 
80
83
  /**
81
84
  * The three appearances, and the ten colours the scale holds.
@@ -7,7 +7,7 @@ import { mountStory } from "../mountStory.testHelpers.ts"
7
7
  import { expectAgentDrivable } from "../testing/index.ts"
8
8
  import * as stories from "./Avatar.stories.tsx"
9
9
 
10
- const { AllStates, AllVariants, Default, InAList } =
10
+ const { AllStates, AllVariants, Playground, InAList } =
11
11
  composeStories(stories)
12
12
 
13
13
  /**
@@ -18,7 +18,7 @@ const { AllStates, AllVariants, Default, InAList } =
18
18
  * text is the one regression that matters.
19
19
  */
20
20
  test("the name is readable by an agent and never printed", async () => {
21
- const { canvas } = await mountStory(Default)
21
+ const { canvas } = await mountStory(Playground)
22
22
 
23
23
  const avatar = expectAgentDrivable(canvas, {
24
24
  name: "Ada Lovelace",
@@ -11,7 +11,7 @@ Four repos, and rip-deck declares the **identical** `TONE_CLASS` map twice —
11
11
  copy-paste. mux-magic's `statusClassMap` is the same idea spelled a third way, keyed by a
12
12
  bare `string`, so an unrecognised status renders with no colour and no error.
13
13
 
14
- <Canvas of={BadgeStories.Default} />
14
+ <Canvas of={BadgeStories.Playground} />
15
15
 
16
16
  ## Props
17
17
 
@@ -2,6 +2,7 @@ import {
2
2
  asyncTransitions,
3
3
  useStatus,
4
4
  } from "@charcuterie/logic"
5
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
5
6
  import {
6
7
  CATEGORICAL_HUES,
7
8
  CATEGORICAL_INDEXES,
@@ -64,7 +65,8 @@ type Story = StoryObj<typeof meta>
64
65
  * else, not a live region — so the handle an agent reads off the row
65
66
  * is its text.
66
67
  */
67
- export const Default: Story = {
68
+ export const Playground: Story = {
69
+ parameters: playgroundParameters,
68
70
  args: { children: "running", intent: "info" },
69
71
  }
70
72
 
@@ -11,13 +11,13 @@ import meta, * as stories from "./Badge.stories.tsx"
11
11
  const {
12
12
  Categorical,
13
13
  CategoricalLabels,
14
- Default,
14
+ Playground,
15
15
  Interactive,
16
16
  Responsive,
17
17
  } = composeStories(stories)
18
18
 
19
19
  test("the text is queryable, which is what an agent matches on", async () => {
20
- const { canvas } = await mountStory(Default)
20
+ const { canvas } = await mountStory(Playground)
21
21
 
22
22
  // No role, deliberately — a badge is a word about something else,
23
23
  // not a live region. So there is nothing to `getByRole` and the
@@ -115,7 +115,7 @@ test("a truncated badge never paints outside its container", async () => {
115
115
  })
116
116
 
117
117
  test("a short badge gets no tooltip", async () => {
118
- const { canvasElement } = await mountStory(Default)
118
+ const { canvasElement } = await mountStory(Playground)
119
119
 
120
120
  // The measurement has to be able to say *no*, or `title` is just
121
121
  // unconditional and every pill in a bay list grows a tooltip.
@@ -16,7 +16,7 @@ opens the panel that changes it, so each one is pressable — and all six were s
16
16
  had no way to make `Badge` pressable. The same shape turns up on a start-point chip, a
17
17
  group chip and a pool's Exclude chip.
18
18
 
19
- <Canvas of={BadgeButtonStories.Default} />
19
+ <Canvas of={BadgeButtonStories.Playground} />
20
20
 
21
21
  ## Props
22
22
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
 
3
4
  import {
@@ -53,7 +54,8 @@ type Story = StoryObj<typeof meta>
53
54
  * finds it — which is what an agent, and every test in the fleet,
54
55
  * actually matches on.
55
56
  */
56
- export const Default: Story = {
57
+ export const Playground: Story = {
58
+ parameters: playgroundParameters,
57
59
  args: { children: "1 episode", intent: "accent" },
58
60
  }
59
61
 
@@ -10,7 +10,7 @@ import { mountStory } from "../mountStory.testHelpers.ts"
10
10
  import { expectAgentDrivable } from "../testing/index.ts"
11
11
  import meta, * as stories from "./BadgeButton.stories.tsx"
12
12
 
13
- const { BesideABadge, Default, InATileFooter } =
13
+ const { BesideABadge, Playground, InATileFooter } =
14
14
  composeStories(stories)
15
15
 
16
16
  /**
@@ -18,7 +18,7 @@ const { BesideABadge, Default, InATileFooter } =
18
18
  * is a component rather than a `className` on `Badge`.
19
19
  */
20
20
  test("is a button, not a span", async () => {
21
- const { canvas } = await mountStory(Default)
21
+ const { canvas } = await mountStory(Playground)
22
22
 
23
23
  const chip = expectAgentDrivable(canvas, {
24
24
  name: "1 episode",
@@ -9,7 +9,7 @@ import * as BoardStories from "./Board.stories";
9
9
  Lanes of cards, sized by their **container**, moved by keyboard or by pointer — and with
10
10
  **no drag-and-drop dependency**.
11
11
 
12
- <Canvas of={BoardStories.Default} />
12
+ <Canvas of={BoardStories.Playground} />
13
13
 
14
14
  <Canvas of={BoardStories.CardMenuItems} />
15
15
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
  import type { ReactNode } from "react"
3
4
  import { useState } from "react"
@@ -473,7 +474,9 @@ type Story = StoryObj<typeof meta>
473
474
  * a real mode rather than a story convenience: a board on a wall
474
475
  * display should not be advertising affordances nobody can use.
475
476
  */
476
- export const Default: Story = {}
477
+ export const Playground: Story = {
478
+ parameters: playgroundParameters,
479
+ }
477
480
 
478
481
  /**
479
482
  * Parallel project pools as horizontal bands. Every lane stays on
@@ -16,7 +16,7 @@ const {
16
16
  AccentEdge,
17
17
  AllStates,
18
18
  CardMenuItems,
19
- Default,
19
+ Playground,
20
20
  InBoardScreen,
21
21
  Interactive,
22
22
  MarkdownTitles,
@@ -188,7 +188,7 @@ test("the priority bar's meaning is available as text", async () => {
188
188
  * a promise.
189
189
  */
190
190
  test("a board with no onMove has no move handles", async () => {
191
- const { canvas } = await mountStory(Default)
191
+ const { canvas } = await mountStory(Playground)
192
192
 
193
193
  await expect(
194
194
  canvas.queryAllByRole("button", { name: /^Move / }),
@@ -14,7 +14,7 @@ Six intents x four appearances x three sizes, all of it from tier-2 tokens — s
14
14
  swap or a density flip repaints every button on the page with no prop change and no
15
15
  re-render.
16
16
 
17
- <Canvas of={ButtonStories.Default} />
17
+ <Canvas of={ButtonStories.Playground} />
18
18
 
19
19
  ## Props
20
20
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
 
3
4
  import {
@@ -57,7 +58,8 @@ export default meta
57
58
 
58
59
  type Story = StoryObj<typeof meta>
59
60
 
60
- export const Default: Story = {
61
+ export const Playground: Story = {
62
+ parameters: playgroundParameters,
61
63
  args: { children: "Start rip" },
62
64
  }
63
65
 
@@ -9,11 +9,11 @@ import { mountStory } from "../mountStory.testHelpers.ts"
9
9
  import { expectAgentDrivable } from "../testing/index.ts"
10
10
  import meta, * as stories from "./Button.stories.tsx"
11
11
 
12
- const { AllStates, Default, Loading } =
12
+ const { AllStates, Playground, Loading } =
13
13
  composeStories(stories)
14
14
 
15
15
  test("is drivable by role and name", async () => {
16
- const { canvas } = await mountStory(Default)
16
+ const { canvas } = await mountStory(Playground)
17
17
 
18
18
  expectAgentDrivable(canvas, {
19
19
  name: "Start rip",
@@ -16,7 +16,7 @@ cannot be middle-clicked, ctrl-clicked, opened in a new tab, or copied — and m
16
16
  solves the same problem in the other direction, with 14 raw `<a href="/…">` that force a
17
17
  full page reload through its own SPA router.
18
18
 
19
- <Canvas of={ButtonLinkStories.Default} />
19
+ <Canvas of={ButtonLinkStories.Playground} />
20
20
 
21
21
  ## Props
22
22
 
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
  import type { ReactNode } from "react"
3
4
 
@@ -77,7 +78,8 @@ export default meta
77
78
 
78
79
  type Story = StoryObj<typeof meta>
79
80
 
80
- export const Default: Story = {
81
+ export const Playground: Story = {
82
+ parameters: playgroundParameters,
81
83
  args: { children: "Configure" },
82
84
  }
83
85
 
@@ -14,7 +14,7 @@ const {
14
14
  AllStates,
15
15
  AllVariants,
16
16
  BesideAButton,
17
- Default,
17
+ Playground,
18
18
  External,
19
19
  Routed,
20
20
  } = composeStories(stories)
@@ -29,7 +29,7 @@ const {
29
29
  * whole argument.
30
30
  */
31
31
  test("is a link, not a button", async () => {
32
- const { canvas } = await mountStory(Default)
32
+ const { canvas } = await mountStory(Playground)
33
33
 
34
34
  const link = expectAgentDrivable(canvas, {
35
35
  name: "Configure",
@@ -51,7 +51,7 @@ test("is a link, not a button", async () => {
51
51
  })
52
52
 
53
53
  test("Tab reaches it", async () => {
54
- const { canvas } = await mountStory(Default)
54
+ const { canvas } = await mountStory(Playground)
55
55
 
56
56
  const link = canvas.getByRole("link", {
57
57
  name: "Configure",
package/src/Card/Card.mdx CHANGED
@@ -11,7 +11,7 @@ a **landmark**, so `getByRole("region", { name: "Bay 3" })` scopes every query i
11
11
  Without that, an agent driving a 16-bay tower sees sixteen identical "Start" buttons and no
12
12
  way to say which one it means. The `Interactive` story asserts exactly that.
13
13
 
14
- <Canvas of={CardStories.Default} />
14
+ <Canvas of={CardStories.Playground} />
15
15
 
16
16
  ## Props
17
17
 
@@ -35,6 +35,26 @@ all, deliberately — it has nothing to be named.
35
35
  `raised` means *more separated from base*, not *lighter*, which is why light mode's base is
36
36
  `#F5F7FA` and its raised is white.
37
37
 
38
+ ### A card the app names itself
39
+
40
+ Pass `aria-labelledby` and no `heading` when the app draws its own title row — a name beside
41
+ a count is one line that `heading` cannot express, so mail-sifter's tiles render it and point
42
+ at it. The card keeps that pointer.
43
+
44
+ > **It has to be a fallback, not a default.** The attribute is written after the caller's
45
+ > props are spread, so the obvious `heading ? headingId : undefined` **overwrites** the call
46
+ > site's pointer rather than leaving it alone. React then drops the attribute, the card's name
47
+ > falls back to its entire subtree, and nothing reports it: the markup is valid, the types are
48
+ > satisfied, and axe is content with a name made of everything. Both of mail-sifter's
49
+ > `role="button"` tiles announced their whole contents — "Recent Mail 6 40 arrived in the last
50
+ > 24 hours, 34 done" for a tile called "Recent Mail".
51
+
52
+ `heading` still wins where both are given, because the heading is text the reader can see and
53
+ this component renders it. `aria-label` needs no fallback at all — `Card` never writes one, so
54
+ the spread carries the caller's through.
55
+
56
+ <Canvas of={CardStories.CallerNamed} />
57
+
38
58
  <Canvas of={CardStories.AllVariants} />
39
59
 
40
60
  ## Container queries, not media queries
@@ -1,3 +1,4 @@
1
+ import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
1
2
  import type { Meta, StoryObj } from "@storybook/react"
2
3
 
3
4
  import { toStoryChoice } from "../argTypes.storyHelpers.ts"
@@ -43,7 +44,8 @@ export default meta
43
44
 
44
45
  type Story = StoryObj<typeof meta>
45
46
 
46
- export const Default: Story = {
47
+ export const Playground: Story = {
48
+ parameters: playgroundParameters,
47
49
  args: {
48
50
  children: (
49
51
  <p className="text-content-secondary text-sm">
@@ -296,3 +298,91 @@ export const AccentEdge: Story = {
296
298
  </StorySection>
297
299
  ),
298
300
  }
301
+
302
+ /**
303
+ * Ids for the two cells that point at their own text. Written out
304
+ * rather than generated, because a story is a static demo and the
305
+ * docs page mounts every cell at once — two cells sharing a
306
+ * generated id would be a duplicate-id violation nobody could see.
307
+ */
308
+ const CALLER_HEADING_ID = "card-caller-heading"
309
+ const SHADOWED_HEADING_ID = "card-shadowed-heading"
310
+
311
+ /**
312
+ * The card is named by a heading the **app** draws, not by
313
+ * `heading`.
314
+ *
315
+ * mail-sifter's tiles put the name and its count on one row, so they
316
+ * render the title themselves and pass `aria-labelledby` at the call
317
+ * site. `Card` writes that attribute after the caller's spread, so
318
+ * it has to fall back to the caller's pointer: without the fallback
319
+ * the attribute is overwritten with `undefined`, React drops it, and
320
+ * the tile's name becomes its whole subtree — "Recent Mail 6 40
321
+ * arrived in the last 24 hours, 34 done" instead of "Recent Mail".
322
+ * Nothing reports that: it renders, it typechecks, and axe is happy
323
+ * with a name made of everything.
324
+ *
325
+ * `heading` still wins where it is given, and `aria-label` needs no
326
+ * fallback at all — the component never writes one, so the spread
327
+ * carries it through.
328
+ */
329
+ export const CallerNamed: Story = {
330
+ args: { children: "Content" },
331
+ render: () => (
332
+ <StoryGrid columns={3}>
333
+ <StoryCell
334
+ align="stretch"
335
+ label="the call site's own pointer"
336
+ >
337
+ <Card aria-labelledby={CALLER_HEADING_ID}>
338
+ <div className="flex items-baseline justify-between gap-2">
339
+ <h2
340
+ className="font-semibold text-md leading-tight"
341
+ id={CALLER_HEADING_ID}
342
+ >
343
+ Recent Mail
344
+ </h2>
345
+
346
+ <Badge intent="info" size="sm">
347
+ 6
348
+ </Badge>
349
+ </div>
350
+
351
+ <p className="text-content-secondary text-sm">
352
+ 40 arrived in the last 24 hours, 34 done.
353
+ </p>
354
+ </Card>
355
+ </StoryCell>
356
+
357
+ <StoryCell
358
+ align="stretch"
359
+ label="a heading beats the pointer"
360
+ >
361
+ <Card
362
+ aria-labelledby={SHADOWED_HEADING_ID}
363
+ heading="Bay 5"
364
+ >
365
+ <p
366
+ className="text-content-secondary text-sm"
367
+ id={SHADOWED_HEADING_ID}
368
+ >
369
+ Pointed at, and deliberately not the name — the
370
+ heading is the text the reader can see.
371
+ </p>
372
+ </Card>
373
+ </StoryCell>
374
+
375
+ <StoryCell
376
+ align="stretch"
377
+ label="an aria-label passes through"
378
+ >
379
+ <Card aria-label="Unread mail">
380
+ <p className="text-content-secondary text-sm">
381
+ No heading and no pointer, so the card is named
382
+ by the label the call site set.
383
+ </p>
384
+ </Card>
385
+ </StoryCell>
386
+ </StoryGrid>
387
+ ),
388
+ }
@@ -6,11 +6,16 @@ import { mountStory } from "../mountStory.testHelpers.ts"
6
6
  import { expectAgentDrivable } from "../testing/index.ts"
7
7
  import * as stories from "./Card.stories.tsx"
8
8
 
9
- const { AccentEdge, AllStates, Default, Interactive } =
10
- composeStories(stories)
9
+ const {
10
+ AccentEdge,
11
+ AllStates,
12
+ CallerNamed,
13
+ Playground,
14
+ Interactive,
15
+ } = composeStories(stories)
11
16
 
12
17
  test("a heading turns the card into a named landmark", async () => {
13
- const { canvas } = await mountStory(Default)
18
+ const { canvas } = await mountStory(Playground)
14
19
 
15
20
  expectAgentDrivable(canvas, {
16
21
  name: "Bay 3",
@@ -29,6 +34,58 @@ test("a card with no heading is not a landmark", async () => {
29
34
  )
30
35
  })
31
36
 
37
+ /**
38
+ * The name the call site set is the fallback, and it is the half the
39
+ * component used to throw away.
40
+ *
41
+ * `aria-labelledby` is written after the caller's spread, so the old
42
+ * `heading ? headingId : undefined` overwrote the caller's pointer
43
+ * instead of deferring to it. A tile naming itself from a heading it
44
+ * draws lost its name and picked up its whole subtree — and this is
45
+ * the only gate that can see it, because the markup is valid, the
46
+ * types are satisfied, and a card named by everything is still a
47
+ * card with a name.
48
+ */
49
+ test("a card with no heading keeps the caller's own name", async () => {
50
+ const { canvas } = await mountStory(CallerNamed)
51
+
52
+ // Exactly "Recent Mail". Were the subtree naming it, this would be
53
+ // "Recent Mail 6 40 arrived in the last 24 hours, 34 done" and the
54
+ // query would match nothing.
55
+ expectAgentDrivable(canvas, {
56
+ name: "Recent Mail",
57
+ role: "region",
58
+ })
59
+ })
60
+
61
+ /**
62
+ * The fallback is a fallback, not a swap: a `heading` is text the
63
+ * reader can see and the component renders it, so it still wins.
64
+ */
65
+ test("a heading still names the card over the caller's pointer", async () => {
66
+ const { canvas } = await mountStory(CallerNamed)
67
+
68
+ expectAgentDrivable(canvas, {
69
+ name: "Bay 5",
70
+ role: "region",
71
+ })
72
+ })
73
+
74
+ /**
75
+ * `aria-label` needs no fallback — the component never writes one,
76
+ * so the spread carries the caller's through. Asserted anyway, so
77
+ * that a future "fix" which starts writing `aria-label` here cannot
78
+ * take the caller's with it the way this one took `aria-labelledby`.
79
+ */
80
+ test("a caller's aria-label reaches the card untouched", async () => {
81
+ const { canvas } = await mountStory(CallerNamed)
82
+
83
+ expectAgentDrivable(canvas, {
84
+ name: "Unread mail",
85
+ role: "region",
86
+ })
87
+ })
88
+
32
89
  /**
33
90
  * Two identical "Start rip" buttons on one page, disambiguated only
34
91
  * by the region each sits in.