@buildcanada/components 0.3.3 → 0.3.5
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.
- package/dist/content/Card/Card.d.ts +62 -0
- package/dist/content/Card/Card.d.ts.map +1 -0
- package/dist/content/Card/Card.js +45 -0
- package/dist/content/Card/Card.scss +281 -0
- package/dist/content/Card/index.d.ts +3 -0
- package/dist/content/Card/index.d.ts.map +1 -0
- package/dist/content/Card/index.js +2 -0
- package/dist/content/Hero/Hero.d.ts +28 -0
- package/dist/content/Hero/Hero.d.ts.map +1 -0
- package/dist/content/Hero/Hero.js +16 -0
- package/dist/content/Hero/Hero.scss +150 -0
- package/dist/content/Hero/index.d.ts +3 -0
- package/dist/content/Hero/index.d.ts.map +1 -0
- package/dist/content/Hero/index.js +2 -0
- package/dist/content/StatBlock/StatBlock.d.ts +15 -0
- package/dist/content/StatBlock/StatBlock.d.ts.map +1 -0
- package/dist/content/StatBlock/StatBlock.js +10 -0
- package/dist/content/StatBlock/StatBlock.scss +83 -0
- package/dist/content/StatBlock/index.d.ts +3 -0
- package/dist/content/StatBlock/index.d.ts.map +1 -0
- package/dist/content/StatBlock/index.js +2 -0
- package/dist/feedback/Dialog/Dialog.d.ts +18 -0
- package/dist/feedback/Dialog/Dialog.d.ts.map +1 -0
- package/dist/feedback/Dialog/Dialog.js +33 -0
- package/dist/feedback/Dialog/Dialog.scss +158 -0
- package/dist/feedback/Dialog/index.d.ts +2 -0
- package/dist/feedback/Dialog/index.d.ts.map +1 -0
- package/dist/feedback/Dialog/index.js +1 -0
- package/dist/feedback/PopupForm/PopupForm.d.ts +24 -0
- package/dist/feedback/PopupForm/PopupForm.d.ts.map +1 -0
- package/dist/feedback/PopupForm/PopupForm.js +13 -0
- package/dist/feedback/PopupForm/PopupForm.scss +34 -0
- package/dist/feedback/PopupForm/index.d.ts +2 -0
- package/dist/feedback/PopupForm/index.d.ts.map +1 -0
- package/dist/feedback/PopupForm/index.js +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/layout/Container/Container.d.ts +11 -0
- package/dist/layout/Container/Container.d.ts.map +1 -0
- package/dist/layout/Container/Container.js +7 -0
- package/dist/layout/Container/Container.scss +40 -0
- package/dist/layout/Container/index.d.ts +3 -0
- package/dist/layout/Container/index.d.ts.map +1 -0
- package/dist/layout/Container/index.js +2 -0
- package/dist/layout/Divider/Divider.d.ts +12 -0
- package/dist/layout/Divider/Divider.d.ts.map +1 -0
- package/dist/layout/Divider/Divider.js +7 -0
- package/dist/layout/Divider/Divider.scss +117 -0
- package/dist/layout/Divider/index.d.ts +3 -0
- package/dist/layout/Divider/index.d.ts.map +1 -0
- package/dist/layout/Divider/index.js +2 -0
- package/dist/layout/Grid/Grid.d.ts +24 -0
- package/dist/layout/Grid/Grid.d.ts.map +1 -0
- package/dist/layout/Grid/Grid.js +11 -0
- package/dist/layout/Grid/Grid.scss +81 -0
- package/dist/layout/Grid/index.d.ts +3 -0
- package/dist/layout/Grid/index.d.ts.map +1 -0
- package/dist/layout/Grid/index.js +2 -0
- package/dist/layout/Section/Section.d.ts +13 -0
- package/dist/layout/Section/Section.d.ts.map +1 -0
- package/dist/layout/Section/Section.js +7 -0
- package/dist/layout/Section/Section.scss +74 -0
- package/dist/layout/Section/index.d.ts +3 -0
- package/dist/layout/Section/index.d.ts.map +1 -0
- package/dist/layout/Section/index.js +2 -0
- package/dist/layout/Stack/Stack.d.ts +18 -0
- package/dist/layout/Stack/Stack.d.ts.map +1 -0
- package/dist/layout/Stack/Stack.js +7 -0
- package/dist/layout/Stack/Stack.scss +61 -0
- package/dist/layout/Stack/index.d.ts +3 -0
- package/dist/layout/Stack/index.d.ts.map +1 -0
- package/dist/layout/Stack/index.js +2 -0
- package/dist/navigation/Footer/Footer.d.ts +31 -0
- package/dist/navigation/Footer/Footer.d.ts.map +1 -0
- package/dist/navigation/Footer/Footer.js +21 -0
- package/dist/navigation/Footer/Footer.scss +233 -0
- package/dist/navigation/Footer/index.d.ts +3 -0
- package/dist/navigation/Footer/index.d.ts.map +1 -0
- package/dist/navigation/Footer/index.js +2 -0
- package/dist/navigation/Header/Header.d.ts +23 -0
- package/dist/navigation/Header/Header.d.ts.map +1 -0
- package/dist/navigation/Header/Header.js +16 -0
- package/dist/navigation/Header/Header.scss +325 -0
- package/dist/navigation/Header/index.d.ts +3 -0
- package/dist/navigation/Header/index.d.ts.map +1 -0
- package/dist/navigation/Header/index.js +2 -0
- package/dist/primitives/Button/Button.d.ts +31 -0
- package/dist/primitives/Button/Button.d.ts.map +1 -0
- package/dist/primitives/Button/Button.js +36 -0
- package/dist/primitives/Button/Button.scss +218 -0
- package/dist/primitives/Button/index.d.ts +3 -0
- package/dist/primitives/Button/index.d.ts.map +1 -0
- package/dist/primitives/Button/index.js +2 -0
- package/dist/primitives/Checkbox/Checkbox.d.ts +13 -0
- package/dist/primitives/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/primitives/Checkbox/Checkbox.js +10 -0
- package/dist/primitives/Checkbox/Checkbox.scss +114 -0
- package/dist/primitives/Checkbox/index.d.ts +3 -0
- package/dist/primitives/Checkbox/index.d.ts.map +1 -0
- package/dist/primitives/Checkbox/index.js +2 -0
- package/dist/primitives/TextField/TextField.d.ts +22 -0
- package/dist/primitives/TextField/TextField.d.ts.map +1 -0
- package/dist/primitives/TextField/TextField.js +14 -0
- package/dist/primitives/TextField/TextField.scss +93 -0
- package/dist/primitives/TextField/index.d.ts +3 -0
- package/dist/primitives/TextField/index.d.ts.map +1 -0
- package/dist/primitives/TextField/index.js +2 -0
- package/dist/styles/fonts.scss +27 -0
- package/dist/styles/main.scss +36 -0
- package/dist/styles/tokens.scss +301 -0
- package/dist/styles/typography.scss +232 -0
- package/package.json +12 -11
- package/src/content/Card/Card.stories.tsx +389 -0
- package/src/content/Card/index.ts +2 -2
- package/src/content/Hero/Hero.stories.tsx +299 -0
- package/src/content/Hero/index.ts +2 -2
- package/src/content/StatBlock/StatBlock.stories.tsx +331 -0
- package/src/content/StatBlock/index.ts +2 -2
- package/src/feedback/Dialog/Dialog.stories.tsx +286 -0
- package/src/feedback/Dialog/index.ts +1 -1
- package/src/feedback/PopupForm/PopupForm.stories.tsx +341 -0
- package/src/feedback/PopupForm/PopupForm.tsx +2 -2
- package/src/feedback/PopupForm/index.ts +1 -1
- package/src/index.ts +15 -15
- package/src/layout/Container/Container.stories.tsx +153 -0
- package/src/layout/Container/index.ts +2 -2
- package/src/layout/Divider/Divider.stories.tsx +204 -0
- package/src/layout/Divider/index.ts +2 -2
- package/src/layout/Grid/Grid.stories.tsx +263 -0
- package/src/layout/Grid/index.ts +2 -2
- package/src/layout/Section/Section.stories.tsx +173 -0
- package/src/layout/Section/index.ts +2 -2
- package/src/layout/Stack/Stack.stories.tsx +342 -0
- package/src/layout/Stack/index.ts +2 -2
- package/src/navigation/Footer/Footer.stories.tsx +351 -0
- package/src/navigation/Footer/index.ts +2 -2
- package/src/navigation/Header/Header.stories.tsx +346 -0
- package/src/navigation/Header/index.ts +2 -2
- package/src/primitives/Button/Button.stories.tsx +300 -0
- package/src/primitives/Button/index.ts +2 -2
- package/src/primitives/Checkbox/Checkbox.stories.tsx +204 -0
- package/src/primitives/Checkbox/index.ts +2 -2
- package/src/primitives/TextField/TextField.stories.tsx +265 -0
- package/src/primitives/TextField/index.ts +2 -2
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { within, userEvent, expect } from "@storybook/test"
|
|
3
|
+
|
|
4
|
+
import { Header } from "./Header"
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Header> = {
|
|
7
|
+
title: "Components/Navigation/Header",
|
|
8
|
+
component: Header,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "fullscreen",
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component: `
|
|
14
|
+
A responsive site header with navigation, logo, CTA button, and optional announcement banner.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
\`\`\`tsx
|
|
19
|
+
import { Header } from "@buildcanada/components"
|
|
20
|
+
|
|
21
|
+
<Header
|
|
22
|
+
logo={<Logo />}
|
|
23
|
+
navItems={[
|
|
24
|
+
{ label: "Home", href: "/" },
|
|
25
|
+
{ label: "About", href: "/about" },
|
|
26
|
+
{ label: "Projects", href: "/projects" },
|
|
27
|
+
]}
|
|
28
|
+
cta={{ label: "Get Started", href: "/start" }}
|
|
29
|
+
/>
|
|
30
|
+
\`\`\`
|
|
31
|
+
|
|
32
|
+
## With Dropdowns
|
|
33
|
+
|
|
34
|
+
\`\`\`tsx
|
|
35
|
+
<Header
|
|
36
|
+
logo={<Logo />}
|
|
37
|
+
navItems={[
|
|
38
|
+
{ label: "Home", href: "/" },
|
|
39
|
+
{
|
|
40
|
+
label: "Projects",
|
|
41
|
+
href: "/projects",
|
|
42
|
+
dropdown: [
|
|
43
|
+
{ label: "Project A", href: "/projects/a" },
|
|
44
|
+
{ label: "Project B", href: "/projects/b" },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
]}
|
|
48
|
+
/>
|
|
49
|
+
\`\`\`
|
|
50
|
+
|
|
51
|
+
## Announcement Banner
|
|
52
|
+
|
|
53
|
+
\`\`\`tsx
|
|
54
|
+
<Header
|
|
55
|
+
logo={<Logo />}
|
|
56
|
+
navItems={navItems}
|
|
57
|
+
announcement={{
|
|
58
|
+
text: "New feature available!",
|
|
59
|
+
href: "/new-feature",
|
|
60
|
+
variant: "auburn", // or "default"
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
## Responsive
|
|
66
|
+
|
|
67
|
+
On mobile, navigation collapses into a hamburger menu.
|
|
68
|
+
`,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default meta
|
|
75
|
+
type Story = StoryObj<typeof Header>
|
|
76
|
+
|
|
77
|
+
const Logo = () => (
|
|
78
|
+
<span style={{
|
|
79
|
+
fontFamily: "'Soehne Kraftig', 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
|
80
|
+
fontSize: "18px",
|
|
81
|
+
fontWeight: 500,
|
|
82
|
+
color: "#272727",
|
|
83
|
+
letterSpacing: "-0.01em",
|
|
84
|
+
}}>
|
|
85
|
+
Build Canada
|
|
86
|
+
</span>
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const basicNavItems = [
|
|
90
|
+
{ label: "Home", href: "/" },
|
|
91
|
+
{ label: "About", href: "/about" },
|
|
92
|
+
{ label: "Projects", href: "/projects" },
|
|
93
|
+
{ label: "Contact", href: "/contact" },
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
const navWithDropdowns = [
|
|
97
|
+
{ label: "Home", href: "/" },
|
|
98
|
+
{
|
|
99
|
+
label: "Projects",
|
|
100
|
+
href: "/projects",
|
|
101
|
+
dropdown: [
|
|
102
|
+
{ label: "Canada Spends", href: "/projects/canada-spends" },
|
|
103
|
+
{ label: "Budget Tracker", href: "/projects/budget-tracker" },
|
|
104
|
+
{ label: "Data Explorer", href: "/projects/data-explorer" },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
label: "Research",
|
|
109
|
+
href: "/research",
|
|
110
|
+
dropdown: [
|
|
111
|
+
{ label: "Reports", href: "/research/reports" },
|
|
112
|
+
{ label: "Analysis", href: "/research/analysis" },
|
|
113
|
+
{ label: "Publications", href: "/research/publications" },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{ label: "About", href: "/about" },
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
export const Default: Story = {
|
|
120
|
+
args: {
|
|
121
|
+
logo: <Logo />,
|
|
122
|
+
navItems: basicNavItems,
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const WithCTA: Story = {
|
|
127
|
+
args: {
|
|
128
|
+
logo: <Logo />,
|
|
129
|
+
navItems: basicNavItems,
|
|
130
|
+
cta: {
|
|
131
|
+
label: "Get Started",
|
|
132
|
+
href: "/get-started",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const WithAnnouncement: Story = {
|
|
138
|
+
args: {
|
|
139
|
+
logo: <Logo />,
|
|
140
|
+
navItems: basicNavItems,
|
|
141
|
+
cta: {
|
|
142
|
+
label: "Get Started",
|
|
143
|
+
href: "/get-started",
|
|
144
|
+
},
|
|
145
|
+
announcement: {
|
|
146
|
+
text: "New: Canada Spends 2024 data now available!",
|
|
147
|
+
href: "/projects/canada-spends",
|
|
148
|
+
variant: "default",
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export const WithAuburnAnnouncement: Story = {
|
|
154
|
+
args: {
|
|
155
|
+
logo: <Logo />,
|
|
156
|
+
navItems: basicNavItems,
|
|
157
|
+
cta: {
|
|
158
|
+
label: "Get Started",
|
|
159
|
+
href: "/get-started",
|
|
160
|
+
},
|
|
161
|
+
announcement: {
|
|
162
|
+
text: "Breaking: Federal Budget 2024 Analysis",
|
|
163
|
+
href: "/research/budget-2024",
|
|
164
|
+
variant: "auburn",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const WithDropdowns: Story = {
|
|
170
|
+
args: {
|
|
171
|
+
logo: <Logo />,
|
|
172
|
+
navItems: navWithDropdowns,
|
|
173
|
+
cta: {
|
|
174
|
+
label: "Explore Data",
|
|
175
|
+
href: "/explore",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export const MinimalHeader: Story = {
|
|
181
|
+
args: {
|
|
182
|
+
logo: <Logo />,
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export const FullFeatured: Story = {
|
|
187
|
+
args: {
|
|
188
|
+
logo: <Logo />,
|
|
189
|
+
navItems: navWithDropdowns,
|
|
190
|
+
cta: {
|
|
191
|
+
label: "Get Started",
|
|
192
|
+
href: "/get-started",
|
|
193
|
+
},
|
|
194
|
+
announcement: {
|
|
195
|
+
text: "New: 2024 Federal Budget Analysis now available",
|
|
196
|
+
href: "/research/budget-2024",
|
|
197
|
+
variant: "auburn",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export const ManyNavItems: Story = {
|
|
203
|
+
args: {
|
|
204
|
+
logo: <Logo />,
|
|
205
|
+
navItems: [
|
|
206
|
+
{ label: "Home", href: "/" },
|
|
207
|
+
{ label: "About", href: "/about" },
|
|
208
|
+
{ label: "Projects", href: "/projects" },
|
|
209
|
+
{ label: "Research", href: "/research" },
|
|
210
|
+
{ label: "Data", href: "/data" },
|
|
211
|
+
{ label: "Blog", href: "/blog" },
|
|
212
|
+
{ label: "Contact", href: "/contact" },
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export const WithTextLogo: Story = {
|
|
218
|
+
args: {
|
|
219
|
+
logo: (
|
|
220
|
+
<span style={{
|
|
221
|
+
fontFamily: "'Soehne Kraftig', 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
|
222
|
+
fontSize: "20px",
|
|
223
|
+
fontWeight: 500,
|
|
224
|
+
color: "#932F2F",
|
|
225
|
+
letterSpacing: "-0.01em",
|
|
226
|
+
}}>
|
|
227
|
+
Company Name
|
|
228
|
+
</span>
|
|
229
|
+
),
|
|
230
|
+
navItems: basicNavItems,
|
|
231
|
+
cta: {
|
|
232
|
+
label: "Sign Up",
|
|
233
|
+
href: "/signup",
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export const CanadaSpendsHeader: Story = {
|
|
239
|
+
args: {
|
|
240
|
+
logo: (
|
|
241
|
+
<svg width="160" height="24" viewBox="0 0 160 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
242
|
+
<text x="0" y="18" fontFamily="sans-serif" fontSize="16" fontWeight="600" fill="#272727">
|
|
243
|
+
Canada Spends
|
|
244
|
+
</text>
|
|
245
|
+
</svg>
|
|
246
|
+
),
|
|
247
|
+
navItems: [
|
|
248
|
+
{ label: "Charts", href: "/charts" },
|
|
249
|
+
{ label: "Data", href: "/data" },
|
|
250
|
+
{
|
|
251
|
+
label: "Topics",
|
|
252
|
+
href: "/topics",
|
|
253
|
+
dropdown: [
|
|
254
|
+
{ label: "Healthcare", href: "/topics/healthcare" },
|
|
255
|
+
{ label: "Education", href: "/topics/education" },
|
|
256
|
+
{ label: "Defense", href: "/topics/defense" },
|
|
257
|
+
{ label: "Infrastructure", href: "/topics/infrastructure" },
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
{ label: "About", href: "/about" },
|
|
261
|
+
],
|
|
262
|
+
cta: {
|
|
263
|
+
label: "Explore",
|
|
264
|
+
href: "/explore",
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export const ResponsiveDemo: Story = {
|
|
270
|
+
args: {
|
|
271
|
+
logo: <Logo />,
|
|
272
|
+
navItems: navWithDropdowns,
|
|
273
|
+
cta: {
|
|
274
|
+
label: "Get Started",
|
|
275
|
+
href: "/get-started",
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
parameters: {
|
|
279
|
+
docs: {
|
|
280
|
+
description: {
|
|
281
|
+
story: "Resize the viewport to see the responsive behavior. On smaller screens, the navigation collapses into a hamburger menu.",
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Interactive test: Navigation links
|
|
288
|
+
export const NavigationTest: Story = {
|
|
289
|
+
args: {
|
|
290
|
+
logo: <Logo />,
|
|
291
|
+
navItems: basicNavItems,
|
|
292
|
+
cta: {
|
|
293
|
+
label: "Get Started",
|
|
294
|
+
href: "/get-started",
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
play: async ({ canvasElement }) => {
|
|
298
|
+
const canvas = within(canvasElement)
|
|
299
|
+
|
|
300
|
+
// Check that navigation links are present
|
|
301
|
+
const homeLink = canvas.getByRole("link", { name: /home/i })
|
|
302
|
+
const aboutLink = canvas.getByRole("link", { name: /about/i })
|
|
303
|
+
const ctaButton = canvas.getByRole("link", { name: /get started/i })
|
|
304
|
+
|
|
305
|
+
await expect(homeLink).toBeInTheDocument()
|
|
306
|
+
await expect(aboutLink).toBeInTheDocument()
|
|
307
|
+
await expect(ctaButton).toBeInTheDocument()
|
|
308
|
+
|
|
309
|
+
await expect(homeLink).toHaveAttribute("href", "/")
|
|
310
|
+
await expect(aboutLink).toHaveAttribute("href", "/about")
|
|
311
|
+
},
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Interactive test: Logo presence
|
|
315
|
+
export const LogoTest: Story = {
|
|
316
|
+
args: {
|
|
317
|
+
logo: <Logo />,
|
|
318
|
+
navItems: basicNavItems,
|
|
319
|
+
},
|
|
320
|
+
play: async ({ canvasElement }) => {
|
|
321
|
+
const canvas = within(canvasElement)
|
|
322
|
+
|
|
323
|
+
// Check that the logo/brand text is present
|
|
324
|
+
const logoText = canvas.getByText(/build canada/i)
|
|
325
|
+
await expect(logoText).toBeInTheDocument()
|
|
326
|
+
},
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Interactive test: Announcement banner
|
|
330
|
+
export const AnnouncementTest: Story = {
|
|
331
|
+
args: {
|
|
332
|
+
logo: <Logo />,
|
|
333
|
+
navItems: basicNavItems,
|
|
334
|
+
announcement: {
|
|
335
|
+
text: "Test announcement message",
|
|
336
|
+
href: "/test-link",
|
|
337
|
+
variant: "auburn",
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
play: async ({ canvasElement }) => {
|
|
341
|
+
const canvas = within(canvasElement)
|
|
342
|
+
|
|
343
|
+
const announcement = canvas.getByText(/test announcement message/i)
|
|
344
|
+
await expect(announcement).toBeInTheDocument()
|
|
345
|
+
},
|
|
346
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Header, type HeaderProps, type NavItem } from "./Header"
|
|
2
|
-
export { default } from "./Header"
|
|
1
|
+
export { Header, type HeaderProps, type NavItem } from "./Header.js"
|
|
2
|
+
export { default } from "./Header.js"
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { within, userEvent, expect, fn } from "@storybook/test"
|
|
3
|
+
import { faDownload, faPlus, faCheck, faEnvelope } from "@fortawesome/free-solid-svg-icons"
|
|
4
|
+
|
|
5
|
+
import { Button } from "./Button"
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Button> = {
|
|
8
|
+
title: "Components/Primitives/Button",
|
|
9
|
+
component: Button,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component: `
|
|
14
|
+
A versatile button component that supports multiple variants, sizes, and icon configurations.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
\`\`\`tsx
|
|
19
|
+
import { Button } from "@buildcanada/components"
|
|
20
|
+
|
|
21
|
+
<Button text="Click me" variant="solid-auburn" />
|
|
22
|
+
\`\`\`
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- **6 variants**: solid-auburn, solid-charcoal, solid-linen, outline-auburn, outline-charcoal, outline-white
|
|
27
|
+
- **3 sizes**: sm, md, lg
|
|
28
|
+
- **Icon support**: Left or right positioned icons using FontAwesome
|
|
29
|
+
- **Link mode**: Can render as an anchor tag with \`href\` prop
|
|
30
|
+
- **Full width**: Expand to container width with \`fullWidth\` prop
|
|
31
|
+
`,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
argTypes: {
|
|
36
|
+
variant: {
|
|
37
|
+
control: "select",
|
|
38
|
+
options: [
|
|
39
|
+
"solid-auburn",
|
|
40
|
+
"solid-charcoal",
|
|
41
|
+
"solid-linen",
|
|
42
|
+
"outline-auburn",
|
|
43
|
+
"outline-charcoal",
|
|
44
|
+
"outline-white",
|
|
45
|
+
],
|
|
46
|
+
description: "The visual style variant of the button",
|
|
47
|
+
},
|
|
48
|
+
size: {
|
|
49
|
+
control: "radio",
|
|
50
|
+
options: ["sm", "md", "lg"],
|
|
51
|
+
description: "The size of the button",
|
|
52
|
+
},
|
|
53
|
+
iconPosition: {
|
|
54
|
+
control: "radio",
|
|
55
|
+
options: ["left", "right"],
|
|
56
|
+
description: "Position of the icon relative to the text",
|
|
57
|
+
},
|
|
58
|
+
text: {
|
|
59
|
+
description: "The button label text",
|
|
60
|
+
},
|
|
61
|
+
icon: {
|
|
62
|
+
description: "FontAwesome icon definition. Defaults to arrow-right.",
|
|
63
|
+
},
|
|
64
|
+
disabled: {
|
|
65
|
+
description: "Whether the button is disabled",
|
|
66
|
+
},
|
|
67
|
+
fullWidth: {
|
|
68
|
+
description: "Whether the button should expand to full container width",
|
|
69
|
+
},
|
|
70
|
+
href: {
|
|
71
|
+
description: "If provided, renders as an anchor tag instead of button",
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default meta
|
|
77
|
+
type Story = StoryObj<typeof Button>
|
|
78
|
+
|
|
79
|
+
export const Default: Story = {
|
|
80
|
+
args: {
|
|
81
|
+
text: "Get Started",
|
|
82
|
+
variant: "solid-auburn",
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const SolidAuburn: Story = {
|
|
87
|
+
args: {
|
|
88
|
+
text: "Learn More",
|
|
89
|
+
variant: "solid-auburn",
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const SolidCharcoal: Story = {
|
|
94
|
+
args: {
|
|
95
|
+
text: "View Projects",
|
|
96
|
+
variant: "solid-charcoal",
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const SolidLinen: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
text: "Explore",
|
|
103
|
+
variant: "solid-linen",
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const OutlineAuburn: Story = {
|
|
108
|
+
args: {
|
|
109
|
+
text: "Subscribe",
|
|
110
|
+
variant: "outline-auburn",
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const OutlineCharcoal: Story = {
|
|
115
|
+
args: {
|
|
116
|
+
text: "Read Article",
|
|
117
|
+
variant: "outline-charcoal",
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const OutlineWhite: Story = {
|
|
122
|
+
args: {
|
|
123
|
+
text: "Contact Us",
|
|
124
|
+
variant: "outline-white",
|
|
125
|
+
},
|
|
126
|
+
parameters: {
|
|
127
|
+
backgrounds: { default: "charcoal" },
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const Small: Story = {
|
|
132
|
+
args: {
|
|
133
|
+
text: "Small Button",
|
|
134
|
+
variant: "solid-auburn",
|
|
135
|
+
size: "sm",
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const Medium: Story = {
|
|
140
|
+
args: {
|
|
141
|
+
text: "Medium Button",
|
|
142
|
+
variant: "solid-auburn",
|
|
143
|
+
size: "md",
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export const Large: Story = {
|
|
148
|
+
args: {
|
|
149
|
+
text: "Large Button",
|
|
150
|
+
variant: "solid-auburn",
|
|
151
|
+
size: "lg",
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const WithIconRight: Story = {
|
|
156
|
+
args: {
|
|
157
|
+
text: "Download Report",
|
|
158
|
+
variant: "solid-auburn",
|
|
159
|
+
icon: faDownload,
|
|
160
|
+
iconPosition: "right",
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const WithIconLeft: Story = {
|
|
165
|
+
args: {
|
|
166
|
+
text: "Add Item",
|
|
167
|
+
variant: "solid-charcoal",
|
|
168
|
+
icon: faPlus,
|
|
169
|
+
iconPosition: "left",
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const IconOnly: Story = {
|
|
174
|
+
args: {
|
|
175
|
+
icon: faEnvelope,
|
|
176
|
+
variant: "outline-auburn",
|
|
177
|
+
ariaLabel: "Send email",
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export const NoIcon: Story = {
|
|
182
|
+
args: {
|
|
183
|
+
text: "No Arrow",
|
|
184
|
+
variant: "solid-auburn",
|
|
185
|
+
icon: null,
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const Disabled: Story = {
|
|
190
|
+
args: {
|
|
191
|
+
text: "Disabled",
|
|
192
|
+
variant: "solid-auburn",
|
|
193
|
+
disabled: true,
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export const FullWidth: Story = {
|
|
198
|
+
args: {
|
|
199
|
+
text: "Full Width Button",
|
|
200
|
+
variant: "solid-auburn",
|
|
201
|
+
fullWidth: true,
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export const AsLink: Story = {
|
|
206
|
+
args: {
|
|
207
|
+
text: "Visit Website",
|
|
208
|
+
variant: "solid-auburn",
|
|
209
|
+
href: "https://buildcanada.com",
|
|
210
|
+
},
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const SubmitButton: Story = {
|
|
214
|
+
args: {
|
|
215
|
+
text: "Submit Form",
|
|
216
|
+
variant: "solid-auburn",
|
|
217
|
+
type: "submit",
|
|
218
|
+
icon: faCheck,
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Interactive test: Button click
|
|
223
|
+
export const ClickTest: Story = {
|
|
224
|
+
args: {
|
|
225
|
+
text: "Click Me",
|
|
226
|
+
variant: "solid-auburn",
|
|
227
|
+
onClick: fn(),
|
|
228
|
+
},
|
|
229
|
+
play: async ({ canvasElement, args }) => {
|
|
230
|
+
const canvas = within(canvasElement)
|
|
231
|
+
const button = canvas.getByRole("button", { name: /click me/i })
|
|
232
|
+
|
|
233
|
+
await expect(button).toBeInTheDocument()
|
|
234
|
+
await userEvent.click(button)
|
|
235
|
+
await expect(args.onClick).toHaveBeenCalled()
|
|
236
|
+
},
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Interactive test: Disabled button should not be clickable
|
|
240
|
+
export const DisabledClickTest: Story = {
|
|
241
|
+
args: {
|
|
242
|
+
text: "Disabled Button",
|
|
243
|
+
variant: "solid-auburn",
|
|
244
|
+
disabled: true,
|
|
245
|
+
onClick: fn(),
|
|
246
|
+
},
|
|
247
|
+
play: async ({ canvasElement, args }) => {
|
|
248
|
+
const canvas = within(canvasElement)
|
|
249
|
+
const button = canvas.getByRole("button", { name: /disabled button/i })
|
|
250
|
+
|
|
251
|
+
await expect(button).toBeDisabled()
|
|
252
|
+
await userEvent.click(button)
|
|
253
|
+
await expect(args.onClick).not.toHaveBeenCalled()
|
|
254
|
+
},
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Interactive test: Hover state
|
|
258
|
+
export const HoverTest: Story = {
|
|
259
|
+
args: {
|
|
260
|
+
text: "Hover Me",
|
|
261
|
+
variant: "solid-auburn",
|
|
262
|
+
},
|
|
263
|
+
play: async ({ canvasElement }) => {
|
|
264
|
+
const canvas = within(canvasElement)
|
|
265
|
+
const button = canvas.getByRole("button", { name: /hover me/i })
|
|
266
|
+
|
|
267
|
+
await expect(button).toBeInTheDocument()
|
|
268
|
+
await userEvent.hover(button)
|
|
269
|
+
// Visual check - hover state should be visible
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export const AllVariants: Story = {
|
|
274
|
+
render: () => (
|
|
275
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
|
|
276
|
+
<div style={{ display: "flex", flexWrap: "wrap", gap: "8px", alignItems: "center" }}>
|
|
277
|
+
<Button text="Solid Auburn" variant="solid-auburn" />
|
|
278
|
+
<Button text="Solid Charcoal" variant="solid-charcoal" />
|
|
279
|
+
<Button text="Solid Linen" variant="solid-linen" />
|
|
280
|
+
</div>
|
|
281
|
+
<div style={{ display: "flex", flexWrap: "wrap", gap: "8px", alignItems: "center" }}>
|
|
282
|
+
<Button text="Outline Auburn" variant="outline-auburn" />
|
|
283
|
+
<Button text="Outline Charcoal" variant="outline-charcoal" />
|
|
284
|
+
</div>
|
|
285
|
+
<div style={{ display: "flex", flexWrap: "wrap", gap: "8px", alignItems: "center", backgroundColor: "#272727", padding: "16px" }}>
|
|
286
|
+
<Button text="Outline White" variant="outline-white" />
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
),
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export const AllSizes: Story = {
|
|
293
|
+
render: () => (
|
|
294
|
+
<div style={{ display: "flex", flexWrap: "wrap", gap: "16px", alignItems: "center" }}>
|
|
295
|
+
<Button text="Small" variant="solid-auburn" size="sm" />
|
|
296
|
+
<Button text="Medium" variant="solid-auburn" size="md" />
|
|
297
|
+
<Button text="Large" variant="solid-auburn" size="lg" />
|
|
298
|
+
</div>
|
|
299
|
+
),
|
|
300
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from "./Button"
|
|
2
|
-
export { default } from "./Button"
|
|
1
|
+
export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from "./Button.js"
|
|
2
|
+
export { default } from "./Button.js"
|