@recursica/adapter-mantine-v8 1.3.4 → 1.3.6

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 (60) hide show
  1. package/.storybook/commonArgTypes.ts +148 -0
  2. package/CHANGELOG.md +12 -0
  3. package/package.json +2 -2
  4. package/src/Introduction.stories.tsx +149 -0
  5. package/src/components/Accordion/Accordion.stories.tsx +189 -0
  6. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +68 -0
  7. package/src/components/AutoComplete/AutoComplete.stories.tsx +336 -0
  8. package/src/components/Avatar/Avatar.stories.tsx +92 -0
  9. package/src/components/Badge/Badge.stories.tsx +78 -0
  10. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +114 -0
  11. package/src/components/Button/Button.stories.tsx +192 -0
  12. package/src/components/Card/Card.stories.tsx +76 -0
  13. package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +4 -0
  14. package/src/components/Checkbox/Checkbox.stories.tsx +97 -0
  15. package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
  16. package/src/components/Chip/Chip.stories.tsx +128 -0
  17. package/src/components/Container/Container.stories.tsx +118 -0
  18. package/src/components/DatePicker/DatePicker.stories.tsx +158 -0
  19. package/src/components/Dropdown/Dropdown.stories.tsx +252 -0
  20. package/src/components/FileInput/FileInput.stories.tsx +313 -0
  21. package/src/components/FileUpload/FileUpload.stories.tsx +362 -0
  22. package/src/components/Flex/Flex.stories.tsx +128 -0
  23. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +118 -0
  24. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +129 -0
  25. package/src/components/Group/Group.stories.tsx +120 -0
  26. package/src/components/Heading/Heading.stories.tsx +112 -0
  27. package/src/components/HoverCard/HoverCard.stories.tsx +172 -0
  28. package/src/components/Label/Label.stories.tsx +131 -0
  29. package/src/components/LayoutGrid/LayoutGrid.stories.tsx +61 -0
  30. package/src/components/Link/Link.stories.tsx +58 -0
  31. package/src/components/Loader/Loader.stories.tsx +123 -0
  32. package/src/components/Menu/Menu.stories.tsx +370 -0
  33. package/src/components/Modal/Modal.stories.tsx +105 -0
  34. package/src/components/NativeInputA11y.dom.test.tsx +60 -0
  35. package/src/components/NumberInput/NumberInput.stories.tsx +96 -0
  36. package/src/components/Pagination/Pagination.stories.tsx +48 -0
  37. package/src/components/Panel/Panel.stories.tsx +219 -0
  38. package/src/components/Popover/Popover.stories.tsx +133 -0
  39. package/src/components/Radio/RADIO_IMPLEMENTATION_NOTES.md +5 -0
  40. package/src/components/Radio/Radio.stories.tsx +93 -0
  41. package/src/components/Radio/RadioGroup.stories.tsx +117 -0
  42. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +163 -0
  43. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +106 -0
  44. package/src/components/Slider/Slider.stories.tsx +282 -0
  45. package/src/components/Stack/Stack.stories.tsx +108 -0
  46. package/src/components/Stepper/Stepper.stories.tsx +148 -0
  47. package/src/components/Switch/SWITCH_IMPLEMENTATION_NOTES.md +4 -0
  48. package/src/components/Switch/Switch.stories.tsx +114 -0
  49. package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
  50. package/src/components/Table/Table.stories.tsx +140 -0
  51. package/src/components/Tabs/Tabs.stories.tsx +154 -0
  52. package/src/components/Text/Text.stories.tsx +148 -0
  53. package/src/components/TextArea/TextArea.stories.tsx +94 -0
  54. package/src/components/TextField/TextField.stories.tsx +162 -0
  55. package/src/components/TimePicker/TimePicker.stories.tsx +141 -0
  56. package/src/components/Timeline/Timeline.stories.tsx +128 -0
  57. package/src/components/Toast/Toast.stories.tsx +67 -0
  58. package/src/components/Tooltip/Tooltip.stories.tsx +165 -0
  59. package/src/components/TransferList/TransferList.stories.tsx +121 -0
  60. package/src/components/Tree/Tree.stories.tsx +104 -0
@@ -0,0 +1,128 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { Flex } from "./Flex";
4
+ import { Button } from "../Button";
5
+ import { Text } from "../Text/Text";
6
+
7
+ type FlexStoryProps = React.ComponentProps<typeof Flex>;
8
+
9
+ const meta: Meta<FlexStoryProps> = {
10
+ title: "UI-Kit/Flex",
11
+ component: Flex,
12
+ tags: ["autodocs"],
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component:
17
+ "Flex is a bare-metal flex container that maps directly to Mantine's Flex component, providing unopinionated control over direction, alignment, and wrapping.",
18
+ },
19
+ },
20
+ },
21
+ args: {
22
+ gap: "rec-default",
23
+ align: "center",
24
+ justify: "flex-start",
25
+ direction: "row",
26
+ wrap: "wrap",
27
+ },
28
+ argTypes: {
29
+ gap: {
30
+ control: "select",
31
+ options: [
32
+ "rec-none",
33
+ "rec-sm",
34
+ "rec-default",
35
+ "rec-md",
36
+ "rec-lg",
37
+ "rec-xl",
38
+ "rec-2xl",
39
+ "xs",
40
+ "sm",
41
+ "md",
42
+ "lg",
43
+ "xl",
44
+ ],
45
+ description: "Gap between elements",
46
+ },
47
+ direction: {
48
+ control: "select",
49
+ options: ["row", "column", "row-reverse", "column-reverse"],
50
+ description: "Flex-direction property",
51
+ },
52
+ align: {
53
+ control: "select",
54
+ options: ["flex-start", "center", "flex-end", "stretch"],
55
+ description: "Align-items property",
56
+ },
57
+ justify: {
58
+ control: "select",
59
+ options: [
60
+ "flex-start",
61
+ "center",
62
+ "flex-end",
63
+ "space-between",
64
+ "space-around",
65
+ ],
66
+ description: "Justify-content property",
67
+ },
68
+ wrap: {
69
+ control: "select",
70
+ options: ["wrap", "nowrap", "wrap-reverse"],
71
+ description: "Flex-wrap property",
72
+ },
73
+ defaultChecked: {
74
+ table: { disable: true },
75
+ },
76
+ rowGap: {
77
+ table: { disable: true },
78
+ },
79
+ columnGap: {
80
+ table: { disable: true },
81
+ },
82
+ },
83
+ };
84
+
85
+ export default meta;
86
+
87
+ type Story = StoryObj<FlexStoryProps>;
88
+
89
+ export const Default: Story = {
90
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
91
+ render: ({ withLayer, layer, ...args }: any) => (
92
+ <Flex {...args}>
93
+ <Button variant="solid">Block A</Button>
94
+ <Button variant="outline">Block B</Button>
95
+ <Text>Text inside Flex</Text>
96
+ </Flex>
97
+ ),
98
+ };
99
+
100
+ export const StaticGapSmallColumn: Story = {
101
+ args: {
102
+ gap: "rec-sm",
103
+ direction: "column",
104
+ },
105
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
106
+ render: ({ withLayer, layer, ...args }: any) => (
107
+ <Flex {...args}>
108
+ <Button variant="solid">Item 1</Button>
109
+ <Button variant="solid">Item 2</Button>
110
+ <Button variant="solid">Item 3</Button>
111
+ </Flex>
112
+ ),
113
+ };
114
+
115
+ export const StaticGapLargeRow: Story = {
116
+ args: {
117
+ gap: "rec-xl",
118
+ direction: "row",
119
+ },
120
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
121
+ render: ({ withLayer, layer, ...args }: any) => (
122
+ <Flex {...args}>
123
+ <Button variant="solid">Item 1</Button>
124
+ <Button variant="solid">Item 2</Button>
125
+ <Button variant="solid">Item 3</Button>
126
+ </Flex>
127
+ ),
128
+ };
@@ -0,0 +1,118 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { FormControlLayout } from "./FormControlLayout";
3
+ import { Switch } from "../Switch/Switch";
4
+ import { Label } from "../Label/Label";
5
+
6
+ const meta: Meta<typeof FormControlLayout> = {
7
+ title: "UI-Kit/FormControlLayout",
8
+ component: FormControlLayout,
9
+ parameters: {
10
+ layout: "padded",
11
+ docs: {
12
+ description: {
13
+ component:
14
+ "A layout component used to correctly position form inputs alongside their labels.\n\n**When to use this:**\nTypically, you should use `FormControlWrapper` instead, which uses this component under the hood to handle layout automatically.\n\nHowever, this component is useful when you need to align standalone inputs (like a `Switch` or `Checkbox` without a label) so they perfectly match the spacing and alignment of your other form fields in a `side-by-side` layout.",
15
+ },
16
+ },
17
+ },
18
+ tags: ["autodocs"],
19
+ argTypes: {
20
+ formLayout: {
21
+ control: "radio",
22
+ options: ["stacked", "side-by-side"],
23
+ },
24
+ labelSize: {
25
+ control: "radio",
26
+ options: ["default", "small"],
27
+ description: "Dictates the physical width of the left column.",
28
+ },
29
+ children: {
30
+ table: { disable: true },
31
+ },
32
+ leftSection: {
33
+ table: { disable: true },
34
+ },
35
+ },
36
+ };
37
+
38
+ export default meta;
39
+ type Story = StoryObj<typeof FormControlLayout>;
40
+
41
+ /**
42
+ * The Default layout demonstrates wrapping a standalone primitive without a Label.
43
+ * In a stacked layout, an omitted leftSection naturally results in no structural padding.
44
+ */
45
+ export const Default: Story = {
46
+ args: {
47
+ formLayout: "stacked",
48
+ labelSize: "default",
49
+ leftSection: (
50
+ <div
51
+ style={{ padding: 8, border: "1px dashed #ccc", background: "#fafafa" }}
52
+ >
53
+ Left Section Boundary
54
+ </div>
55
+ ),
56
+ children: <Switch label="Input area content" />,
57
+ },
58
+ };
59
+
60
+ /**
61
+ * Demonstrates the stacked layout without a left section.
62
+ * The input should natively pull flush to the top left since there is no left column.
63
+ */
64
+ export const StackedLayout: Story = {
65
+ args: {
66
+ formLayout: "stacked",
67
+ labelSize: "default",
68
+ children: <Switch label="Flush stacked switch" />,
69
+ },
70
+ };
71
+
72
+ /**
73
+ * Demonstrates how a naked boolean primitive perfectly aligns in a side-by-side layout
74
+ * by utilizing the layout wrapper. The left column maintains its precise design system width
75
+ * even when `leftSection` is undefined, forcing the component into the correct form column!
76
+ */
77
+ export const SideBySideLayout: Story = {
78
+ args: {
79
+ formLayout: "side-by-side",
80
+ labelSize: "default",
81
+ children: <Switch label="Offset switch aligning with grid" />,
82
+ },
83
+ };
84
+
85
+ /**
86
+ * A real Label (not a placeholder) in a stacked layout, at `labelSize="default"`. Even
87
+ * though the label sits above the field rather than beside it, its own column still caps
88
+ * to the design system's stacked-layout width (224px) rather than stretching to the full
89
+ * container — long label text wraps instead of spanning edge-to-edge.
90
+ */
91
+ export const StackedLayoutWithLabelDefault: Story = {
92
+ args: {
93
+ formLayout: "stacked",
94
+ labelSize: "default",
95
+ leftSection: (
96
+ <Label labelSize="default">
97
+ A fairly long label to show the stacked-layout width cap in action
98
+ </Label>
99
+ ),
100
+ children: <Switch label="Input area content" />,
101
+ },
102
+ };
103
+
104
+ /**
105
+ * Same as above, at `labelSize="small"` — the stacked-layout width cap is narrower (80px).
106
+ */
107
+ export const StackedLayoutWithLabelSmall: Story = {
108
+ args: {
109
+ formLayout: "stacked",
110
+ labelSize: "small",
111
+ leftSection: (
112
+ <Label labelSize="small">
113
+ A fairly long label to show the stacked-layout width cap in action
114
+ </Label>
115
+ ),
116
+ children: <Switch label="Input area content" />,
117
+ },
118
+ };
@@ -0,0 +1,129 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ FormControlWrapper,
4
+ type FormControlWrapperProps,
5
+ } from "./FormControlWrapper";
6
+ import { TextField } from "../TextField/TextField";
7
+ import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
8
+
9
+ type WrapperStoryProps = FormControlWrapperProps;
10
+
11
+ const meta: Meta<WrapperStoryProps> = {
12
+ title: "UI-Kit/FormControlWrapper",
13
+ component: FormControlWrapper,
14
+ tags: ["autodocs"],
15
+ parameters: {
16
+ docs: {
17
+ description: {
18
+ component:
19
+ "The `FormControlWrapper` is the ultimate structural replacement for Mantine's built-in `Input.Wrapper`. By abandoning Mantine's opinionated wrappers entirely, we centralize all label tracking, error rendering, ARIA generation, and grid layouts natively inside this single component.\n\n### Usage with Naked Primitives\nThis component wraps 'naked' elements like `<Input>` directly. The demonstration stories below utilize `<TextField>` as a native display vehicle, since `<TextField>` natively pipes all its properties structurally back into this wrapper.",
20
+ },
21
+ },
22
+ },
23
+ argTypes: {
24
+ ...formControlArgTypes,
25
+ error: {
26
+ control: "text",
27
+ description:
28
+ "Error string driving native assistive component and validation markers.",
29
+ },
30
+ assistiveText: {
31
+ control: "text",
32
+ description:
33
+ "Helper instructions safely dynamically anchored below the input box.",
34
+ },
35
+ assistiveWithIcon: {
36
+ control: "boolean",
37
+ },
38
+ required: {
39
+ control: "boolean",
40
+ },
41
+ },
42
+ };
43
+
44
+ export default meta;
45
+
46
+ type Story = StoryObj<WrapperStoryProps>;
47
+
48
+ const renderWithTextField = (args: WrapperStoryProps) => (
49
+ // We explicitly cast args to 'any' here because Mantine enforces strict anatomy types for
50
+ // 'classNames', 'styles', and 'attributes'. WrapperStoryProps defines these for the Wrapper anatomy,
51
+ // but TextField expects them for the full TextInput anatomy, causing a TS intersection mismatch.
52
+ <TextField
53
+ placeholder="Form Control primitive mapped..."
54
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ {...(args as any)}
56
+ />
57
+ );
58
+
59
+ export const Default: Story = {
60
+ args: {
61
+ label: "Account Username",
62
+ formLayout: "stacked",
63
+ assistiveText: "Validation occurs immediately natively.",
64
+ },
65
+ render: renderWithTextField,
66
+ };
67
+
68
+ export const VisualErrorState: Story = {
69
+ args: {
70
+ label: "Encryption Protocol",
71
+ formLayout: "stacked",
72
+ error: "Strict validation limits reached. Handshake rejected securely.",
73
+ },
74
+ render: renderWithTextField,
75
+ };
76
+
77
+ export const RequiredArchitecture: Story = {
78
+ args: {
79
+ label: "Root Password",
80
+ formLayout: "side-by-side",
81
+ required: true,
82
+ assistiveText: "Bypass string structure required to initiate protocol.",
83
+ },
84
+ render: renderWithTextField,
85
+ };
86
+
87
+ export const WithoutAssistiveIcons: Story = {
88
+ args: {
89
+ label: "Server Domain",
90
+ assistiveText:
91
+ "A standard text boundary without default native icon parameters bounding.",
92
+ assistiveWithIcon: false,
93
+ },
94
+ render: renderWithTextField,
95
+ };
96
+
97
+ export const NativeChildrenDirectly: Story = {
98
+ parameters: {
99
+ docs: {
100
+ description: {
101
+ story:
102
+ "Bypassing the TextField map to show exactly how native `<input>` hooks execute inside the raw wrapper natively perfectly.",
103
+ },
104
+ },
105
+ },
106
+ args: {
107
+ label: "Raw HTML Checkbox",
108
+ formLayout: "side-by-side",
109
+ assistiveText: "This wraps a raw HTML input tag mapping correctly.",
110
+ },
111
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
112
+ render: ({ withLayer, layer, ...args }: any) => (
113
+ <div
114
+ style={{
115
+ display: "flex",
116
+ gap: "10px",
117
+ alignItems: "center",
118
+ }}
119
+ >
120
+ {/* We can cleanly wrap even un-styled HTML primitives! */}
121
+ <FormControlWrapper {...args}>
122
+ <input
123
+ type="checkbox"
124
+ style={{ margin: 0, width: "16px", height: "16px" }}
125
+ />
126
+ </FormControlWrapper>
127
+ </div>
128
+ ),
129
+ };
@@ -0,0 +1,120 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { Group } from "./Group";
4
+ import { Button } from "../Button";
5
+ import { Text } from "../Text/Text";
6
+
7
+ type GroupStoryProps = React.ComponentProps<typeof Group>;
8
+
9
+ const meta: Meta<GroupStoryProps> = {
10
+ title: "UI-Kit/Group",
11
+ component: Group,
12
+ tags: ["autodocs"],
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component:
17
+ "Group is a flex horizontal layout container that maps directly to Mantine's Group component allowing safe layout property passing.",
18
+ },
19
+ },
20
+ },
21
+ args: {
22
+ gap: "rec-default",
23
+ align: "center",
24
+ justify: "flex-start",
25
+ wrap: "wrap",
26
+ },
27
+ argTypes: {
28
+ gap: {
29
+ control: "select",
30
+ options: [
31
+ "rec-none",
32
+ "rec-sm",
33
+ "rec-default",
34
+ "rec-md",
35
+ "rec-lg",
36
+ "rec-xl",
37
+ "rec-2xl",
38
+ "xs",
39
+ "sm",
40
+ "md",
41
+ "lg",
42
+ "xl",
43
+ ],
44
+ description: "Gap between elements",
45
+ },
46
+ align: {
47
+ control: "select",
48
+ options: ["flex-start", "center", "flex-end", "stretch"],
49
+ description: "Align-items property",
50
+ },
51
+ justify: {
52
+ control: "select",
53
+ options: [
54
+ "flex-start",
55
+ "center",
56
+ "flex-end",
57
+ "space-between",
58
+ "space-around",
59
+ ],
60
+ description: "Justify-content property",
61
+ },
62
+ wrap: {
63
+ control: "select",
64
+ options: ["wrap", "nowrap", "wrap-reverse"],
65
+ description: "Flex-wrap property",
66
+ },
67
+ defaultChecked: {
68
+ table: { disable: true },
69
+ },
70
+ rowGap: {
71
+ table: { disable: true },
72
+ },
73
+ columnGap: {
74
+ table: { disable: true },
75
+ },
76
+ },
77
+ };
78
+
79
+ export default meta;
80
+
81
+ type Story = StoryObj<GroupStoryProps>;
82
+
83
+ export const Default: Story = {
84
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
85
+ render: ({ withLayer, layer, ...args }: any) => (
86
+ <Group {...args}>
87
+ <Button variant="solid">Primary</Button>
88
+ <Button variant="outline">Secondary</Button>
89
+ <Text>Text element within Group</Text>
90
+ </Group>
91
+ ),
92
+ };
93
+
94
+ export const StaticGapSmall: Story = {
95
+ args: {
96
+ gap: "rec-sm",
97
+ },
98
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
99
+ render: ({ withLayer, layer, ...args }: any) => (
100
+ <Group {...args}>
101
+ <Button variant="solid">Item 1</Button>
102
+ <Button variant="solid">Item 2</Button>
103
+ <Button variant="solid">Item 3</Button>
104
+ </Group>
105
+ ),
106
+ };
107
+
108
+ export const StaticGapLarge: Story = {
109
+ args: {
110
+ gap: "rec-xl",
111
+ },
112
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
113
+ render: ({ withLayer, layer, ...args }: any) => (
114
+ <Group {...args}>
115
+ <Button variant="solid">Item 1</Button>
116
+ <Button variant="solid">Item 2</Button>
117
+ <Button variant="solid">Item 3</Button>
118
+ </Group>
119
+ ),
120
+ };
@@ -0,0 +1,112 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Heading } from "./Heading";
3
+
4
+ const meta: Meta<typeof Heading> = {
5
+ title: "UI-Kit/Heading",
6
+ component: Heading,
7
+ tags: ["autodocs"],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component:
12
+ "The semantic `<Heading>` abstraction intrinsically links pure `h1-h6` tag generation with exact Recursica design boundaries to preserve SEO and screen reader trees uniformly globally.",
13
+ },
14
+ },
15
+ },
16
+ argTypes: {
17
+ order: {
18
+ control: "select",
19
+ options: [1, 2, 3, 4, 5, 6],
20
+ description:
21
+ "Controls the `h` tag and the resultant typographical weighting natively mapped to Recursica.",
22
+ },
23
+ color: {
24
+ control: "select",
25
+ options: ["default", "warning", "alert", "success"],
26
+ description:
27
+ "Semantic text color, bound to the active layer's text-element tokens via `data-color`.",
28
+ },
29
+ emphasis: {
30
+ control: "inline-radio",
31
+ options: ["high", "low"],
32
+ description:
33
+ "Emphasis level, bound to the theme's text-emphasis opacity tokens via `data-emphasis`.",
34
+ },
35
+ },
36
+ };
37
+
38
+ export default meta;
39
+
40
+ type Story = StoryObj<typeof Heading>;
41
+
42
+ export const Default: Story = {
43
+ args: {
44
+ order: 1,
45
+ children: "Semantic H1 Document Boundary",
46
+ },
47
+ render: ({ ...args }) => <Heading {...args} />,
48
+ };
49
+
50
+ export const StaticVariations: Story = {
51
+ args: {},
52
+ render: () => (
53
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
54
+ <Heading order={1}>H1 Heading</Heading>
55
+ <Heading order={2}>H2 Heading</Heading>
56
+ <Heading order={3}>H3 Heading</Heading>
57
+ <Heading order={4}>H4 Heading</Heading>
58
+ <Heading order={5}>H5 Heading</Heading>
59
+ <Heading order={6}>H6 Heading</Heading>
60
+ </div>
61
+ ),
62
+ };
63
+
64
+ export const Colors: Story = {
65
+ args: {},
66
+ parameters: {
67
+ docs: {
68
+ description: {
69
+ story:
70
+ "Semantic colors map to the active layer's text-element tokens. `default` follows the layer's base text color; `warning`, `alert`, and `success` pull their respective semantic tones.",
71
+ },
72
+ },
73
+ },
74
+ render: () => (
75
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
76
+ <Heading order={2} color="default">
77
+ Default heading
78
+ </Heading>
79
+ <Heading order={2} color="warning">
80
+ Warning heading
81
+ </Heading>
82
+ <Heading order={2} color="alert">
83
+ Alert heading
84
+ </Heading>
85
+ <Heading order={2} color="success">
86
+ Success heading
87
+ </Heading>
88
+ </div>
89
+ ),
90
+ };
91
+
92
+ export const Emphasis: Story = {
93
+ args: {},
94
+ parameters: {
95
+ docs: {
96
+ description: {
97
+ story:
98
+ "Emphasis controls text opacity via the theme's text-emphasis tokens. `high` (the default) is solid; `low` dims the heading for secondary content.",
99
+ },
100
+ },
101
+ },
102
+ render: () => (
103
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
104
+ <Heading order={2} emphasis="high">
105
+ High emphasis heading
106
+ </Heading>
107
+ <Heading order={2} emphasis="low">
108
+ Low emphasis heading
109
+ </Heading>
110
+ </div>
111
+ ),
112
+ };