@nationaldesignstudio/react 0.0.10 → 0.0.11

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 (169) hide show
  1. package/dist/component-registry.md +2405 -0
  2. package/dist/components/atoms/accordion/accordion.d.ts +44 -3
  3. package/dist/components/atoms/button/button.d.ts +155 -11
  4. package/dist/components/atoms/button/icon-button.d.ts +114 -5
  5. package/dist/components/atoms/ndstudio-footer/ndstudio-footer.d.ts +30 -0
  6. package/dist/components/atoms/pager-control/pager-control.d.ts +116 -9
  7. package/dist/components/dev-tools/dev-toolbar/dev-toolbar.d.ts +4 -0
  8. package/dist/components/dev-tools/grid-overlay/grid-overlay.d.ts +6 -0
  9. package/dist/components/organisms/card/card.d.ts +40 -4
  10. package/dist/components/sections/banner/banner.d.ts +39 -6
  11. package/dist/components/sections/card-grid/card-grid.d.ts +37 -4
  12. package/dist/components/sections/faq-section/faq-section.d.ts +2 -2
  13. package/dist/components/sections/hero/hero.d.ts +167 -16
  14. package/dist/components/sections/river/river.d.ts +37 -4
  15. package/dist/components/sections/tout/tout.d.ts +86 -6
  16. package/dist/components/sections/two-column-section/two-column-section.d.ts +80 -6
  17. package/dist/hooks/index.d.ts +1 -0
  18. package/dist/hooks/use-event-listener.d.ts +24 -0
  19. package/dist/index.d.ts +9 -2
  20. package/dist/index.js +12034 -5934
  21. package/dist/index.js.map +1 -1
  22. package/dist/lib/theme.d.ts +330 -0
  23. package/dist/tokens.css +13650 -6129
  24. package/package.json +11 -21
  25. package/src/App.css +0 -0
  26. package/src/App.tsx +0 -7
  27. package/src/assets/fonts/PPNeueMontreal-Variable.woff2 +0 -0
  28. package/src/assets/react.svg +0 -1
  29. package/src/components/atoms/accordion/accordion.stories.tsx +0 -228
  30. package/src/components/atoms/accordion/accordion.tsx +0 -137
  31. package/src/components/atoms/accordion/index.ts +0 -6
  32. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-darwin.png +0 -0
  33. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-linux.png +0 -0
  34. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-darwin.png +0 -0
  35. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-linux.png +0 -0
  36. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-darwin.png +0 -0
  37. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-linux.png +0 -0
  38. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-darwin.png +0 -0
  39. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-linux.png +0 -0
  40. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-darwin.png +0 -0
  41. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-linux.png +0 -0
  42. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-darwin.png +0 -0
  43. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-linux.png +0 -0
  44. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-darwin.png +0 -0
  45. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-linux.png +0 -0
  46. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-darwin.png +0 -0
  47. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-linux.png +0 -0
  48. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-darwin.png +0 -0
  49. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-linux.png +0 -0
  50. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-darwin.png +0 -0
  51. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-linux.png +0 -0
  52. package/src/components/atoms/button/button.stories.tsx +0 -84
  53. package/src/components/atoms/button/button.test.tsx +0 -141
  54. package/src/components/atoms/button/button.tsx +0 -95
  55. package/src/components/atoms/button/button.visual.test.tsx +0 -102
  56. package/src/components/atoms/button/icon-button.stories.tsx +0 -166
  57. package/src/components/atoms/button/icon-button.tsx +0 -125
  58. package/src/components/atoms/button/index.ts +0 -6
  59. package/src/components/atoms/pager-control/index.ts +0 -5
  60. package/src/components/atoms/pager-control/pager-control.stories.tsx +0 -209
  61. package/src/components/atoms/pager-control/pager-control.test.tsx +0 -149
  62. package/src/components/atoms/pager-control/pager-control.tsx +0 -328
  63. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-darwin.png +0 -0
  64. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-linux.png +0 -0
  65. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-darwin.png +0 -0
  66. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-linux.png +0 -0
  67. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-darwin.png +0 -0
  68. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-linux.png +0 -0
  69. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-darwin.png +0 -0
  70. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-linux.png +0 -0
  71. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-darwin.png +0 -0
  72. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-linux.png +0 -0
  73. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-darwin.png +0 -0
  74. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-linux.png +0 -0
  75. package/src/components/organisms/card/card.stories.tsx +0 -293
  76. package/src/components/organisms/card/card.test.tsx +0 -245
  77. package/src/components/organisms/card/card.tsx +0 -227
  78. package/src/components/organisms/card/card.visual.test.tsx +0 -197
  79. package/src/components/organisms/card/index.ts +0 -19
  80. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-darwin.png +0 -0
  81. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-linux.png +0 -0
  82. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-darwin.png +0 -0
  83. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-linux.png +0 -0
  84. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-darwin.png +0 -0
  85. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-linux.png +0 -0
  86. package/src/components/organisms/navbar/index.ts +0 -18
  87. package/src/components/organisms/navbar/navbar.stories.tsx +0 -313
  88. package/src/components/organisms/navbar/navbar.test.tsx +0 -190
  89. package/src/components/organisms/navbar/navbar.tsx +0 -317
  90. package/src/components/organisms/navbar/navbar.visual.test.tsx +0 -85
  91. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-darwin.png +0 -0
  92. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-linux.png +0 -0
  93. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-darwin.png +0 -0
  94. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-linux.png +0 -0
  95. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-darwin.png +0 -0
  96. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-linux.png +0 -0
  97. package/src/components/organisms/us-gov-banner/index.ts +0 -1
  98. package/src/components/organisms/us-gov-banner/us-gov-banner.stories.tsx +0 -35
  99. package/src/components/organisms/us-gov-banner/us-gov-banner.test.tsx +0 -107
  100. package/src/components/organisms/us-gov-banner/us-gov-banner.tsx +0 -73
  101. package/src/components/organisms/us-gov-banner/us-gov-banner.visual.test.tsx +0 -46
  102. package/src/components/sections/banner/banner.stories.tsx +0 -150
  103. package/src/components/sections/banner/banner.test.tsx +0 -185
  104. package/src/components/sections/banner/banner.tsx +0 -130
  105. package/src/components/sections/banner/index.ts +0 -2
  106. package/src/components/sections/card-grid/card-grid.stories.tsx +0 -351
  107. package/src/components/sections/card-grid/card-grid.tsx +0 -118
  108. package/src/components/sections/card-grid/index.ts +0 -1
  109. package/src/components/sections/faq-section/faq-section.tsx +0 -77
  110. package/src/components/sections/faq-section/index.ts +0 -2
  111. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-darwin.png +0 -0
  112. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-linux.png +0 -0
  113. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-darwin.png +0 -0
  114. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-linux.png +0 -0
  115. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-darwin.png +0 -0
  116. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-linux.png +0 -0
  117. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-darwin.png +0 -0
  118. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-linux.png +0 -0
  119. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-darwin.png +0 -0
  120. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-linux.png +0 -0
  121. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-darwin.png +0 -0
  122. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-linux.png +0 -0
  123. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-darwin.png +0 -0
  124. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-linux.png +0 -0
  125. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-darwin.png +0 -0
  126. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-linux.png +0 -0
  127. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-darwin.png +0 -0
  128. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-linux.png +0 -0
  129. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-darwin.png +0 -0
  130. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-linux.png +0 -0
  131. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-default-chromium-linux.png +0 -0
  132. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-darwin.png +0 -0
  133. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-linux.png +0 -0
  134. package/src/components/sections/hero/hero.stories.tsx +0 -145
  135. package/src/components/sections/hero/hero.test.tsx +0 -135
  136. package/src/components/sections/hero/hero.tsx +0 -191
  137. package/src/components/sections/hero/hero.visual.test.tsx +0 -140
  138. package/src/components/sections/hero/index.ts +0 -1
  139. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-darwin.png +0 -0
  140. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-linux.png +0 -0
  141. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-darwin.png +0 -0
  142. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-linux.png +0 -0
  143. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-darwin.png +0 -0
  144. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-linux.png +0 -0
  145. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-darwin.png +0 -0
  146. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-linux.png +0 -0
  147. package/src/components/sections/prose/index.ts +0 -6
  148. package/src/components/sections/prose/prose.stories.tsx +0 -144
  149. package/src/components/sections/prose/prose.test.tsx +0 -178
  150. package/src/components/sections/prose/prose.tsx +0 -88
  151. package/src/components/sections/prose/prose.visual.test.tsx +0 -105
  152. package/src/components/sections/river/index.ts +0 -1
  153. package/src/components/sections/river/river.stories.tsx +0 -237
  154. package/src/components/sections/river/river.test.tsx +0 -268
  155. package/src/components/sections/river/river.tsx +0 -175
  156. package/src/components/sections/tout/index.ts +0 -1
  157. package/src/components/sections/tout/tout.stories.tsx +0 -154
  158. package/src/components/sections/tout/tout.test.tsx +0 -242
  159. package/src/components/sections/tout/tout.tsx +0 -206
  160. package/src/components/sections/two-column-section/index.ts +0 -5
  161. package/src/components/sections/two-column-section/two-column-section.stories.tsx +0 -285
  162. package/src/components/sections/two-column-section/two-column-section.tsx +0 -152
  163. package/src/index.ts +0 -98
  164. package/src/lib/utils.ts +0 -6
  165. package/src/main.tsx +0 -13
  166. package/src/stories/Introduction.mdx +0 -114
  167. package/src/stories/TokenShowcase.stories.tsx +0 -92
  168. package/src/stories/TokenShowcase.tsx +0 -1352
  169. package/src/styles.css +0 -11
@@ -1,145 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react-vite";
2
- import { Hero } from ".";
3
-
4
- const meta: Meta<typeof Hero> = {
5
- title: "Sections/Hero",
6
- component: Hero,
7
- parameters: {
8
- layout: "fullscreen",
9
- },
10
- argTypes: {
11
- variant: {
12
- control: "select",
13
- options: ["A1", "A2", "A3"],
14
- description: "Hero variant controlling content alignment",
15
- },
16
- title: {
17
- control: "text",
18
- description: "The title text displayed in the hero",
19
- },
20
- },
21
- } as Meta<typeof Hero>;
22
-
23
- export default meta;
24
- type Story = StoryObj<typeof Hero>;
25
-
26
- export const Playground: Story = {
27
- render: (args) => <Hero {...args} />,
28
- };
29
- Playground.args = {
30
- title: "Hero Title",
31
- variant: "A1",
32
- };
33
-
34
- // =============================================================================
35
- // Variants
36
- // =============================================================================
37
-
38
- /**
39
- * A1 variant: Content aligned at the bottom of the hero.
40
- * This is the default variant.
41
- */
42
- export const A1: Story = {
43
- render: () => <Hero variant="A1" title="Hero A1" />,
44
- };
45
-
46
- /**
47
- * A2 variant: Content aligned at the top of the hero.
48
- */
49
- export const A2: Story = {
50
- render: () => <Hero variant="A2" title="Hero A2" />,
51
- };
52
-
53
- /**
54
- * A3 variant: Content centered vertically in the hero.
55
- */
56
- export const A3: Story = {
57
- render: () => <Hero variant="A3" title="Hero A3" />,
58
- };
59
-
60
- // =============================================================================
61
- // Responsive Variants - A1 (Content at bottom)
62
- // =============================================================================
63
-
64
- export const A1Desktop: Story = {
65
- render: () => <Hero variant="A1" title="Hero A1" />,
66
- globals: {
67
- viewport: { value: "lg", isRotated: false },
68
- },
69
- };
70
-
71
- export const A1Tablet: Story = {
72
- render: () => <Hero variant="A1" title="Hero A1" />,
73
- globals: {
74
- viewport: { value: "md", isRotated: false },
75
- },
76
- };
77
-
78
- export const A1Mobile: Story = {
79
- render: () => <Hero variant="A1" title="Hero A1" />,
80
- globals: {
81
- viewport: { value: "sm", isRotated: false },
82
- },
83
- };
84
-
85
- // =============================================================================
86
- // Responsive Variants - A2 (Content at top)
87
- // =============================================================================
88
-
89
- export const A2Desktop: Story = {
90
- render: () => <Hero variant="A2" title="Hero A2" />,
91
- globals: {
92
- viewport: { value: "lg", isRotated: false },
93
- },
94
- };
95
-
96
- export const A2Tablet: Story = {
97
- render: () => <Hero variant="A2" title="Hero A2" />,
98
- globals: {
99
- viewport: { value: "md", isRotated: false },
100
- },
101
- };
102
-
103
- export const A2Mobile: Story = {
104
- render: () => <Hero variant="A2" title="Hero A2" />,
105
- globals: {
106
- viewport: { value: "sm", isRotated: false },
107
- },
108
- };
109
-
110
- // =============================================================================
111
- // Responsive Variants - A3 (Content centered)
112
- // =============================================================================
113
-
114
- export const A3Desktop: Story = {
115
- render: () => <Hero variant="A3" title="Hero A3" />,
116
- globals: {
117
- viewport: { value: "lg", isRotated: false },
118
- },
119
- };
120
-
121
- export const A3Tablet: Story = {
122
- render: () => <Hero variant="A3" title="Hero A3" />,
123
- globals: {
124
- viewport: { value: "md", isRotated: false },
125
- },
126
- };
127
-
128
- export const A3Mobile: Story = {
129
- render: () => <Hero variant="A3" title="Hero A3" />,
130
- globals: {
131
- viewport: { value: "sm", isRotated: false },
132
- },
133
- };
134
-
135
- // =============================================================================
136
- // Examples
137
- // =============================================================================
138
-
139
- export const WithLongTitle: Story = {
140
- render: () => <Hero title="A Much Longer Hero Title That Wraps" />,
141
- };
142
-
143
- export const WithCustomClassName: Story = {
144
- render: () => <Hero title="Custom Background" className="bg-blue-600" />,
145
- };
@@ -1,135 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import { page } from "vitest/browser";
3
- import { render } from "vitest-browser-react";
4
- import { Hero } from "./hero";
5
-
6
- describe("Hero", () => {
7
- describe("Accessibility", () => {
8
- test("renders as section landmark", async () => {
9
- render(<Hero title="Test Hero" data-testid="hero" />);
10
-
11
- // Section is a region landmark when it has an accessible name
12
- const hero = page.getByTestId("hero");
13
- await expect.element(hero).toBeInTheDocument();
14
- });
15
-
16
- test("title renders as h1 heading", async () => {
17
- render(<Hero title="Hero Title" />);
18
-
19
- await expect
20
- .element(page.getByRole("heading", { level: 1, name: "Hero Title" }))
21
- .toBeInTheDocument();
22
- });
23
-
24
- test("title is accessible to screen readers", async () => {
25
- render(<Hero title="Accessible Title" />);
26
-
27
- await expect
28
- .element(page.getByText("Accessible Title"))
29
- .toBeInTheDocument();
30
- });
31
- });
32
-
33
- describe("Props", () => {
34
- test("renders with required title prop", async () => {
35
- render(<Hero title="Required Title" />);
36
-
37
- await expect
38
- .element(page.getByText("Required Title"))
39
- .toBeInTheDocument();
40
- });
41
-
42
- test("supports custom className", async () => {
43
- render(
44
- <Hero title="Custom" className="custom-class" data-testid="hero" />,
45
- );
46
-
47
- const hero = page.getByTestId("hero");
48
- await expect.element(hero).toHaveClass(/custom-class/);
49
- });
50
-
51
- test("spreads additional props to section element", async () => {
52
- render(
53
- <Hero
54
- title="Props Test"
55
- data-testid="hero"
56
- aria-label="Hero section"
57
- />,
58
- );
59
-
60
- const hero = page.getByTestId("hero");
61
- await expect.element(hero).toHaveAttribute("aria-label", "Hero section");
62
- });
63
- });
64
-
65
- describe("Styling", () => {
66
- test("applies default background color", async () => {
67
- render(<Hero title="Default" data-testid="hero" />);
68
-
69
- const hero = page.getByTestId("hero");
70
- await expect.element(hero).toHaveClass(/bg-gray-1000/);
71
- });
72
-
73
- test("applies responsive height classes", async () => {
74
- render(<Hero title="Responsive" data-testid="hero" />);
75
-
76
- const hero = page.getByTestId("hero");
77
- // Mobile height
78
- await expect.element(hero).toHaveClass(/h-\[500px\]/);
79
- });
80
- });
81
-
82
- describe("Variants", () => {
83
- test("A1 variant applies items-end alignment (default)", async () => {
84
- render(<Hero title="A1 Hero" variant="A1" data-testid="hero" />);
85
-
86
- const hero = page.getByTestId("hero");
87
- await expect.element(hero).toHaveClass(/items-end/);
88
- });
89
-
90
- test("A1 variant is default when no variant specified", async () => {
91
- render(<Hero title="Default Hero" data-testid="hero" />);
92
-
93
- const hero = page.getByTestId("hero");
94
- await expect.element(hero).toHaveClass(/items-end/);
95
- });
96
-
97
- test("A2 variant applies items-start alignment", async () => {
98
- render(<Hero title="A2 Hero" variant="A2" data-testid="hero" />);
99
-
100
- const hero = page.getByTestId("hero");
101
- await expect.element(hero).toHaveClass(/items-start/);
102
- });
103
-
104
- test("A3 variant applies items-center alignment", async () => {
105
- render(<Hero title="A3 Hero" variant="A3" data-testid="hero" />);
106
-
107
- const hero = page.getByTestId("hero");
108
- await expect.element(hero).toHaveClass(/items-center/);
109
- });
110
-
111
- test("A1 variant maintains common styles", async () => {
112
- render(<Hero title="A1 Hero" variant="A1" data-testid="hero" />);
113
-
114
- const hero = page.getByTestId("hero");
115
- await expect.element(hero).toHaveClass(/bg-gray-1000/);
116
- await expect.element(hero).toHaveClass(/h-\[500px\]/);
117
- });
118
-
119
- test("A2 variant maintains common styles", async () => {
120
- render(<Hero title="A2 Hero" variant="A2" data-testid="hero" />);
121
-
122
- const hero = page.getByTestId("hero");
123
- await expect.element(hero).toHaveClass(/bg-gray-1000/);
124
- await expect.element(hero).toHaveClass(/h-\[500px\]/);
125
- });
126
-
127
- test("A3 variant maintains common styles", async () => {
128
- render(<Hero title="A3 Hero" variant="A3" data-testid="hero" />);
129
-
130
- const hero = page.getByTestId("hero");
131
- await expect.element(hero).toHaveClass(/bg-gray-1000/);
132
- await expect.element(hero).toHaveClass(/h-\[500px\]/);
133
- });
134
- });
135
- });
@@ -1,191 +0,0 @@
1
- import { cva, type VariantProps } from "class-variance-authority";
2
- import * as React from "react";
3
- import { cn } from "@/lib/utils";
4
-
5
- /**
6
- * Hero variants based on Figma BaseKit / Heros
7
- *
8
- * Variants:
9
- * - A1: Content aligned at bottom (default)
10
- * - A2: Content aligned at top
11
- * - A3: Content aligned at center
12
- *
13
- * Each variant is responsive across breakpoints:
14
- * - sm (Mobile): 500px height, 20px padding
15
- * - md (Tablet): 650px height, 56px padding
16
- * - lg (Desktop): 700-850px height, 64-72px padding
17
- */
18
- const heroVariants = cva(
19
- [
20
- "flex w-full bg-gray-1000",
21
- // Mobile (sm)
22
- "h-[500px] p-spacing-20",
23
- // Tablet (md)
24
- "md:h-[650px] md:p-spacing-56",
25
- ],
26
- {
27
- variants: {
28
- variant: {
29
- // A1: Content at bottom
30
- A1: [
31
- "items-end",
32
- // Desktop (lg) - 800px height, 72px padding
33
- "xl:h-[800px] xl:p-spacing-72",
34
- ],
35
- // A2: Content at top
36
- A2: [
37
- "items-start",
38
- // Desktop (lg) - 700px height, 64px padding
39
- "xl:h-[700px] xl:p-spacing-64",
40
- ],
41
- // A3: Content centered
42
- A3: [
43
- "items-center",
44
- // Desktop (lg) - 800px height, 64px padding
45
- "xl:h-[800px] xl:p-spacing-64",
46
- ],
47
- },
48
- },
49
- defaultVariants: {
50
- variant: "A1",
51
- },
52
- },
53
- );
54
-
55
- export interface HeroProps
56
- extends React.HTMLAttributes<HTMLElement>,
57
- VariantProps<typeof heroVariants> {
58
- /**
59
- * The title text displayed in the hero
60
- */
61
- title: string;
62
- /**
63
- * URL for the background image
64
- */
65
- backgroundImage?: string;
66
- /**
67
- * URL for a background video (takes precedence over backgroundImage)
68
- */
69
- backgroundVideo?: string;
70
- /**
71
- * Opacity of the dark overlay (0-1, default: 0)
72
- */
73
- overlayOpacity?: number;
74
- /**
75
- * Color of the overlay (default: "black")
76
- */
77
- overlayColor?: string;
78
- /**
79
- * CSS background-position value (default: "center")
80
- */
81
- backgroundPosition?: string;
82
- }
83
-
84
- /**
85
- * Hero component for page headers with large display typography.
86
- *
87
- * Features responsive sizing across three variants:
88
- * - A1: Content at bottom (default)
89
- * - A2: Content at top
90
- * - A3: Content centered
91
- *
92
- * Each variant responds to breakpoints:
93
- * - Mobile: 500px height, 20px padding, 64px typography
94
- * - Tablet (768px+): 650px height, 56px padding, 128-148px typography
95
- * - Desktop (1440px+): 700-800px height, 64-72px padding, 148-192px typography
96
- *
97
- * @example
98
- * ```tsx
99
- * // Simple hero
100
- * <Hero title="Welcome" variant="A1" />
101
- *
102
- * // With background image and overlay
103
- * <Hero
104
- * title="Welcome"
105
- * variant="A1"
106
- * backgroundImage="/hero.jpg"
107
- * overlayOpacity={0.4}
108
- * />
109
- * ```
110
- */
111
- const Hero = React.forwardRef<HTMLElement, HeroProps>(
112
- (
113
- {
114
- className,
115
- title,
116
- variant,
117
- backgroundImage,
118
- backgroundVideo,
119
- overlayOpacity = 0,
120
- overlayColor = "black",
121
- backgroundPosition = "center",
122
- ...props
123
- },
124
- ref,
125
- ) => {
126
- const hasBackground = backgroundImage || backgroundVideo;
127
-
128
- return (
129
- <section
130
- ref={ref}
131
- className={cn(
132
- heroVariants({ variant }),
133
- hasBackground && "relative overflow-hidden",
134
- className,
135
- )}
136
- {...props}
137
- >
138
- {/* Background image */}
139
- {backgroundImage && !backgroundVideo && (
140
- <div
141
- aria-hidden="true"
142
- className="absolute inset-0 bg-cover"
143
- style={{
144
- backgroundImage: `url(${backgroundImage})`,
145
- backgroundPosition,
146
- }}
147
- />
148
- )}
149
-
150
- {/* Background video */}
151
- {backgroundVideo && (
152
- <video
153
- autoPlay
154
- loop
155
- muted
156
- playsInline
157
- aria-hidden="true"
158
- className="absolute inset-0 h-full w-full object-cover"
159
- >
160
- <source src={backgroundVideo} />
161
- </video>
162
- )}
163
-
164
- {/* Overlay */}
165
- {hasBackground && overlayOpacity > 0 && (
166
- <div
167
- aria-hidden="true"
168
- className="absolute inset-0"
169
- style={{
170
- backgroundColor: overlayColor,
171
- opacity: overlayOpacity,
172
- }}
173
- />
174
- )}
175
-
176
- {/* Content */}
177
- <h1
178
- className={cn(
179
- "typography-display-large text-gray-50",
180
- hasBackground && "relative z-10",
181
- )}
182
- >
183
- {title}
184
- </h1>
185
- </section>
186
- );
187
- },
188
- );
189
- Hero.displayName = "Hero";
190
-
191
- export { Hero, heroVariants };
@@ -1,140 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import { page } from "vitest/browser";
3
- import { render } from "vitest-browser-react";
4
- import { Hero } from "./hero";
5
-
6
- describe("Hero Visual Regression", () => {
7
- // =========================================================================
8
- // Variant A1 (Content at bottom) - Default
9
- // =========================================================================
10
- describe("Variant A1", () => {
11
- test("A1 desktop renders correctly", async () => {
12
- await page.viewport(1440, 900);
13
-
14
- render(<Hero data-testid="hero" variant="A1" title="Hero A1" />);
15
-
16
- await expect(page.getByTestId("hero")).toMatchScreenshot(
17
- "hero-a1-desktop",
18
- );
19
- });
20
-
21
- test("A1 tablet renders correctly", async () => {
22
- await page.viewport(834, 700);
23
-
24
- render(<Hero data-testid="hero" variant="A1" title="Hero A1" />);
25
-
26
- await expect(page.getByTestId("hero")).toMatchScreenshot(
27
- "hero-a1-tablet",
28
- );
29
- });
30
-
31
- test("A1 mobile renders correctly", async () => {
32
- await page.viewport(393, 600);
33
-
34
- render(<Hero data-testid="hero" variant="A1" title="Hero A1" />);
35
-
36
- await expect(page.getByTestId("hero")).toMatchScreenshot(
37
- "hero-a1-mobile",
38
- );
39
- });
40
- });
41
-
42
- // =========================================================================
43
- // Variant A2 (Content at top)
44
- // =========================================================================
45
- describe("Variant A2", () => {
46
- test("A2 desktop renders correctly", async () => {
47
- await page.viewport(1440, 900);
48
-
49
- render(<Hero data-testid="hero" variant="A2" title="Hero A2" />);
50
-
51
- await expect(page.getByTestId("hero")).toMatchScreenshot(
52
- "hero-a2-desktop",
53
- );
54
- });
55
-
56
- test("A2 tablet renders correctly", async () => {
57
- await page.viewport(834, 700);
58
-
59
- render(<Hero data-testid="hero" variant="A2" title="Hero A2" />);
60
-
61
- await expect(page.getByTestId("hero")).toMatchScreenshot(
62
- "hero-a2-tablet",
63
- );
64
- });
65
-
66
- test("A2 mobile renders correctly", async () => {
67
- await page.viewport(393, 600);
68
-
69
- render(<Hero data-testid="hero" variant="A2" title="Hero A2" />);
70
-
71
- await expect(page.getByTestId("hero")).toMatchScreenshot(
72
- "hero-a2-mobile",
73
- );
74
- });
75
- });
76
-
77
- // =========================================================================
78
- // Variant A3 (Content centered)
79
- // =========================================================================
80
- describe("Variant A3", () => {
81
- test("A3 desktop renders correctly", async () => {
82
- await page.viewport(1440, 900);
83
-
84
- render(<Hero data-testid="hero" variant="A3" title="Hero A3" />);
85
-
86
- await expect(page.getByTestId("hero")).toMatchScreenshot(
87
- "hero-a3-desktop",
88
- );
89
- });
90
-
91
- test("A3 tablet renders correctly", async () => {
92
- await page.viewport(834, 700);
93
-
94
- render(<Hero data-testid="hero" variant="A3" title="Hero A3" />);
95
-
96
- await expect(page.getByTestId("hero")).toMatchScreenshot(
97
- "hero-a3-tablet",
98
- );
99
- });
100
-
101
- test("A3 mobile renders correctly", async () => {
102
- await page.viewport(393, 600);
103
-
104
- render(<Hero data-testid="hero" variant="A3" title="Hero A3" />);
105
-
106
- await expect(page.getByTestId("hero")).toMatchScreenshot(
107
- "hero-a3-mobile",
108
- );
109
- });
110
- });
111
-
112
- // =========================================================================
113
- // Additional tests
114
- // =========================================================================
115
- test("hero with long title renders correctly", async () => {
116
- await page.viewport(1280, 800);
117
-
118
- render(
119
- <Hero data-testid="hero" title="A Much Longer Hero Title That Wraps" />,
120
- );
121
-
122
- await expect(page.getByTestId("hero")).toMatchScreenshot("hero-long-title");
123
- });
124
-
125
- test("hero with custom className renders correctly", async () => {
126
- await page.viewport(1280, 800);
127
-
128
- render(
129
- <Hero
130
- data-testid="hero"
131
- title="Custom Background"
132
- className="bg-blue-600"
133
- />,
134
- );
135
-
136
- await expect(page.getByTestId("hero")).toMatchScreenshot(
137
- "hero-custom-class",
138
- );
139
- });
140
- });
@@ -1 +0,0 @@
1
- export { Hero, type HeroProps, heroVariants } from "./hero";
@@ -1,6 +0,0 @@
1
- export {
2
- Prose,
3
- type ProseProps,
4
- ProseSection,
5
- type ProseSectionProps,
6
- } from "./prose";