@nationaldesignstudio/react 0.5.2 → 0.5.4

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 (161) hide show
  1. package/package.json +10 -2
  2. package/src/components/organisms/navbar/navbar.tsx +8 -8
  3. package/src/App.css +0 -0
  4. package/src/App.tsx +0 -7
  5. package/src/assets/fonts/PPNeueMontreal-Variable.woff2 +0 -0
  6. package/src/assets/react.svg +0 -1
  7. package/src/components/atoms/accordion/accordion.stories.tsx +0 -228
  8. package/src/components/atoms/accordion/accordion.test.tsx +0 -231
  9. package/src/components/atoms/accordion/index.ts +0 -6
  10. package/src/components/atoms/background/background.test.tsx +0 -213
  11. package/src/components/atoms/background/index.ts +0 -22
  12. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-darwin.png +0 -0
  13. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-linux.png +0 -0
  14. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-darwin.png +0 -0
  15. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-linux.png +0 -0
  16. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-darwin.png +0 -0
  17. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-linux.png +0 -0
  18. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-darwin.png +0 -0
  19. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-linux.png +0 -0
  20. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-darwin.png +0 -0
  21. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-linux.png +0 -0
  22. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-darwin.png +0 -0
  23. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-linux.png +0 -0
  24. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-darwin.png +0 -0
  25. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-linux.png +0 -0
  26. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-darwin.png +0 -0
  27. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-linux.png +0 -0
  28. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-darwin.png +0 -0
  29. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-linux.png +0 -0
  30. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-darwin.png +0 -0
  31. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-linux.png +0 -0
  32. package/src/components/atoms/button/button.stories.tsx +0 -289
  33. package/src/components/atoms/button/button.test.tsx +0 -419
  34. package/src/components/atoms/button/button.visual.test.tsx +0 -98
  35. package/src/components/atoms/button/icon-button.stories.tsx +0 -260
  36. package/src/components/atoms/button/icon-button.test.tsx +0 -186
  37. package/src/components/atoms/button/index.ts +0 -6
  38. package/src/components/atoms/input/index.ts +0 -17
  39. package/src/components/atoms/input/input-group.stories.tsx +0 -646
  40. package/src/components/atoms/input/input-group.test.tsx +0 -362
  41. package/src/components/atoms/input/input.stories.tsx +0 -228
  42. package/src/components/atoms/input/input.test.tsx +0 -167
  43. package/src/components/atoms/ndstudio-footer/index.ts +0 -1
  44. package/src/components/atoms/pager-control/index.ts +0 -5
  45. package/src/components/atoms/pager-control/pager-control.stories.tsx +0 -207
  46. package/src/components/atoms/pager-control/pager-control.test.tsx +0 -130
  47. package/src/components/atoms/popover/index.ts +0 -30
  48. package/src/components/atoms/popover/popover.stories.tsx +0 -531
  49. package/src/components/atoms/popover/popover.test.tsx +0 -486
  50. package/src/components/atoms/select/index.ts +0 -18
  51. package/src/components/atoms/select/select.stories.tsx +0 -455
  52. package/src/components/atoms/tooltip/index.ts +0 -24
  53. package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -348
  54. package/src/components/atoms/tooltip/tooltip.test.tsx +0 -363
  55. package/src/components/dev-tools/dev-toolbar/dev-toolbar.stories.tsx +0 -73
  56. package/src/components/dev-tools/dev-toolbar/index.ts +0 -1
  57. package/src/components/dev-tools/grid-overlay/index.ts +0 -1
  58. package/src/components/dev-tools/index.ts +0 -2
  59. package/src/components/foundation/typography/typography.stories.tsx +0 -401
  60. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-darwin.png +0 -0
  61. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-linux.png +0 -0
  62. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-darwin.png +0 -0
  63. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-linux.png +0 -0
  64. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-darwin.png +0 -0
  65. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-linux.png +0 -0
  66. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-darwin.png +0 -0
  67. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-linux.png +0 -0
  68. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-darwin.png +0 -0
  69. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-linux.png +0 -0
  70. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-darwin.png +0 -0
  71. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-linux.png +0 -0
  72. package/src/components/organisms/card/card.stories.tsx +0 -293
  73. package/src/components/organisms/card/card.test.tsx +0 -247
  74. package/src/components/organisms/card/card.visual.test.tsx +0 -197
  75. package/src/components/organisms/card/index.ts +0 -26
  76. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-darwin.png +0 -0
  77. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-linux.png +0 -0
  78. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-darwin.png +0 -0
  79. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-linux.png +0 -0
  80. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-darwin.png +0 -0
  81. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-linux.png +0 -0
  82. package/src/components/organisms/navbar/index.ts +0 -18
  83. package/src/components/organisms/navbar/navbar.stories.tsx +0 -313
  84. package/src/components/organisms/navbar/navbar.test.tsx +0 -190
  85. package/src/components/organisms/navbar/navbar.visual.test.tsx +0 -85
  86. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-darwin.png +0 -0
  87. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-linux.png +0 -0
  88. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-darwin.png +0 -0
  89. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-linux.png +0 -0
  90. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-darwin.png +0 -0
  91. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-linux.png +0 -0
  92. package/src/components/organisms/us-gov-banner/index.ts +0 -5
  93. package/src/components/organisms/us-gov-banner/us-gov-banner.stories.tsx +0 -35
  94. package/src/components/organisms/us-gov-banner/us-gov-banner.test.tsx +0 -107
  95. package/src/components/organisms/us-gov-banner/us-gov-banner.visual.test.tsx +0 -46
  96. package/src/components/sections/banner/banner.stories.tsx +0 -150
  97. package/src/components/sections/banner/banner.test.tsx +0 -185
  98. package/src/components/sections/banner/index.ts +0 -2
  99. package/src/components/sections/card-grid/card-grid.stories.tsx +0 -351
  100. package/src/components/sections/card-grid/index.ts +0 -1
  101. package/src/components/sections/faq-section/faq-section.stories.tsx +0 -453
  102. package/src/components/sections/faq-section/index.ts +0 -2
  103. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-darwin.png +0 -0
  104. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-linux.png +0 -0
  105. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-darwin.png +0 -0
  106. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-linux.png +0 -0
  107. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-darwin.png +0 -0
  108. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-linux.png +0 -0
  109. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-darwin.png +0 -0
  110. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-linux.png +0 -0
  111. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-darwin.png +0 -0
  112. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-linux.png +0 -0
  113. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-darwin.png +0 -0
  114. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-linux.png +0 -0
  115. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-darwin.png +0 -0
  116. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-linux.png +0 -0
  117. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-darwin.png +0 -0
  118. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-linux.png +0 -0
  119. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-darwin.png +0 -0
  120. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-linux.png +0 -0
  121. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-darwin.png +0 -0
  122. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-linux.png +0 -0
  123. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-default-chromium-linux.png +0 -0
  124. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-darwin.png +0 -0
  125. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-linux.png +0 -0
  126. package/src/components/sections/hero/hero.stories.tsx +0 -397
  127. package/src/components/sections/hero/hero.test.tsx +0 -138
  128. package/src/components/sections/hero/hero.visual.test.tsx +0 -140
  129. package/src/components/sections/hero/index.ts +0 -23
  130. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-darwin.png +0 -0
  131. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-linux.png +0 -0
  132. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-darwin.png +0 -0
  133. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-linux.png +0 -0
  134. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-darwin.png +0 -0
  135. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-linux.png +0 -0
  136. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-darwin.png +0 -0
  137. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-linux.png +0 -0
  138. package/src/components/sections/prose/index.ts +0 -6
  139. package/src/components/sections/prose/prose.stories.tsx +0 -144
  140. package/src/components/sections/prose/prose.test.tsx +0 -178
  141. package/src/components/sections/prose/prose.visual.test.tsx +0 -105
  142. package/src/components/sections/quote-block/index.ts +0 -5
  143. package/src/components/sections/river/index.ts +0 -1
  144. package/src/components/sections/river/river.stories.tsx +0 -237
  145. package/src/components/sections/river/river.test.tsx +0 -268
  146. package/src/components/sections/tout/index.ts +0 -1
  147. package/src/components/sections/tout/tout.stories.tsx +0 -171
  148. package/src/components/sections/tout/tout.test.tsx +0 -242
  149. package/src/components/sections/two-column-section/index.ts +0 -5
  150. package/src/components/sections/two-column-section/two-column-section.stories.tsx +0 -285
  151. package/src/components/shared/index.ts +0 -5
  152. package/src/index.ts +0 -293
  153. package/src/main.tsx +0 -13
  154. package/src/stories/grid-system.stories.tsx +0 -309
  155. package/src/stories/introduction.mdx +0 -128
  156. package/src/stories/theme-provider.stories.tsx +0 -349
  157. package/src/stories/token-showcase.stories.tsx +0 -73
  158. package/src/stories/token-showcase.tsx +0 -777
  159. package/src/styles.css +0 -14
  160. package/src/tests/token-resolution.test.tsx +0 -298
  161. package/src/theme/theme-provider.test.tsx +0 -270
@@ -1,6 +0,0 @@
1
- export {
2
- Prose,
3
- type ProseProps,
4
- ProseSection,
5
- type ProseSectionProps,
6
- } from "./prose";
@@ -1,144 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react-vite";
2
- import { Prose, ProseSection } from ".";
3
-
4
- const meta: Meta<typeof Prose> = {
5
- title: "Sections/Prose",
6
- component: Prose,
7
- parameters: {
8
- layout: "centered",
9
- },
10
- } as Meta<typeof Prose>;
11
-
12
- export default meta;
13
- type Story = StoryObj<typeof Prose>;
14
-
15
- const sampleIntro =
16
- "On the modern web, typography is not decoration; it's the cognitive interface. Before a user understands your product, policy, or program, they're unconsciously reading the structure of your type: the hierarchy of headings, the discipline of your spacing, the confidence or hesitation in your line lengths.";
17
-
18
- const sampleParagraph1 =
19
- "Style here isn't about clever fonts, it's about creating a system of visual cues that makes thinking easier. A consistent scale, clear contrast between roles, and careful use of weight and size become a kind of mental exoskeleton for the reader. Done well, typography lowers the friction of understanding to the point where attention can be spent on the content itself rather than on decoding the layout.";
20
-
21
- const sampleParagraph2 =
22
- 'Rhythm is where that structure turns into a voice. Online, people experience your text as a sequence of micro-moments: the way a headline sits in space, how paragraphs breathe, where the eye can rest. Tight, compressed leading and dense blocks say, "this is serious, pay attention." Generous white space and measured line lengths say, "you have room to think." Over time, those choices form a recognizable persona, just as surely as a writing style does. When the rhythm is intentional, your site speaks with a calm, authoritative cadence that users begin to trust. When it\'s sloppy or inconsistent, the voice fractures, and so does the sense that there\'s a clear, competent mind behind the interface.';
23
-
24
- // =============================================================================
25
- // Default
26
- // =============================================================================
27
-
28
- export const Default: Story = {
29
- render: () => (
30
- <Prose>
31
- <ProseSection heading="Headline - Medium" as="h2">
32
- <p>{sampleIntro}</p>
33
- </ProseSection>
34
- <ProseSection heading="Headline - Small" as="h3">
35
- <p>{sampleParagraph1}</p>
36
- <p>{sampleParagraph2}</p>
37
- </ProseSection>
38
- </Prose>
39
- ),
40
- };
41
-
42
- // =============================================================================
43
- // Responsive Variants
44
- // =============================================================================
45
-
46
- export const Desktop: Story = {
47
- render: () => (
48
- <Prose>
49
- <ProseSection heading="Headline - Medium" as="h2">
50
- <p>{sampleIntro}</p>
51
- </ProseSection>
52
- <ProseSection heading="Headline - Small" as="h3">
53
- <p>{sampleParagraph1}</p>
54
- <p>{sampleParagraph2}</p>
55
- </ProseSection>
56
- </Prose>
57
- ),
58
- globals: {
59
- viewport: { value: "lg", isRotated: false },
60
- },
61
- };
62
-
63
- export const Tablet: Story = {
64
- render: () => (
65
- <Prose>
66
- <ProseSection heading="Headline - Medium" as="h2">
67
- <p>{sampleIntro}</p>
68
- </ProseSection>
69
- <ProseSection heading="Headline - Small" as="h3">
70
- <p>{sampleParagraph1}</p>
71
- <p>{sampleParagraph2}</p>
72
- </ProseSection>
73
- </Prose>
74
- ),
75
- globals: {
76
- viewport: { value: "md", isRotated: false },
77
- },
78
- };
79
-
80
- export const Mobile: Story = {
81
- render: () => (
82
- <Prose>
83
- <ProseSection heading="Headline - Medium" as="h2">
84
- <p>{sampleIntro}</p>
85
- </ProseSection>
86
- <ProseSection heading="Headline - Small" as="h3">
87
- <p>{sampleParagraph1}</p>
88
- <p>{sampleParagraph2}</p>
89
- </ProseSection>
90
- </Prose>
91
- ),
92
- globals: {
93
- viewport: { value: "sm", isRotated: false },
94
- },
95
- };
96
-
97
- // =============================================================================
98
- // Playground
99
- // =============================================================================
100
-
101
- export const Playground: Story = {
102
- render: (args) => (
103
- <Prose {...args}>
104
- <ProseSection heading="Main Heading" as="h2">
105
- <p>{sampleIntro}</p>
106
- </ProseSection>
107
- <ProseSection heading="Subheading" as="h3">
108
- <p>{sampleParagraph1}</p>
109
- <p>{sampleParagraph2}</p>
110
- </ProseSection>
111
- </Prose>
112
- ),
113
- };
114
-
115
- // =============================================================================
116
- // Examples
117
- // =============================================================================
118
-
119
- export const SingleSection: Story = {
120
- render: () => (
121
- <Prose>
122
- <ProseSection heading="About Our Mission" as="h2">
123
- <p>{sampleIntro}</p>
124
- <p>{sampleParagraph1}</p>
125
- </ProseSection>
126
- </Prose>
127
- ),
128
- };
129
-
130
- export const MultipleSections: Story = {
131
- render: () => (
132
- <Prose>
133
- <ProseSection heading="Introduction" as="h2">
134
- <p>{sampleIntro}</p>
135
- </ProseSection>
136
- <ProseSection heading="The Importance of Style" as="h3">
137
- <p>{sampleParagraph1}</p>
138
- </ProseSection>
139
- <ProseSection heading="Finding Your Rhythm" as="h3">
140
- <p>{sampleParagraph2}</p>
141
- </ProseSection>
142
- </Prose>
143
- ),
144
- };
@@ -1,178 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import { page } from "vitest/browser";
3
- import { render } from "vitest-browser-react";
4
- import { Prose, ProseSection } from "./prose";
5
-
6
- describe("Prose", () => {
7
- describe("Accessibility", () => {
8
- test("ProseSection renders as section landmark", async () => {
9
- render(
10
- <Prose>
11
- <ProseSection heading="Test Section" data-testid="section">
12
- <p>Content</p>
13
- </ProseSection>
14
- </Prose>,
15
- );
16
-
17
- const section = page.getByTestId("section");
18
- await expect.element(section).toBeInTheDocument();
19
- });
20
-
21
- test("ProseSection heading renders as h2 by default", async () => {
22
- render(
23
- <Prose>
24
- <ProseSection heading="Default Heading">
25
- <p>Content</p>
26
- </ProseSection>
27
- </Prose>,
28
- );
29
-
30
- await expect
31
- .element(
32
- page.getByRole("heading", { level: 2, name: "Default Heading" }),
33
- )
34
- .toBeInTheDocument();
35
- });
36
-
37
- test("ProseSection heading renders as h3 when specified", async () => {
38
- render(
39
- <Prose>
40
- <ProseSection heading="H3 Heading" as="h3">
41
- <p>Content</p>
42
- </ProseSection>
43
- </Prose>,
44
- );
45
-
46
- await expect
47
- .element(page.getByRole("heading", { level: 3, name: "H3 Heading" }))
48
- .toBeInTheDocument();
49
- });
50
-
51
- test("prose content is readable", async () => {
52
- render(
53
- <Prose>
54
- <ProseSection heading="Readable Content">
55
- <p>This is some readable body text.</p>
56
- </ProseSection>
57
- </Prose>,
58
- );
59
-
60
- await expect
61
- .element(page.getByText("This is some readable body text."))
62
- .toBeInTheDocument();
63
- });
64
- });
65
-
66
- describe("Props", () => {
67
- test("Prose renders children", async () => {
68
- render(
69
- <Prose data-testid="prose">
70
- <ProseSection heading="Child Section">
71
- <p>Child content</p>
72
- </ProseSection>
73
- </Prose>,
74
- );
75
-
76
- await expect.element(page.getByText("Child content")).toBeInTheDocument();
77
- });
78
-
79
- test("Prose supports custom className", async () => {
80
- render(
81
- <Prose className="custom-prose" data-testid="prose">
82
- <ProseSection heading="Test">
83
- <p>Content</p>
84
- </ProseSection>
85
- </Prose>,
86
- );
87
-
88
- const prose = page.getByTestId("prose");
89
- await expect.element(prose).toHaveClass(/custom-prose/);
90
- });
91
-
92
- test("ProseSection supports custom className", async () => {
93
- render(
94
- <Prose>
95
- <ProseSection
96
- heading="Test"
97
- className="custom-section"
98
- data-testid="section"
99
- >
100
- <p>Content</p>
101
- </ProseSection>
102
- </Prose>,
103
- );
104
-
105
- const section = page.getByTestId("section");
106
- await expect.element(section).toHaveClass(/custom-section/);
107
- });
108
- });
109
-
110
- describe("Styling", () => {
111
- test("Prose has max-width constraint", async () => {
112
- render(
113
- <Prose data-testid="prose">
114
- <ProseSection heading="Test">
115
- <p>Content</p>
116
- </ProseSection>
117
- </Prose>,
118
- );
119
-
120
- const prose = page.getByTestId("prose");
121
- await expect.element(prose).toHaveClass(/max-w-\[700px\]/);
122
- });
123
-
124
- test("h2 heading has correct typography class", async () => {
125
- render(
126
- <Prose>
127
- <ProseSection heading="H2 Test">
128
- <p>Content</p>
129
- </ProseSection>
130
- </Prose>,
131
- );
132
-
133
- const heading = page.getByRole("heading", { name: "H2 Test" });
134
- await expect.element(heading).toHaveClass(/typography-h3/);
135
- });
136
-
137
- test("h3 heading has correct typography class", async () => {
138
- render(
139
- <Prose>
140
- <ProseSection heading="H3 Test" as="h3">
141
- <p>Content</p>
142
- </ProseSection>
143
- </Prose>,
144
- );
145
-
146
- const heading = page.getByRole("heading", { name: "H3 Test" });
147
- await expect.element(heading).toHaveClass(/typography-h4/);
148
- });
149
- });
150
-
151
- describe("Composition", () => {
152
- test("renders multiple sections", async () => {
153
- render(
154
- <Prose>
155
- <ProseSection heading="First">
156
- <p>First content</p>
157
- </ProseSection>
158
- <ProseSection heading="Second">
159
- <p>Second content</p>
160
- </ProseSection>
161
- <ProseSection heading="Third">
162
- <p>Third content</p>
163
- </ProseSection>
164
- </Prose>,
165
- );
166
-
167
- await expect
168
- .element(page.getByRole("heading", { name: "First" }))
169
- .toBeInTheDocument();
170
- await expect
171
- .element(page.getByRole("heading", { name: "Second" }))
172
- .toBeInTheDocument();
173
- await expect
174
- .element(page.getByRole("heading", { name: "Third" }))
175
- .toBeInTheDocument();
176
- });
177
- });
178
- });
@@ -1,105 +0,0 @@
1
- import { render } from "@testing-library/react";
2
- import { describe, expect, test } from "vitest";
3
- import { page } from "vitest/browser";
4
- import { Prose, ProseSection } from "./prose";
5
-
6
- describe("Prose Visual Regression", () => {
7
- test("prose with single section renders correctly", async () => {
8
- render(
9
- <div
10
- style={{ width: "800px", backgroundColor: "#ffffff", padding: "40px" }}
11
- >
12
- <Prose data-testid="prose">
13
- <ProseSection heading="Section Heading">
14
- <p>
15
- This is a paragraph of body text that demonstrates the prose
16
- component's typography and spacing. It should be easy to read and
17
- properly formatted.
18
- </p>
19
- </ProseSection>
20
- </Prose>
21
- </div>,
22
- );
23
-
24
- await expect(page.getByTestId("prose")).toMatchScreenshot(
25
- "prose-single-section",
26
- );
27
- });
28
-
29
- test("prose with multiple sections renders correctly", async () => {
30
- render(
31
- <div
32
- style={{ width: "800px", backgroundColor: "#ffffff", padding: "40px" }}
33
- >
34
- <Prose data-testid="prose">
35
- <ProseSection heading="First Section">
36
- <p>
37
- This is the first section of content with some body text to
38
- demonstrate spacing between sections.
39
- </p>
40
- </ProseSection>
41
- <ProseSection heading="Second Section">
42
- <p>
43
- This is the second section showing how multiple sections stack
44
- with proper gaps between them.
45
- </p>
46
- </ProseSection>
47
- </Prose>
48
- </div>,
49
- );
50
-
51
- await expect(page.getByTestId("prose")).toMatchScreenshot(
52
- "prose-multiple-sections",
53
- );
54
- });
55
-
56
- test("prose with h3 heading renders correctly", async () => {
57
- render(
58
- <div
59
- style={{ width: "800px", backgroundColor: "#ffffff", padding: "40px" }}
60
- >
61
- <Prose data-testid="prose">
62
- <ProseSection heading="H3 Heading" as="h3">
63
- <p>
64
- This section uses an h3 heading which has smaller typography than
65
- the default h2.
66
- </p>
67
- </ProseSection>
68
- </Prose>
69
- </div>,
70
- );
71
-
72
- await expect(page.getByTestId("prose")).toMatchScreenshot(
73
- "prose-h3-heading",
74
- );
75
- });
76
-
77
- test("prose with multiple paragraphs renders correctly", async () => {
78
- render(
79
- <div
80
- style={{ width: "800px", backgroundColor: "#ffffff", padding: "40px" }}
81
- >
82
- <Prose data-testid="prose">
83
- <ProseSection heading="Long Content">
84
- <p>
85
- First paragraph with some content to show how multiple paragraphs
86
- are spaced within a prose section.
87
- </p>
88
- <p>
89
- Second paragraph demonstrating the gap between paragraphs in the
90
- prose component.
91
- </p>
92
- <p>
93
- Third paragraph to show consistent spacing throughout the content
94
- area.
95
- </p>
96
- </ProseSection>
97
- </Prose>
98
- </div>,
99
- );
100
-
101
- await expect(page.getByTestId("prose")).toMatchScreenshot(
102
- "prose-multiple-paragraphs",
103
- );
104
- });
105
- });
@@ -1,5 +0,0 @@
1
- export {
2
- QuoteBlock,
3
- type QuoteBlockProps,
4
- quoteBlockVariants,
5
- } from "./quote-block";
@@ -1 +0,0 @@
1
- export { River, type RiverProps, riverVariants } from "./river";
@@ -1,237 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react-vite";
2
- import { Button } from "../../atoms/button";
3
- import { River } from ".";
4
-
5
- const meta: Meta<typeof River> = {
6
- title: "Sections/River",
7
- component: River,
8
- parameters: {
9
- layout: "fullscreen",
10
- },
11
- argTypes: {
12
- variant: {
13
- control: "select",
14
- options: ["A", "B"],
15
- description: "Layout variant",
16
- },
17
- headline: {
18
- control: "text",
19
- description: "The headline text",
20
- },
21
- body: {
22
- control: "text",
23
- description: "The body text",
24
- },
25
- },
26
- decorators: [
27
- (Story) => (
28
- <div className="grid-container">
29
- <Story />
30
- </div>
31
- ),
32
- ],
33
- } as Meta<typeof River>;
34
-
35
- export default meta;
36
- type Story = StoryObj<typeof River>;
37
-
38
- const PlaceholderImage = () => (
39
- <div className="bg-gray-200 w-full aspect-[4/3] rounded-lg flex items-center justify-center">
40
- <span className="text-gray-500 typography-body-small">
41
- Image Placeholder
42
- </span>
43
- </div>
44
- );
45
-
46
- export const Playground: Story = {
47
- render: (args) => <River {...args} />,
48
- };
49
- Playground.args = {
50
- variant: "A",
51
- headline: "Feature Headline",
52
- body: "Use rivers to present content with supporting media. They work great for feature highlights, product showcases, and storytelling sections.",
53
- primaryAction: <Button>Primary Action</Button>,
54
- secondaryAction: <Button variant="outline">Secondary</Button>,
55
- media: <PlaceholderImage />,
56
- };
57
-
58
- // =============================================================================
59
- // Variants
60
- // =============================================================================
61
-
62
- /**
63
- * Variant A: Text on left, media on right (desktop)
64
- */
65
- export const VariantA: Story = {
66
- render: () => (
67
- <River
68
- variant="A"
69
- headline="Text Left, Media Right"
70
- body="Variant A places the text content on the left (9 columns) and media on the right (15 columns) on desktop viewports. On mobile and tablet, they stack vertically."
71
- primaryAction={<Button>Primary Action</Button>}
72
- secondaryAction={<Button variant="outline">Secondary</Button>}
73
- media={<PlaceholderImage />}
74
- />
75
- ),
76
- };
77
-
78
- /**
79
- * Variant B: Media on left, text on right (desktop)
80
- */
81
- export const VariantB: Story = {
82
- render: () => (
83
- <River
84
- variant="B"
85
- headline="Media Left, Text Right"
86
- body="Variant B places the media on the left (15 columns) and text content on the right (9 columns) on desktop viewports. On mobile and tablet, they stack vertically with text first."
87
- primaryAction={<Button>Primary Action</Button>}
88
- secondaryAction={<Button variant="outline">Secondary</Button>}
89
- media={<PlaceholderImage />}
90
- />
91
- ),
92
- };
93
-
94
- // =============================================================================
95
- // Responsive Variants
96
- // =============================================================================
97
-
98
- export const VariantADesktop: Story = {
99
- render: () => (
100
- <River
101
- variant="A"
102
- headline="Desktop View"
103
- body="On desktop (lg, 1440px), the content spans 9 columns and the media spans 15 columns in a horizontal layout."
104
- primaryAction={<Button>Primary</Button>}
105
- secondaryAction={<Button variant="outline">Secondary</Button>}
106
- media={<PlaceholderImage />}
107
- />
108
- ),
109
- globals: {
110
- viewport: { value: "lg", isRotated: false },
111
- },
112
- };
113
-
114
- export const VariantATablet: Story = {
115
- render: () => (
116
- <River
117
- variant="A"
118
- headline="Tablet View"
119
- body="On tablet (md, 768px), the content and media stack vertically with the text above the media."
120
- primaryAction={<Button>Primary</Button>}
121
- secondaryAction={<Button variant="outline">Secondary</Button>}
122
- media={<PlaceholderImage />}
123
- />
124
- ),
125
- globals: {
126
- viewport: { value: "md", isRotated: false },
127
- },
128
- };
129
-
130
- export const VariantAMobile: Story = {
131
- render: () => (
132
- <River
133
- variant="A"
134
- headline="Mobile View"
135
- body="On mobile (sm, 320px), content is stacked with smaller button sizing."
136
- primaryAction={<Button size="sm">Primary</Button>}
137
- secondaryAction={
138
- <Button size="sm" variant="outline">
139
- Secondary
140
- </Button>
141
- }
142
- media={<PlaceholderImage />}
143
- />
144
- ),
145
- globals: {
146
- viewport: { value: "sm", isRotated: false },
147
- },
148
- };
149
-
150
- export const VariantBDesktop: Story = {
151
- render: () => (
152
- <River
153
- variant="B"
154
- headline="Desktop View - Reversed"
155
- body="Variant B reverses the layout, placing media on the left and content on the right."
156
- primaryAction={<Button>Primary</Button>}
157
- secondaryAction={<Button variant="outline">Secondary</Button>}
158
- media={<PlaceholderImage />}
159
- />
160
- ),
161
- globals: {
162
- viewport: { value: "lg", isRotated: false },
163
- },
164
- };
165
-
166
- // =============================================================================
167
- // Examples
168
- // =============================================================================
169
-
170
- /**
171
- * Without secondary action
172
- */
173
- export const SingleAction: Story = {
174
- render: () => (
175
- <River
176
- variant="A"
177
- headline="Single Action Button"
178
- body="Rivers can also be used with just a primary action button when a secondary action isn't needed."
179
- primaryAction={<Button>Learn More</Button>}
180
- media={<PlaceholderImage />}
181
- />
182
- ),
183
- };
184
-
185
- /**
186
- * Alternating rivers for visual rhythm
187
- */
188
- export const AlternatingRivers: Story = {
189
- render: () => (
190
- <>
191
- <River
192
- variant="A"
193
- headline="First Feature"
194
- body="Start with text on the left for the first section."
195
- primaryAction={<Button>Explore</Button>}
196
- media={<PlaceholderImage />}
197
- />
198
- <River
199
- variant="B"
200
- headline="Second Feature"
201
- body="Alternate to media on the left for visual variety."
202
- primaryAction={<Button>Discover</Button>}
203
- media={<PlaceholderImage />}
204
- className="bg-gray-100"
205
- />
206
- <River
207
- variant="A"
208
- headline="Third Feature"
209
- body="Return to the original layout to create rhythm."
210
- primaryAction={<Button>Learn More</Button>}
211
- media={<PlaceholderImage />}
212
- />
213
- </>
214
- ),
215
- };
216
-
217
- /**
218
- * With actual image
219
- */
220
- export const WithImage: Story = {
221
- render: () => (
222
- <River
223
- variant="A"
224
- headline="Real World Example"
225
- body="Rivers work great with actual images, videos, or any media content. The media column is designed to accommodate various aspect ratios."
226
- primaryAction={<Button>Get Started</Button>}
227
- secondaryAction={<Button variant="outline">Learn More</Button>}
228
- media={
229
- <img
230
- src="https://images.unsplash.com/photo-1551434678-e076c223a692?w=800&h=600&fit=crop"
231
- alt="Team collaboration"
232
- className="rounded-lg object-cover"
233
- />
234
- }
235
- />
236
- ),
237
- };