@nationaldesignstudio/react 0.5.2 → 0.5.3

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 (160) hide show
  1. package/package.json +10 -2
  2. package/src/App.css +0 -0
  3. package/src/App.tsx +0 -7
  4. package/src/assets/fonts/PPNeueMontreal-Variable.woff2 +0 -0
  5. package/src/assets/react.svg +0 -1
  6. package/src/components/atoms/accordion/accordion.stories.tsx +0 -228
  7. package/src/components/atoms/accordion/accordion.test.tsx +0 -231
  8. package/src/components/atoms/accordion/index.ts +0 -6
  9. package/src/components/atoms/background/background.test.tsx +0 -213
  10. package/src/components/atoms/background/index.ts +0 -22
  11. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-darwin.png +0 -0
  12. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-chromium-linux.png +0 -0
  13. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-darwin.png +0 -0
  14. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-chromium-linux.png +0 -0
  15. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-darwin.png +0 -0
  16. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-charcoal-outline-quiet-chromium-linux.png +0 -0
  17. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-darwin.png +0 -0
  18. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-disabled-chromium-linux.png +0 -0
  19. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-darwin.png +0 -0
  20. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-chromium-linux.png +0 -0
  21. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-darwin.png +0 -0
  22. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-chromium-linux.png +0 -0
  23. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-darwin.png +0 -0
  24. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-ivory-outline-quiet-chromium-linux.png +0 -0
  25. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-darwin.png +0 -0
  26. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-large-chromium-linux.png +0 -0
  27. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-darwin.png +0 -0
  28. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-medium-chromium-linux.png +0 -0
  29. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-darwin.png +0 -0
  30. package/src/components/atoms/button/__screenshots__/button.visual.test.tsx/button-size-small-chromium-linux.png +0 -0
  31. package/src/components/atoms/button/button.stories.tsx +0 -289
  32. package/src/components/atoms/button/button.test.tsx +0 -419
  33. package/src/components/atoms/button/button.visual.test.tsx +0 -98
  34. package/src/components/atoms/button/icon-button.stories.tsx +0 -260
  35. package/src/components/atoms/button/icon-button.test.tsx +0 -186
  36. package/src/components/atoms/button/index.ts +0 -6
  37. package/src/components/atoms/input/index.ts +0 -17
  38. package/src/components/atoms/input/input-group.stories.tsx +0 -646
  39. package/src/components/atoms/input/input-group.test.tsx +0 -362
  40. package/src/components/atoms/input/input.stories.tsx +0 -228
  41. package/src/components/atoms/input/input.test.tsx +0 -167
  42. package/src/components/atoms/ndstudio-footer/index.ts +0 -1
  43. package/src/components/atoms/pager-control/index.ts +0 -5
  44. package/src/components/atoms/pager-control/pager-control.stories.tsx +0 -207
  45. package/src/components/atoms/pager-control/pager-control.test.tsx +0 -130
  46. package/src/components/atoms/popover/index.ts +0 -30
  47. package/src/components/atoms/popover/popover.stories.tsx +0 -531
  48. package/src/components/atoms/popover/popover.test.tsx +0 -486
  49. package/src/components/atoms/select/index.ts +0 -18
  50. package/src/components/atoms/select/select.stories.tsx +0 -455
  51. package/src/components/atoms/tooltip/index.ts +0 -24
  52. package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -348
  53. package/src/components/atoms/tooltip/tooltip.test.tsx +0 -363
  54. package/src/components/dev-tools/dev-toolbar/dev-toolbar.stories.tsx +0 -73
  55. package/src/components/dev-tools/dev-toolbar/index.ts +0 -1
  56. package/src/components/dev-tools/grid-overlay/index.ts +0 -1
  57. package/src/components/dev-tools/index.ts +0 -2
  58. package/src/components/foundation/typography/typography.stories.tsx +0 -401
  59. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-darwin.png +0 -0
  60. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-default-vertical-chromium-linux.png +0 -0
  61. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-darwin.png +0 -0
  62. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-horizontal-chromium-linux.png +0 -0
  63. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-darwin.png +0 -0
  64. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-minimal-chromium-linux.png +0 -0
  65. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-darwin.png +0 -0
  66. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-actions-chromium-linux.png +0 -0
  67. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-darwin.png +0 -0
  68. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-eyebrow-chromium-linux.png +0 -0
  69. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-darwin.png +0 -0
  70. package/src/components/organisms/card/__screenshots__/card.visual.test.tsx/card-without-image-chromium-linux.png +0 -0
  71. package/src/components/organisms/card/card.stories.tsx +0 -293
  72. package/src/components/organisms/card/card.test.tsx +0 -247
  73. package/src/components/organisms/card/card.visual.test.tsx +0 -197
  74. package/src/components/organisms/card/index.ts +0 -26
  75. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-darwin.png +0 -0
  76. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-active-link-chromium-linux.png +0 -0
  77. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-darwin.png +0 -0
  78. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-brand-only-chromium-linux.png +0 -0
  79. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-darwin.png +0 -0
  80. package/src/components/organisms/navbar/__screenshots__/navbar.visual.test.tsx/navbar-default-chromium-linux.png +0 -0
  81. package/src/components/organisms/navbar/index.ts +0 -18
  82. package/src/components/organisms/navbar/navbar.stories.tsx +0 -313
  83. package/src/components/organisms/navbar/navbar.test.tsx +0 -190
  84. package/src/components/organisms/navbar/navbar.visual.test.tsx +0 -85
  85. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-darwin.png +0 -0
  86. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-icon-chromium-linux.png +0 -0
  87. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-darwin.png +0 -0
  88. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-custom-text-chromium-linux.png +0 -0
  89. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-darwin.png +0 -0
  90. package/src/components/organisms/us-gov-banner/__screenshots__/us-gov-banner.visual.test.tsx/us-gov-banner-default-chromium-linux.png +0 -0
  91. package/src/components/organisms/us-gov-banner/index.ts +0 -5
  92. package/src/components/organisms/us-gov-banner/us-gov-banner.stories.tsx +0 -35
  93. package/src/components/organisms/us-gov-banner/us-gov-banner.test.tsx +0 -107
  94. package/src/components/organisms/us-gov-banner/us-gov-banner.visual.test.tsx +0 -46
  95. package/src/components/sections/banner/banner.stories.tsx +0 -150
  96. package/src/components/sections/banner/banner.test.tsx +0 -185
  97. package/src/components/sections/banner/index.ts +0 -2
  98. package/src/components/sections/card-grid/card-grid.stories.tsx +0 -351
  99. package/src/components/sections/card-grid/index.ts +0 -1
  100. package/src/components/sections/faq-section/faq-section.stories.tsx +0 -453
  101. package/src/components/sections/faq-section/index.ts +0 -2
  102. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-darwin.png +0 -0
  103. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-desktop-chromium-linux.png +0 -0
  104. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-darwin.png +0 -0
  105. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-mobile-chromium-linux.png +0 -0
  106. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-darwin.png +0 -0
  107. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a1-tablet-chromium-linux.png +0 -0
  108. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-darwin.png +0 -0
  109. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-desktop-chromium-linux.png +0 -0
  110. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-darwin.png +0 -0
  111. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-mobile-chromium-linux.png +0 -0
  112. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-darwin.png +0 -0
  113. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a2-tablet-chromium-linux.png +0 -0
  114. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-darwin.png +0 -0
  115. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-desktop-chromium-linux.png +0 -0
  116. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-darwin.png +0 -0
  117. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-mobile-chromium-linux.png +0 -0
  118. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-darwin.png +0 -0
  119. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-a3-tablet-chromium-linux.png +0 -0
  120. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-darwin.png +0 -0
  121. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-custom-class-chromium-linux.png +0 -0
  122. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-default-chromium-linux.png +0 -0
  123. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-darwin.png +0 -0
  124. package/src/components/sections/hero/__screenshots__/hero.visual.test.tsx/hero-long-title-chromium-linux.png +0 -0
  125. package/src/components/sections/hero/hero.stories.tsx +0 -397
  126. package/src/components/sections/hero/hero.test.tsx +0 -138
  127. package/src/components/sections/hero/hero.visual.test.tsx +0 -140
  128. package/src/components/sections/hero/index.ts +0 -23
  129. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-darwin.png +0 -0
  130. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-h3-heading-chromium-linux.png +0 -0
  131. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-darwin.png +0 -0
  132. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-paragraphs-chromium-linux.png +0 -0
  133. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-darwin.png +0 -0
  134. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-multiple-sections-chromium-linux.png +0 -0
  135. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-darwin.png +0 -0
  136. package/src/components/sections/prose/__screenshots__/prose.visual.test.tsx/prose-single-section-chromium-linux.png +0 -0
  137. package/src/components/sections/prose/index.ts +0 -6
  138. package/src/components/sections/prose/prose.stories.tsx +0 -144
  139. package/src/components/sections/prose/prose.test.tsx +0 -178
  140. package/src/components/sections/prose/prose.visual.test.tsx +0 -105
  141. package/src/components/sections/quote-block/index.ts +0 -5
  142. package/src/components/sections/river/index.ts +0 -1
  143. package/src/components/sections/river/river.stories.tsx +0 -237
  144. package/src/components/sections/river/river.test.tsx +0 -268
  145. package/src/components/sections/tout/index.ts +0 -1
  146. package/src/components/sections/tout/tout.stories.tsx +0 -171
  147. package/src/components/sections/tout/tout.test.tsx +0 -242
  148. package/src/components/sections/two-column-section/index.ts +0 -5
  149. package/src/components/sections/two-column-section/two-column-section.stories.tsx +0 -285
  150. package/src/components/shared/index.ts +0 -5
  151. package/src/index.ts +0 -293
  152. package/src/main.tsx +0 -13
  153. package/src/stories/grid-system.stories.tsx +0 -309
  154. package/src/stories/introduction.mdx +0 -128
  155. package/src/stories/theme-provider.stories.tsx +0 -349
  156. package/src/stories/token-showcase.stories.tsx +0 -73
  157. package/src/stories/token-showcase.tsx +0 -777
  158. package/src/styles.css +0 -14
  159. package/src/tests/token-resolution.test.tsx +0 -298
  160. package/src/theme/theme-provider.test.tsx +0 -270
@@ -1,419 +0,0 @@
1
- import { describe, expect, test, vi } from "vitest";
2
- import { page, userEvent } from "vitest/browser";
3
- import { render } from "vitest-browser-react";
4
- import { Button } from "./button";
5
-
6
- /**
7
- * Helper to get computed styles of an element
8
- */
9
- function getStyles(element: HTMLElement) {
10
- return window.getComputedStyle(element);
11
- }
12
-
13
- /**
14
- * Helper to convert rgb/rgba to hex for easier comparison
15
- */
16
- function _rgbToHex(rgb: string): string {
17
- // Handle rgba format
18
- const match = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/);
19
- if (!match) return rgb;
20
-
21
- const r = parseInt(match[1], 10);
22
- const g = parseInt(match[2], 10);
23
- const b = parseInt(match[3], 10);
24
-
25
- return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
26
- }
27
-
28
- describe("Button", () => {
29
- describe("Accessibility", () => {
30
- test("has correct button role", async () => {
31
- render(<Button>Click me</Button>);
32
- await expect
33
- .element(page.getByRole("button", { name: "Click me" }))
34
- .toBeInTheDocument();
35
- });
36
-
37
- test("is focusable via keyboard", async () => {
38
- render(<Button>Focusable</Button>);
39
- await userEvent.keyboard("{Tab}");
40
- await expect
41
- .element(page.getByRole("button", { name: "Focusable" }))
42
- .toHaveFocus();
43
- });
44
-
45
- test("disabled button has disabled attribute", async () => {
46
- render(<Button disabled>Disabled</Button>);
47
- await expect
48
- .element(page.getByRole("button", { name: "Disabled" }))
49
- .toBeDisabled();
50
- });
51
-
52
- test("disabled button is not focusable", async () => {
53
- render(
54
- <>
55
- <Button disabled>Disabled</Button>
56
- <Button>After</Button>
57
- </>,
58
- );
59
- await userEvent.keyboard("{Tab}");
60
- // Focus should skip the disabled button and go to the next one
61
- await expect
62
- .element(page.getByRole("button", { name: "After" }))
63
- .toHaveFocus();
64
- });
65
-
66
- test("button with aria-label has accessible name", async () => {
67
- render(<Button aria-label="Close dialog">×</Button>);
68
- await expect
69
- .element(page.getByRole("button", { name: "Close dialog" }))
70
- .toBeInTheDocument();
71
- });
72
-
73
- test("button type defaults to button (not submit)", async () => {
74
- render(<Button>Click me</Button>);
75
- await expect
76
- .element(page.getByRole("button", { name: "Click me" }))
77
- .toHaveAttribute("type", "button");
78
- });
79
-
80
- test("button type can be set explicitly to submit", async () => {
81
- render(<Button type="submit">Submit</Button>);
82
- await expect
83
- .element(page.getByRole("button", { name: "Submit" }))
84
- .toHaveAttribute("type", "submit");
85
- });
86
- });
87
-
88
- describe("Interactions", () => {
89
- test("calls onClick when clicked", async () => {
90
- const handleClick = vi.fn();
91
- render(<Button onClick={handleClick}>Click me</Button>);
92
- await page.getByRole("button", { name: "Click me" }).click();
93
- expect(handleClick).toHaveBeenCalledOnce();
94
- });
95
-
96
- test("responds to Enter key when focused", async () => {
97
- const handleClick = vi.fn();
98
- render(<Button onClick={handleClick}>Enter key</Button>);
99
- page.getByRole("button", { name: "Enter key" }).element().focus();
100
- await userEvent.keyboard("{Enter}");
101
- expect(handleClick).toHaveBeenCalledOnce();
102
- });
103
-
104
- test("responds to Space key when focused", async () => {
105
- const handleClick = vi.fn();
106
- render(<Button onClick={handleClick}>Space key</Button>);
107
- page.getByRole("button", { name: "Space key" }).element().focus();
108
- await userEvent.keyboard(" ");
109
- expect(handleClick).toHaveBeenCalledOnce();
110
- });
111
-
112
- test("does not fire onClick when disabled", async () => {
113
- const handleClick = vi.fn();
114
- render(
115
- <Button disabled onClick={handleClick}>
116
- Disabled
117
- </Button>,
118
- );
119
- await page
120
- .getByRole("button", { name: "Disabled" })
121
- .click({ force: true });
122
- expect(handleClick).not.toHaveBeenCalled();
123
- });
124
-
125
- test("supports multiple clicks", async () => {
126
- const handleClick = vi.fn();
127
- render(<Button onClick={handleClick}>Multi click</Button>);
128
- const button = page.getByRole("button", { name: "Multi click" });
129
- await button.click();
130
- await button.click();
131
- await button.click();
132
- expect(handleClick).toHaveBeenCalledTimes(3);
133
- });
134
- });
135
-
136
- describe("render prop", () => {
137
- test("renders as anchor element with button role when render prop is used", async () => {
138
- render(
139
- // biome-ignore lint/a11y/useAnchorContent: Content provided via Button children
140
- <Button render={<a href="/test" />}>Link Button</Button>,
141
- );
142
- // Base UI keeps role="button" for accessibility when rendering as another element
143
- const button = page.getByRole("button", { name: "Link Button" });
144
- await expect.element(button).toBeInTheDocument();
145
- await expect.element(button).toHaveAttribute("href", "/test");
146
- });
147
- });
148
-
149
- describe("Variant Styles", () => {
150
- test("default variant has dark background", async () => {
151
- render(<Button variant="default">Default</Button>);
152
- const button = page.getByRole("button", { name: "Default" });
153
- await expect.element(button).toBeInTheDocument();
154
-
155
- const element = button.element();
156
- const styles = getStyles(element);
157
-
158
- // Default variant should have a dark background (gray-1200)
159
- // The actual color depends on CSS variables, but it should not be transparent
160
- expect(styles.backgroundColor).not.toBe("rgba(0, 0, 0, 0)");
161
- expect(styles.backgroundColor).not.toBe("transparent");
162
- });
163
-
164
- test("primary variant has blue background", async () => {
165
- render(<Button variant="primary">Primary</Button>);
166
- const button = page.getByRole("button", { name: "Primary" });
167
- await expect.element(button).toBeInTheDocument();
168
-
169
- const element = button.element();
170
- const styles = getStyles(element);
171
-
172
- // Primary variant should have a visible background
173
- expect(styles.backgroundColor).not.toBe("rgba(0, 0, 0, 0)");
174
- expect(styles.backgroundColor).not.toBe("transparent");
175
- });
176
-
177
- test("destructive variant has red-tinted background", async () => {
178
- render(<Button variant="destructive">Delete</Button>);
179
- const button = page.getByRole("button", { name: "Delete" });
180
- await expect.element(button).toBeInTheDocument();
181
-
182
- const element = button.element();
183
- const styles = getStyles(element);
184
-
185
- // Destructive variant should have a visible background
186
- expect(styles.backgroundColor).not.toBe("rgba(0, 0, 0, 0)");
187
- expect(styles.backgroundColor).not.toBe("transparent");
188
- });
189
-
190
- test("ghost variant has transparent background", async () => {
191
- render(<Button variant="ghost">Ghost</Button>);
192
- const button = page.getByRole("button", { name: "Ghost" });
193
- await expect.element(button).toBeInTheDocument();
194
-
195
- const element = button.element();
196
- const styles = getStyles(element);
197
-
198
- // Ghost variant should have transparent background
199
- expect(
200
- styles.backgroundColor === "rgba(0, 0, 0, 0)" ||
201
- styles.backgroundColor === "transparent",
202
- ).toBe(true);
203
- });
204
-
205
- test("link variant has no background and underline on hover behavior", async () => {
206
- render(<Button variant="link">Link</Button>);
207
- const button = page.getByRole("button", { name: "Link" });
208
- await expect.element(button).toBeInTheDocument();
209
-
210
- const element = button.element();
211
- const styles = getStyles(element);
212
-
213
- // Link variant should have transparent background
214
- expect(
215
- styles.backgroundColor === "rgba(0, 0, 0, 0)" ||
216
- styles.backgroundColor === "transparent",
217
- ).toBe(true);
218
- });
219
-
220
- test("outline variant has visible border", async () => {
221
- render(<Button variant="outline">Outline</Button>);
222
- const button = page.getByRole("button", { name: "Outline" });
223
- await expect.element(button).toBeInTheDocument();
224
-
225
- const element = button.element();
226
- const styles = getStyles(element);
227
-
228
- // Outline variant should have a visible border
229
- const borderWidth = parseFloat(styles.borderWidth) || 0;
230
- expect(borderWidth).toBeGreaterThan(0);
231
- });
232
-
233
- test("secondary variant has light gray background with border", async () => {
234
- render(<Button variant="secondary">Secondary</Button>);
235
- const button = page.getByRole("button", { name: "Secondary" });
236
- await expect.element(button).toBeInTheDocument();
237
-
238
- const element = button.element();
239
- const styles = getStyles(element);
240
-
241
- // Secondary variant should have a visible background
242
- expect(styles.backgroundColor).not.toBe("rgba(0, 0, 0, 0)");
243
- expect(styles.backgroundColor).not.toBe("transparent");
244
-
245
- // Secondary should also have a border
246
- const borderWidth = parseFloat(styles.borderWidth) || 0;
247
- expect(borderWidth).toBeGreaterThan(0);
248
- });
249
- });
250
-
251
- describe("Size Styles", () => {
252
- test("small size has 32px height", async () => {
253
- render(<Button size="sm">Small</Button>);
254
- const button = page.getByRole("button", { name: "Small" });
255
- await expect.element(button).toBeInTheDocument();
256
-
257
- const element = button.element();
258
- const styles = getStyles(element);
259
-
260
- // Small button should be 32px height
261
- expect(styles.height).toBe("32px");
262
- });
263
-
264
- test("default size has 36px height", async () => {
265
- render(<Button size="default">Default</Button>);
266
- const button = page.getByRole("button", { name: "Default" });
267
- await expect.element(button).toBeInTheDocument();
268
-
269
- const element = button.element();
270
- const styles = getStyles(element);
271
-
272
- // Default button should be 36px height
273
- expect(styles.height).toBe("36px");
274
- });
275
-
276
- test("large size has 40px height", async () => {
277
- render(<Button size="lg">Large</Button>);
278
- const button = page.getByRole("button", { name: "Large" });
279
- await expect.element(button).toBeInTheDocument();
280
-
281
- const element = button.element();
282
- const styles = getStyles(element);
283
-
284
- // Large button should be 40px height
285
- expect(styles.height).toBe("40px");
286
- });
287
-
288
- test("size affects padding appropriately", async () => {
289
- render(
290
- <>
291
- <Button size="sm">Small</Button>
292
- <Button size="lg">Large</Button>
293
- </>,
294
- );
295
- const smallButton = page.getByRole("button", { name: "Small" });
296
- const largeButton = page.getByRole("button", { name: "Large" });
297
-
298
- const smallStyles = getStyles(smallButton.element());
299
- const largeStyles = getStyles(largeButton.element());
300
-
301
- const smallPaddingLeft = parseFloat(smallStyles.paddingLeft);
302
- const largePaddingLeft = parseFloat(largeStyles.paddingLeft);
303
-
304
- // Large should have more padding than small
305
- expect(largePaddingLeft).toBeGreaterThan(smallPaddingLeft);
306
- });
307
-
308
- test("size affects border radius appropriately", async () => {
309
- render(
310
- <>
311
- <Button size="sm">Small</Button>
312
- <Button size="lg">Large</Button>
313
- </>,
314
- );
315
- const smallButton = page.getByRole("button", { name: "Small" });
316
- const largeButton = page.getByRole("button", { name: "Large" });
317
-
318
- const smallStyles = getStyles(smallButton.element());
319
- const largeStyles = getStyles(largeButton.element());
320
-
321
- const smallRadius = parseFloat(smallStyles.borderRadius);
322
- const largeRadius = parseFloat(largeStyles.borderRadius);
323
-
324
- // Large should have more border radius than small
325
- // Figma: sm=4px, default=6px, lg=10px
326
- expect(largeRadius).toBeGreaterThan(smallRadius);
327
- });
328
- });
329
-
330
- describe("Disabled State Styles", () => {
331
- test("disabled button has reduced opacity", async () => {
332
- render(<Button disabled>Disabled</Button>);
333
- const button = page.getByRole("button", { name: "Disabled" });
334
- await expect.element(button).toBeInTheDocument();
335
-
336
- const element = button.element();
337
- const styles = getStyles(element);
338
-
339
- // Disabled button should have opacity of 0.5
340
- expect(parseFloat(styles.opacity)).toBe(0.5);
341
- });
342
-
343
- test("disabled button has pointer-events none", async () => {
344
- render(<Button disabled>Disabled</Button>);
345
- const button = page.getByRole("button", { name: "Disabled" });
346
- await expect.element(button).toBeInTheDocument();
347
-
348
- const element = button.element();
349
- const styles = getStyles(element);
350
-
351
- expect(styles.pointerEvents).toBe("none");
352
- });
353
- });
354
-
355
- describe("Data Attributes", () => {
356
- test("button has correct data-variant attribute", async () => {
357
- render(<Button variant="destructive">Test</Button>);
358
- const button = page.getByRole("button", { name: "Test" });
359
-
360
- await expect
361
- .element(button)
362
- .toHaveAttribute("data-variant", "destructive");
363
- });
364
-
365
- test("button has correct data-size attribute", async () => {
366
- render(<Button size="lg">Test</Button>);
367
- const button = page.getByRole("button", { name: "Test" });
368
-
369
- await expect.element(button).toHaveAttribute("data-size", "lg");
370
- });
371
-
372
- test("default variant and size are reflected in data attributes", async () => {
373
- render(<Button>Test</Button>);
374
- const button = page.getByRole("button", { name: "Test" });
375
-
376
- await expect.element(button).toHaveAttribute("data-variant", "default");
377
- await expect.element(button).toHaveAttribute("data-size", "default");
378
- });
379
- });
380
-
381
- describe("Layout Styles", () => {
382
- test("button uses flexbox for content alignment", async () => {
383
- render(<Button>Test</Button>);
384
- const button = page.getByRole("button", { name: "Test" });
385
- await expect.element(button).toBeInTheDocument();
386
-
387
- const element = button.element();
388
- const styles = getStyles(element);
389
-
390
- expect(styles.display).toBe("inline-flex");
391
- expect(styles.alignItems).toBe("center");
392
- expect(styles.justifyContent).toBe("center");
393
- });
394
-
395
- test("button has cursor pointer", async () => {
396
- render(<Button>Test</Button>);
397
- const button = page.getByRole("button", { name: "Test" });
398
- await expect.element(button).toBeInTheDocument();
399
-
400
- const element = button.element();
401
- const styles = getStyles(element);
402
-
403
- expect(styles.cursor).toBe("pointer");
404
- });
405
-
406
- test("button has gap for icon-text spacing", async () => {
407
- render(<Button>Test</Button>);
408
- const button = page.getByRole("button", { name: "Test" });
409
- await expect.element(button).toBeInTheDocument();
410
-
411
- const element = button.element();
412
- const styles = getStyles(element);
413
-
414
- // Gap should be set (6px from Figma)
415
- const gap = parseFloat(styles.gap);
416
- expect(gap).toBeGreaterThan(0);
417
- });
418
- });
419
- });
@@ -1,98 +0,0 @@
1
- import { render } from "@testing-library/react";
2
- import { describe, expect, test } from "vitest";
3
- import { page } from "vitest/browser";
4
- import { Button } from "./button";
5
-
6
- describe("Button Visual Regression", () => {
7
- test("primary variant renders correctly", async () => {
8
- render(<Button variant="primary">Primary Button</Button>);
9
-
10
- await expect(
11
- page.getByRole("button", { name: "Primary Button" }),
12
- ).toMatchScreenshot("button-primary");
13
- });
14
-
15
- test("primary-outline variant renders correctly", async () => {
16
- render(<Button variant="primary-outline">Primary Outline Button</Button>);
17
-
18
- await expect(
19
- page.getByRole("button", { name: "Primary Outline Button" }),
20
- ).toMatchScreenshot("button-primary-outline");
21
- });
22
-
23
- test("secondary variant renders correctly", async () => {
24
- render(
25
- <div style={{ background: "#1a1a1a", padding: "20px" }}>
26
- <Button variant="secondary">Secondary Button</Button>
27
- </div>,
28
- );
29
-
30
- await expect(
31
- page.getByRole("button", { name: "Secondary Button" }),
32
- ).toMatchScreenshot("button-secondary");
33
- });
34
-
35
- test("secondary-outline variant renders correctly", async () => {
36
- render(
37
- <div style={{ background: "#1a1a1a", padding: "20px" }}>
38
- <Button variant="secondary-outline">Secondary Outline Button</Button>
39
- </div>,
40
- );
41
-
42
- await expect(
43
- page.getByRole("button", { name: "Secondary Outline Button" }),
44
- ).toMatchScreenshot("button-secondary-outline");
45
- });
46
-
47
- test("ghost variant renders correctly", async () => {
48
- render(<Button variant="ghost">Ghost Button</Button>);
49
-
50
- await expect(
51
- page.getByRole("button", { name: "Ghost Button" }),
52
- ).toMatchScreenshot("button-ghost");
53
- });
54
-
55
- test("ghost-inverse variant renders correctly", async () => {
56
- render(
57
- <div style={{ background: "#1a1a1a", padding: "20px" }}>
58
- <Button variant="ghost-inverse">Ghost Inverse Button</Button>
59
- </div>,
60
- );
61
-
62
- await expect(
63
- page.getByRole("button", { name: "Ghost Inverse Button" }),
64
- ).toMatchScreenshot("button-ghost-inverse");
65
- });
66
-
67
- test("small size renders correctly", async () => {
68
- render(<Button size="sm">Small Button</Button>);
69
-
70
- await expect(
71
- page.getByRole("button", { name: "Small Button" }),
72
- ).toMatchScreenshot("button-size-small");
73
- });
74
-
75
- test("medium size renders correctly", async () => {
76
- render(<Button size="md">Medium Button</Button>);
77
-
78
- await expect(
79
- page.getByRole("button", { name: "Medium Button" }),
80
- ).toMatchScreenshot("button-size-medium");
81
- });
82
-
83
- test("large size renders correctly", async () => {
84
- render(<Button size="lg">Large Button</Button>);
85
-
86
- await expect(
87
- page.getByRole("button", { name: "Large Button" }),
88
- ).toMatchScreenshot("button-size-large");
89
- });
90
-
91
- test("disabled state renders correctly", async () => {
92
- render(<Button disabled>Disabled Button</Button>);
93
-
94
- await expect(
95
- page.getByRole("button", { name: "Disabled Button" }),
96
- ).toMatchScreenshot("button-disabled");
97
- });
98
- });