@charcuterie/ui 4.4.0 → 4.5.1
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/README.md +7 -2
- package/dist/ActionTiles/ActionTiles.d.ts +2 -1
- package/dist/ActionTiles/ActionTiles.d.ts.map +1 -1
- package/dist/ActionTiles/ActionTiles.js +4 -2
- package/dist/ActionTiles/ActionTiles.js.map +1 -1
- package/dist/Card/Card.d.ts +5 -2
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +23 -3
- package/dist/Card/Card.js.map +1 -1
- package/package.json +3 -2
- package/src/Accordion/Accordion.mdx +1 -1
- package/src/Accordion/Accordion.stories.tsx +3 -1
- package/src/Accordion/Accordion.test.tsx +4 -4
- package/src/ActionTiles/ActionTiles.mdx +7 -1
- package/src/ActionTiles/ActionTiles.stories.tsx +3 -1
- package/src/ActionTiles/ActionTiles.test.tsx +3 -3
- package/src/ActionTiles/ActionTiles.tsx +4 -2
- package/src/AdaptiveGrid/AdaptiveGrid.mdx +1 -1
- package/src/AdaptiveGrid/AdaptiveGrid.stories.tsx +3 -1
- package/src/AdaptiveGrid/AdaptiveGrid.test.tsx +5 -5
- package/src/Alert/Alert.mdx +1 -1
- package/src/Alert/Alert.stories.tsx +3 -1
- package/src/Alert/Alert.test.tsx +2 -2
- package/src/Avatar/Avatar.mdx +1 -1
- package/src/Avatar/Avatar.stories.tsx +4 -1
- package/src/Avatar/Avatar.test.tsx +2 -2
- package/src/Badge/Badge.mdx +1 -1
- package/src/Badge/Badge.stories.tsx +3 -1
- package/src/Badge/Badge.test.tsx +3 -3
- package/src/BadgeButton/BadgeButton.mdx +1 -1
- package/src/BadgeButton/BadgeButton.stories.tsx +3 -1
- package/src/BadgeButton/BadgeButton.test.tsx +2 -2
- package/src/Board/Board.mdx +1 -1
- package/src/Board/Board.stories.tsx +4 -1
- package/src/Board/Board.test.tsx +2 -2
- package/src/Button/Button.mdx +1 -1
- package/src/Button/Button.stories.tsx +3 -1
- package/src/Button/Button.test.tsx +2 -2
- package/src/ButtonLink/ButtonLink.mdx +1 -1
- package/src/ButtonLink/ButtonLink.stories.tsx +3 -1
- package/src/ButtonLink/ButtonLink.test.tsx +3 -3
- package/src/Card/Card.mdx +21 -1
- package/src/Card/Card.stories.tsx +91 -1
- package/src/Card/Card.test.tsx +60 -3
- package/src/Card/Card.tsx +24 -2
- package/src/Checkbox/Checkbox.mdx +1 -1
- package/src/Checkbox/Checkbox.stories.tsx +3 -1
- package/src/Checkbox/Checkbox.test.tsx +4 -4
- package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.mdx +1 -1
- package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.stories.tsx +3 -1
- package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.test.tsx +5 -5
- package/src/ColorSchemeToggle/ColorSchemeToggle.mdx +1 -1
- package/src/ColorSchemeToggle/ColorSchemeToggle.stories.tsx +3 -1
- package/src/ColorSchemeToggle/ColorSchemeToggle.test.tsx +5 -5
- package/src/Combobox/Combobox.mdx +1 -1
- package/src/Combobox/Combobox.stories.tsx +3 -1
- package/src/Combobox/Combobox.test.tsx +2 -2
- package/src/CopyButton/CopyButton.mdx +1 -1
- package/src/CopyButton/CopyButton.stories.tsx +4 -1
- package/src/CopyButton/CopyButton.test.tsx +3 -3
- package/src/DataTable/DataTable.mdx +1 -1
- package/src/DataTable/DataTable.stories.tsx +3 -1
- package/src/DataTable/DataTable.test.tsx +3 -3
- package/src/DatePicker/DatePicker.mdx +1 -1
- package/src/DatePicker/DatePicker.stories.tsx +3 -1
- package/src/DatePicker/DatePicker.test.tsx +3 -3
- package/src/DatePicker/plainDate.test.ts +21 -3
- package/src/Dialog/Dialog.mdx +1 -1
- package/src/Dialog/Dialog.stories.tsx +3 -1
- package/src/Dialog/Dialog.test.tsx +2 -2
- package/src/DropRail/DropRail.mdx +1 -1
- package/src/DropRail/DropRail.stories.tsx +4 -1
- package/src/DropRail/DropRail.test.tsx +4 -4
- package/src/EmptyState/EmptyState.mdx +1 -1
- package/src/EmptyState/EmptyState.stories.tsx +3 -1
- package/src/EmptyState/EmptyState.test.tsx +2 -2
- package/src/Field/Field.mdx +1 -1
- package/src/Field/Field.stories.tsx +3 -1
- package/src/Field/Field.test.tsx +4 -4
- package/src/FileDropZone/FileDropZone.mdx +1 -1
- package/src/FileDropZone/FileDropZone.stories.tsx +3 -1
- package/src/FileDropZone/FileDropZone.test.tsx +3 -3
- package/src/Header/Header.mdx +1 -1
- package/src/Header/Header.stories.tsx +3 -1
- package/src/IconButton/IconButton.mdx +1 -1
- package/src/IconButton/IconButton.stories.tsx +3 -1
- package/src/IconButton/IconButton.test.tsx +2 -2
- package/src/Lightbox/Lightbox.mdx +1 -1
- package/src/Lightbox/Lightbox.stories.tsx +3 -1
- package/src/Lightbox/Lightbox.test.tsx +2 -2
- package/src/Listbox/Listbox.mdx +1 -1
- package/src/Listbox/Listbox.stories.tsx +3 -1
- package/src/Listbox/Listbox.test.tsx +5 -5
- package/src/LiveStatusIndicator/LiveStatusIndicator.mdx +1 -1
- package/src/LiveStatusIndicator/LiveStatusIndicator.stories.tsx +3 -1
- package/src/LiveStatusIndicator/LiveStatusIndicator.test.tsx +2 -2
- package/src/LogViewer/LogViewer.mdx +1 -1
- package/src/LogViewer/LogViewer.stories.tsx +3 -1
- package/src/LogViewer/LogViewer.test.tsx +2 -2
- package/src/Main/Main.mdx +1 -1
- package/src/Main/Main.stories.tsx +3 -1
- package/src/Main/Main.test.tsx +3 -3
- package/src/MarkdownEditor/MarkdownEditor.mdx +1 -1
- package/src/MarkdownEditor/MarkdownEditor.stories.tsx +3 -1
- package/src/MarkdownEditor/MarkdownEditor.test.tsx +4 -4
- package/src/MarkdownLine/MarkdownLine.mdx +1 -1
- package/src/MarkdownLine/MarkdownLine.stories.tsx +4 -1
- package/src/MarkdownLine/MarkdownLine.test.tsx +3 -3
- package/src/MediaTile/MediaTile.stories.tsx +3 -1
- package/src/MediaTile/MediaTile.test.tsx +2 -2
- package/src/Menu/Menu.mdx +1 -1
- package/src/Menu/Menu.stories.tsx +3 -1
- package/src/Modal/Modal.mdx +1 -1
- package/src/Modal/Modal.stories.tsx +3 -1
- package/src/Modal/Modal.test.tsx +3 -3
- package/src/Nav/Nav.mdx +1 -1
- package/src/Nav/Nav.stories.tsx +3 -1
- package/src/Nav/Nav.test.tsx +6 -6
- package/src/NavBar/NavBar.mdx +1 -1
- package/src/NavBar/NavBar.stories.tsx +3 -1
- package/src/NavBar/NavBar.test.tsx +3 -3
- package/src/Picker/Picker.mdx +1 -1
- package/src/Picker/Picker.stories.tsx +3 -1
- package/src/Picker/Picker.test.tsx +2 -2
- package/src/Popover/Popover.mdx +1 -1
- package/src/Popover/Popover.stories.tsx +3 -1
- package/src/Popover/Popover.test.tsx +2 -2
- package/src/PortraitTiles/PortraitTiles.mdx +1 -1
- package/src/PortraitTiles/PortraitTiles.stories.tsx +3 -1
- package/src/PortraitTiles/PortraitTiles.test.tsx +5 -5
- package/src/ProgressBar/ProgressBar.mdx +1 -1
- package/src/ProgressBar/ProgressBar.stories.tsx +3 -1
- package/src/ProgressBar/ProgressBar.test.tsx +2 -2
- package/src/QueryBuilder/QueryBuilder.mdx +1 -1
- package/src/QueryBuilder/QueryBuilder.stories.tsx +3 -1
- package/src/QueryBuilder/QueryBuilder.test.tsx +2 -2
- package/src/RadioGroup/RadioGroup.mdx +1 -1
- package/src/RadioGroup/RadioGroup.stories.tsx +3 -1
- package/src/RadioGroup/RadioGroup.test.tsx +2 -2
- package/src/Rail/Rail.mdx +1 -1
- package/src/Rail/Rail.stories.tsx +3 -1
- package/src/Rail/Rail.test.tsx +2 -2
- package/src/RangeSlider/RangeSlider.mdx +1 -1
- package/src/RangeSlider/RangeSlider.stories.tsx +3 -1
- package/src/RangeSlider/RangeSlider.test.tsx +7 -3
- package/src/ReorderList/ReorderList.mdx +1 -1
- package/src/ReorderList/ReorderList.stories.tsx +3 -1
- package/src/ReorderList/ReorderList.test.tsx +7 -7
- package/src/RouterLink/UnstyledLink.stories.tsx +4 -1
- package/src/RouterLink/UnstyledLink.test.tsx +2 -2
- package/src/SearchInput/SearchInput.mdx +1 -1
- package/src/SearchInput/SearchInput.stories.tsx +3 -1
- package/src/SegmentedControl/SegmentedControl.mdx +1 -1
- package/src/SegmentedControl/SegmentedControl.stories.tsx +3 -1
- package/src/SegmentedControl/SegmentedControl.test.tsx +2 -2
- package/src/Select/Select.mdx +1 -1
- package/src/Select/Select.stories.tsx +3 -1
- package/src/Select/Select.test.tsx +4 -4
- package/src/Shell/Shell.mdx +1 -1
- package/src/Shell/Shell.stories.tsx +3 -1
- package/src/Shell/Shell.test.tsx +2 -2
- package/src/Skeleton/Skeleton.mdx +1 -1
- package/src/Skeleton/Skeleton.stories.tsx +3 -1
- package/src/Skeleton/Skeleton.test.tsx +2 -2
- package/src/Slider/Slider.mdx +1 -1
- package/src/Slider/Slider.stories.tsx +3 -1
- package/src/Slider/Slider.test.tsx +2 -2
- package/src/SortableTableHeader/SortableTableHeader.mdx +1 -1
- package/src/SortableTableHeader/SortableTableHeader.stories.tsx +3 -1
- package/src/SortableTableHeader/SortableTableHeader.test.tsx +3 -3
- package/src/Spinner/Spinner.mdx +1 -1
- package/src/Spinner/Spinner.stories.tsx +3 -1
- package/src/Spinner/Spinner.test.tsx +2 -2
- package/src/Stepper/Stepper.mdx +1 -1
- package/src/Stepper/Stepper.stories.tsx +4 -1
- package/src/Stepper/Stepper.test.tsx +7 -7
- package/src/Swatch/Swatch.mdx +1 -1
- package/src/Swatch/Swatch.stories.tsx +4 -1
- package/src/Swatch/Swatch.test.tsx +3 -3
- package/src/Switch/Switch.mdx +1 -1
- package/src/Switch/Switch.stories.tsx +3 -1
- package/src/Switch/Switch.test.tsx +2 -2
- package/src/Tabs/Tabs.mdx +1 -1
- package/src/Tabs/Tabs.stories.tsx +3 -1
- package/src/Tabs/Tabs.test.tsx +3 -3
- package/src/TextLink/TextLink.mdx +1 -1
- package/src/TextLink/TextLink.stories.tsx +3 -1
- package/src/TextLink/TextLink.test.tsx +4 -4
- package/src/TimecodeInput/TimecodeInput.mdx +1 -1
- package/src/TimecodeInput/TimecodeInput.stories.tsx +3 -1
- package/src/Toast/Toast.mdx +1 -1
- package/src/Toast/Toast.stories.tsx +3 -1
- package/src/Toast/Toast.test.tsx +2 -2
- package/src/Toolbar/Toolbar.mdx +1 -1
- package/src/Toolbar/Toolbar.stories.tsx +3 -1
- package/src/Toolbar/Toolbar.test.tsx +5 -5
- package/src/Tooltip/Tooltip.mdx +1 -1
- package/src/Tooltip/Tooltip.stories.tsx +3 -1
- package/src/Tooltip/Tooltip.test.tsx +2 -2
- package/src/VirtualizedGrid/VirtualizedGrid.mdx +1 -1
- package/src/VirtualizedGrid/VirtualizedGrid.stories.tsx +4 -1
- package/src/VirtualizedGrid/VirtualizedGrid.test.tsx +5 -5
- package/src/VisuallyHidden/VisuallyHidden.mdx +1 -1
- package/src/VisuallyHidden/VisuallyHidden.stories.tsx +3 -1
- package/src/markdownEditorCodeMirror/MarkdownEditorCodeMirror.mdx +1 -1
- package/src/markdownEditorCodeMirror/MarkdownEditorCodeMirror.stories.tsx +3 -1
- package/src/markdownEditorCodeMirror/MarkdownEditorCodeMirror.test.tsx +3 -3
- package/src/markdownEditorCodeMirror/MarkdownView.mdx +1 -1
- package/src/markdownEditorCodeMirror/MarkdownView.stories.tsx +4 -1
- package/src/markdownEditorCodeMirror/MarkdownView.test.tsx +44 -20
- package/src/reactRouter/ReactRouterAdapter.stories.tsx +3 -1
- package/src/reactRouter/ReactRouterAdapter.test.tsx +2 -2
package/src/Board/Board.test.tsx
CHANGED
|
@@ -16,7 +16,7 @@ const {
|
|
|
16
16
|
AccentEdge,
|
|
17
17
|
AllStates,
|
|
18
18
|
CardMenuItems,
|
|
19
|
-
|
|
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(
|
|
191
|
+
const { canvas } = await mountStory(Playground)
|
|
192
192
|
|
|
193
193
|
await expect(
|
|
194
194
|
canvas.queryAllByRole("button", { name: /^Move / }),
|
package/src/Button/Button.mdx
CHANGED
|
@@ -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.
|
|
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
|
|
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,
|
|
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(
|
|
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.
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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.
|
|
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
|
|
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
|
+
}
|
package/src/Card/Card.test.tsx
CHANGED
|
@@ -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 {
|
|
10
|
-
|
|
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(
|
|
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.
|
package/src/Card/Card.tsx
CHANGED
|
@@ -83,7 +83,10 @@ const PADDING_CLASS: Record<CardPadding, string> = {
|
|
|
83
83
|
*
|
|
84
84
|
* `aria-labelledby` rather than `aria-label`, because the heading is
|
|
85
85
|
* on screen already and stating the name twice is how the two drift
|
|
86
|
-
* apart.
|
|
86
|
+
* apart. A card with **no** `heading` keeps the `aria-labelledby`
|
|
87
|
+
* the call site passed, for the app that draws its own title row
|
|
88
|
+
* inside the card — the name still points at text on screen, which
|
|
89
|
+
* is the same rule one level out.
|
|
87
90
|
*
|
|
88
91
|
* **Density is not a prop here.** mux-magic's inventory turned up a
|
|
89
92
|
* `CardDensityProvider` in the withdrawn bambuddy evidence, and it
|
|
@@ -94,6 +97,7 @@ const PADDING_CLASS: Record<CardPadding, string> = {
|
|
|
94
97
|
* a layout fact rather than a density one.
|
|
95
98
|
*/
|
|
96
99
|
export const Card = ({
|
|
100
|
+
"aria-labelledby": ariaLabelledBy,
|
|
97
101
|
accentEdge,
|
|
98
102
|
actions,
|
|
99
103
|
children,
|
|
@@ -122,12 +126,30 @@ export const Card = ({
|
|
|
122
126
|
? style
|
|
123
127
|
: { ...accentEdgeStyle, ...style }
|
|
124
128
|
|
|
129
|
+
// The caller's own pointer is the FALLBACK, not the loser. This
|
|
130
|
+
// attribute is written *after* the spread, so `undefined` here
|
|
131
|
+
// does not mean "leave whatever the call site passed": it
|
|
132
|
+
// overwrites it, React then drops the attribute entirely, and the
|
|
133
|
+
// card's accessible name falls back to its whole subtree with
|
|
134
|
+
// nothing failing — not typecheck, not axe, not a render. A
|
|
135
|
+
// `role="button"` tile in mail-sifter naming itself
|
|
136
|
+
// `aria-labelledby="recent-tile-heading"` announced as "Recent
|
|
137
|
+
// Mail 6 40 arrived in the last 24 hours, 34 done".
|
|
138
|
+
//
|
|
139
|
+
// `heading` still wins when it is given, because that is the name
|
|
140
|
+
// the reader can see and this component renders it. Do not
|
|
141
|
+
// "simplify" this back to a ternary ending in `undefined`.
|
|
142
|
+
//
|
|
143
|
+
// `aria-label` needs no equivalent: the component never writes
|
|
144
|
+
// one, so the spread carries the caller's through untouched.
|
|
145
|
+
const labelledById = heading ? headingId : ariaLabelledBy
|
|
146
|
+
|
|
125
147
|
const Heading = `h${headingLevel}` as const
|
|
126
148
|
|
|
127
149
|
return (
|
|
128
150
|
<section
|
|
129
151
|
{...sectionProps}
|
|
130
|
-
aria-labelledby={
|
|
152
|
+
aria-labelledby={labelledById}
|
|
131
153
|
className={toClassName(
|
|
132
154
|
// `@container` here, not on a wrapper, is what lets the
|
|
133
155
|
// header stack at narrow widths *inside a wide viewport* —
|
|
@@ -16,7 +16,7 @@ Here the box is `bg-surface-sunken`, its border `border-border-strong`, and the
|
|
|
16
16
|
the kiosk with no per-app override. `BooleanField` becomes a thin wrapper that binds this
|
|
17
17
|
to a `CommandField`.
|
|
18
18
|
|
|
19
|
-
<Canvas of={CheckboxStories.
|
|
19
|
+
<Canvas of={CheckboxStories.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 { controlSizeArgType } from "../argTypes.storyHelpers.ts"
|
|
@@ -29,7 +30,8 @@ export default meta
|
|
|
29
30
|
|
|
30
31
|
type Story = StoryObj<typeof meta>
|
|
31
32
|
|
|
32
|
-
export const
|
|
33
|
+
export const Playground: Story = {
|
|
34
|
+
parameters: playgroundParameters,
|
|
33
35
|
args: { label: "Delete originals after import" },
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -9,7 +9,7 @@ import * as stories from "./Checkbox.stories.tsx"
|
|
|
9
9
|
|
|
10
10
|
const {
|
|
11
11
|
AllStates,
|
|
12
|
-
|
|
12
|
+
Playground,
|
|
13
13
|
Interactive,
|
|
14
14
|
WithDescriptions,
|
|
15
15
|
WithValues,
|
|
@@ -17,7 +17,7 @@ const {
|
|
|
17
17
|
|
|
18
18
|
test("it is a checkbox a screen reader can name", async () => {
|
|
19
19
|
const { canvas, canvasElement } =
|
|
20
|
-
await mountStory(
|
|
20
|
+
await mountStory(Playground)
|
|
21
21
|
|
|
22
22
|
const checkbox = expectAgentDrivable(canvas, {
|
|
23
23
|
name: "Delete originals after import",
|
|
@@ -151,7 +151,7 @@ test("value names the member, and a group reads back the ticked ones", async ()
|
|
|
151
151
|
})
|
|
152
152
|
|
|
153
153
|
test("a box with no value stays out of the way", async () => {
|
|
154
|
-
const { canvas } = await mountStory(
|
|
154
|
+
const { canvas } = await mountStory(Playground)
|
|
155
155
|
|
|
156
156
|
// `value` is optional and a lone boolean should omit it. React drops
|
|
157
157
|
// an `undefined` attribute entirely rather than writing an empty
|
|
@@ -252,7 +252,7 @@ test("each box owns its own description, and the group owns the group's", async
|
|
|
252
252
|
})
|
|
253
253
|
|
|
254
254
|
test("a box with no description writes no aria-describedby", async () => {
|
|
255
|
-
const { canvas } = await mountStory(
|
|
255
|
+
const { canvas } = await mountStory(Playground)
|
|
256
256
|
|
|
257
257
|
// The slot is opt-in. React drops an `undefined` attribute rather
|
|
258
258
|
// than writing an empty string, so a box without a hint points at
|
|
@@ -12,7 +12,7 @@ the [`useColorScheme`](/) hook to the three defaults from `@charcuterie/logic/br
|
|
|
12
12
|
[`ColorSchemeToggle`](?path=/docs/components-colorschemetoggle--docs). Drop it in and the app
|
|
13
13
|
follows the OS, remembers the user's choice, and re-themes with zero React re-render.
|
|
14
14
|
|
|
15
|
-
<Canvas of={ColorSchemeSwitcherStories.
|
|
15
|
+
<Canvas of={ColorSchemeSwitcherStories.Playground} />
|
|
16
16
|
|
|
17
17
|
## Props
|
|
18
18
|
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
ColorSchemeResolver,
|
|
4
4
|
ResolvedColorScheme,
|
|
5
5
|
} from "@charcuterie/logic"
|
|
6
|
+
import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
|
|
6
7
|
import type { Meta, StoryObj } from "@storybook/react"
|
|
7
8
|
import { useRef, useState } from "react"
|
|
8
9
|
import type { ColorSchemeIcons } from "../ColorSchemeToggle/ColorSchemeToggle.tsx"
|
|
@@ -113,6 +114,7 @@ type Story = StoryObj<typeof meta>
|
|
|
113
114
|
* scoped to the demo panel, which is exactly how a non-browser host
|
|
114
115
|
* (Electron `nativeTheme`) wires it — by replacing those seams.
|
|
115
116
|
*/
|
|
116
|
-
export const
|
|
117
|
+
export const Playground: Story = {
|
|
118
|
+
parameters: playgroundParameters,
|
|
117
119
|
render: () => <ScopedSwitcherDemo />,
|
|
118
120
|
}
|
|
@@ -7,7 +7,7 @@ import { mountStory } from "../mountStory.testHelpers.ts"
|
|
|
7
7
|
import { expectAgentDrivable } from "../testing/index.ts"
|
|
8
8
|
import * as stories from "./ColorSchemeSwitcher.stories.tsx"
|
|
9
9
|
|
|
10
|
-
const {
|
|
10
|
+
const { Playground } = composeStories(stories)
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The connected switcher is agent-drivable and cycles like the
|
|
@@ -15,7 +15,7 @@ const { Default } = composeStories(stories)
|
|
|
15
15
|
* reaches the applier: the demo panel's `data-scheme` tracks it.
|
|
16
16
|
*/
|
|
17
17
|
test("it renders a named, drivable button", async () => {
|
|
18
|
-
const { canvas } = await mountStory(
|
|
18
|
+
const { canvas } = await mountStory(Playground)
|
|
19
19
|
|
|
20
20
|
expectAgentDrivable(canvas, {
|
|
21
21
|
name: /colour scheme/i,
|
|
@@ -24,7 +24,7 @@ test("it renders a named, drivable button", async () => {
|
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
test("system resolves through the injected resolver to the panel", async () => {
|
|
27
|
-
const { canvasElement } = await mountStory(
|
|
27
|
+
const { canvasElement } = await mountStory(Playground)
|
|
28
28
|
|
|
29
29
|
const panel = canvasElement.querySelector("[data-scheme]")
|
|
30
30
|
|
|
@@ -33,7 +33,7 @@ test("system resolves through the injected resolver to the panel", async () => {
|
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
test("cycling to a concrete mode re-applies the scheme", async () => {
|
|
36
|
-
const { canvasElement } = await mountStory(
|
|
36
|
+
const { canvasElement } = await mountStory(Playground)
|
|
37
37
|
|
|
38
38
|
const canvas = within(canvasElement)
|
|
39
39
|
|
|
@@ -53,7 +53,7 @@ test("cycling to a concrete mode re-applies the scheme", async () => {
|
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
test("the connected switcher forwards the neutral intent by default", async () => {
|
|
56
|
-
const { canvasElement } = await mountStory(
|
|
56
|
+
const { canvasElement } = await mountStory(Playground)
|
|
57
57
|
|
|
58
58
|
const button = canvasElement.querySelector("button")
|
|
59
59
|
|
|
@@ -16,7 +16,7 @@ That split is deliberate. The browser dependency lives one layer up in
|
|
|
16
16
|
runs unchanged in any runtime — a plain React app wires `onCycle` to `useState`, an Electron
|
|
17
17
|
or React-Native host wires it to `useColorScheme` with its own resolver.
|
|
18
18
|
|
|
19
|
-
<Canvas of={ColorSchemeToggleStories.
|
|
19
|
+
<Canvas of={ColorSchemeToggleStories.Playground} />
|
|
20
20
|
|
|
21
21
|
## Props
|
|
22
22
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ColorSchemeMode } from "@charcuterie/logic"
|
|
2
|
+
import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
|
|
2
3
|
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
4
|
import { useState } from "react"
|
|
4
5
|
|
|
@@ -71,7 +72,8 @@ type Story = StoryObj<typeof meta>
|
|
|
71
72
|
* The accessible name states the current mode and the next one, so
|
|
72
73
|
* it changes as the button cycles — that is what the test asserts.
|
|
73
74
|
*/
|
|
74
|
-
export const
|
|
75
|
+
export const Playground: Story = {
|
|
76
|
+
parameters: playgroundParameters,
|
|
75
77
|
render: (toggleProps) => {
|
|
76
78
|
const [mode, setMode] =
|
|
77
79
|
useState<ColorSchemeMode>("system")
|
|
@@ -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 "./ColorSchemeToggle.stories.tsx"
|
|
12
12
|
|
|
13
|
-
const { AllModes,
|
|
13
|
+
const { AllModes, Playground } = composeStories(stories)
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* The name states the current mode — a screen reader that lands on
|
|
@@ -18,7 +18,7 @@ const { AllModes, Default } = composeStories(stories)
|
|
|
18
18
|
* and an agent can find it.
|
|
19
19
|
*/
|
|
20
20
|
test("the toggle is named for its current mode", async () => {
|
|
21
|
-
const { canvas } = await mountStory(
|
|
21
|
+
const { canvas } = await mountStory(Playground)
|
|
22
22
|
|
|
23
23
|
expectAgentDrivable(canvas, {
|
|
24
24
|
name: /colour scheme: system/i,
|
|
@@ -27,7 +27,7 @@ test("the toggle is named for its current mode", async () => {
|
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
test("a press cycles the mode and updates the name", async () => {
|
|
30
|
-
const { canvas } = await mountStory(
|
|
30
|
+
const { canvas } = await mountStory(Playground)
|
|
31
31
|
|
|
32
32
|
const button = expectAgentDrivable(canvas, {
|
|
33
33
|
name: /colour scheme: system/i,
|
|
@@ -53,7 +53,7 @@ test("a press cycles the mode and updates the name", async () => {
|
|
|
53
53
|
|
|
54
54
|
test("the icon is hidden from assistive tech; the name carries it", async () => {
|
|
55
55
|
const { canvas, canvasElement } =
|
|
56
|
-
await mountStory(
|
|
56
|
+
await mountStory(Playground)
|
|
57
57
|
|
|
58
58
|
expectAgentDrivable(canvas, {
|
|
59
59
|
name: /colour scheme/i,
|
|
@@ -90,7 +90,7 @@ test("each mode renders its own control", async () => {
|
|
|
90
90
|
* action on real app chrome.
|
|
91
91
|
*/
|
|
92
92
|
test("defaults to the neutral intent, not accent", async () => {
|
|
93
|
-
const { canvasElement } = await mountStory(
|
|
93
|
+
const { canvasElement } = await mountStory(Playground)
|
|
94
94
|
|
|
95
95
|
const button = canvasElement.querySelector("button")
|
|
96
96
|
|
|
@@ -13,7 +13,7 @@ Use it when the list is long enough to search or filter; reach for
|
|
|
13
13
|
[`Listbox`](?path=/docs/components-listbox--docs) for a short rich-option list, and the
|
|
14
14
|
native [`Select`](?path=/docs/components-select--docs) for a plain one.
|
|
15
15
|
|
|
16
|
-
<Canvas of={ComboboxStories.
|
|
16
|
+
<Canvas of={ComboboxStories.Playground} />
|
|
17
17
|
|
|
18
18
|
## Props
|
|
19
19
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useVisibility } from "@charcuterie/logic"
|
|
2
|
+
import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
|
|
2
3
|
import type { ControlSize } from "@charcuterie/tokens"
|
|
3
4
|
import type { Meta, StoryObj } from "@storybook/react"
|
|
4
5
|
import type { ReactNode } from "react"
|
|
@@ -150,7 +151,8 @@ const ComboboxHarness = ({
|
|
|
150
151
|
)
|
|
151
152
|
}
|
|
152
153
|
|
|
153
|
-
export const
|
|
154
|
+
export const Playground: Story = {
|
|
155
|
+
parameters: playgroundParameters,
|
|
154
156
|
args: {
|
|
155
157
|
isVisible: false,
|
|
156
158
|
onDismiss: () => {},
|
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
AllVariants,
|
|
12
12
|
AttachedInputDrillDown,
|
|
13
13
|
ChosenValueOnOpen,
|
|
14
|
-
|
|
14
|
+
Playground,
|
|
15
15
|
DisabledFirstOption,
|
|
16
16
|
Interactive,
|
|
17
17
|
LongFooter,
|
|
@@ -42,7 +42,7 @@ const openMulti = async () => {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const openDefault = async () => {
|
|
45
|
-
const mounted = await mountStory(
|
|
45
|
+
const mounted = await mountStory(Playground)
|
|
46
46
|
|
|
47
47
|
await userEvent.click(
|
|
48
48
|
expectAgentDrivable(mounted.canvas, {
|
|
@@ -9,7 +9,7 @@ import * as CopyButtonStories from "./CopyButton.stories";
|
|
|
9
9
|
**A button that puts a string on the clipboard and says so.** Press it, the label turns to
|
|
10
10
|
`Copied`, and the caller is told whether that is true.
|
|
11
11
|
|
|
12
|
-
<Canvas of={CopyButtonStories.
|
|
12
|
+
<Canvas of={CopyButtonStories.Playground} />
|
|
13
13
|
|
|
14
14
|
## Props
|
|
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 { userEvent, within } from "storybook/test"
|
|
3
4
|
|
|
@@ -29,7 +30,9 @@ export default meta
|
|
|
29
30
|
|
|
30
31
|
type Story = StoryObj<typeof meta>
|
|
31
32
|
|
|
32
|
-
export const
|
|
33
|
+
export const Playground: Story = {
|
|
34
|
+
parameters: playgroundParameters,
|
|
35
|
+
}
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* The confirmation, held open. `confirmDuration` is enormous here so
|