@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,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
- });