@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.
Files changed (145) hide show
  1. package/dist/content/Card/Card.d.ts +62 -0
  2. package/dist/content/Card/Card.d.ts.map +1 -0
  3. package/dist/content/Card/Card.js +45 -0
  4. package/dist/content/Card/Card.scss +281 -0
  5. package/dist/content/Card/index.d.ts +3 -0
  6. package/dist/content/Card/index.d.ts.map +1 -0
  7. package/dist/content/Card/index.js +2 -0
  8. package/dist/content/Hero/Hero.d.ts +28 -0
  9. package/dist/content/Hero/Hero.d.ts.map +1 -0
  10. package/dist/content/Hero/Hero.js +16 -0
  11. package/dist/content/Hero/Hero.scss +150 -0
  12. package/dist/content/Hero/index.d.ts +3 -0
  13. package/dist/content/Hero/index.d.ts.map +1 -0
  14. package/dist/content/Hero/index.js +2 -0
  15. package/dist/content/StatBlock/StatBlock.d.ts +15 -0
  16. package/dist/content/StatBlock/StatBlock.d.ts.map +1 -0
  17. package/dist/content/StatBlock/StatBlock.js +10 -0
  18. package/dist/content/StatBlock/StatBlock.scss +83 -0
  19. package/dist/content/StatBlock/index.d.ts +3 -0
  20. package/dist/content/StatBlock/index.d.ts.map +1 -0
  21. package/dist/content/StatBlock/index.js +2 -0
  22. package/dist/feedback/Dialog/Dialog.d.ts +18 -0
  23. package/dist/feedback/Dialog/Dialog.d.ts.map +1 -0
  24. package/dist/feedback/Dialog/Dialog.js +33 -0
  25. package/dist/feedback/Dialog/Dialog.scss +158 -0
  26. package/dist/feedback/Dialog/index.d.ts +2 -0
  27. package/dist/feedback/Dialog/index.d.ts.map +1 -0
  28. package/dist/feedback/Dialog/index.js +1 -0
  29. package/dist/feedback/PopupForm/PopupForm.d.ts +24 -0
  30. package/dist/feedback/PopupForm/PopupForm.d.ts.map +1 -0
  31. package/dist/feedback/PopupForm/PopupForm.js +13 -0
  32. package/dist/feedback/PopupForm/PopupForm.scss +34 -0
  33. package/dist/feedback/PopupForm/index.d.ts +2 -0
  34. package/dist/feedback/PopupForm/index.d.ts.map +1 -0
  35. package/dist/feedback/PopupForm/index.js +1 -0
  36. package/dist/index.d.ts +21 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +25 -0
  39. package/dist/layout/Container/Container.d.ts +11 -0
  40. package/dist/layout/Container/Container.d.ts.map +1 -0
  41. package/dist/layout/Container/Container.js +7 -0
  42. package/dist/layout/Container/Container.scss +40 -0
  43. package/dist/layout/Container/index.d.ts +3 -0
  44. package/dist/layout/Container/index.d.ts.map +1 -0
  45. package/dist/layout/Container/index.js +2 -0
  46. package/dist/layout/Divider/Divider.d.ts +12 -0
  47. package/dist/layout/Divider/Divider.d.ts.map +1 -0
  48. package/dist/layout/Divider/Divider.js +7 -0
  49. package/dist/layout/Divider/Divider.scss +117 -0
  50. package/dist/layout/Divider/index.d.ts +3 -0
  51. package/dist/layout/Divider/index.d.ts.map +1 -0
  52. package/dist/layout/Divider/index.js +2 -0
  53. package/dist/layout/Grid/Grid.d.ts +24 -0
  54. package/dist/layout/Grid/Grid.d.ts.map +1 -0
  55. package/dist/layout/Grid/Grid.js +11 -0
  56. package/dist/layout/Grid/Grid.scss +81 -0
  57. package/dist/layout/Grid/index.d.ts +3 -0
  58. package/dist/layout/Grid/index.d.ts.map +1 -0
  59. package/dist/layout/Grid/index.js +2 -0
  60. package/dist/layout/Section/Section.d.ts +13 -0
  61. package/dist/layout/Section/Section.d.ts.map +1 -0
  62. package/dist/layout/Section/Section.js +7 -0
  63. package/dist/layout/Section/Section.scss +74 -0
  64. package/dist/layout/Section/index.d.ts +3 -0
  65. package/dist/layout/Section/index.d.ts.map +1 -0
  66. package/dist/layout/Section/index.js +2 -0
  67. package/dist/layout/Stack/Stack.d.ts +18 -0
  68. package/dist/layout/Stack/Stack.d.ts.map +1 -0
  69. package/dist/layout/Stack/Stack.js +7 -0
  70. package/dist/layout/Stack/Stack.scss +61 -0
  71. package/dist/layout/Stack/index.d.ts +3 -0
  72. package/dist/layout/Stack/index.d.ts.map +1 -0
  73. package/dist/layout/Stack/index.js +2 -0
  74. package/dist/navigation/Footer/Footer.d.ts +31 -0
  75. package/dist/navigation/Footer/Footer.d.ts.map +1 -0
  76. package/dist/navigation/Footer/Footer.js +21 -0
  77. package/dist/navigation/Footer/Footer.scss +233 -0
  78. package/dist/navigation/Footer/index.d.ts +3 -0
  79. package/dist/navigation/Footer/index.d.ts.map +1 -0
  80. package/dist/navigation/Footer/index.js +2 -0
  81. package/dist/navigation/Header/Header.d.ts +23 -0
  82. package/dist/navigation/Header/Header.d.ts.map +1 -0
  83. package/dist/navigation/Header/Header.js +16 -0
  84. package/dist/navigation/Header/Header.scss +325 -0
  85. package/dist/navigation/Header/index.d.ts +3 -0
  86. package/dist/navigation/Header/index.d.ts.map +1 -0
  87. package/dist/navigation/Header/index.js +2 -0
  88. package/dist/primitives/Button/Button.d.ts +31 -0
  89. package/dist/primitives/Button/Button.d.ts.map +1 -0
  90. package/dist/primitives/Button/Button.js +36 -0
  91. package/dist/primitives/Button/Button.scss +218 -0
  92. package/dist/primitives/Button/index.d.ts +3 -0
  93. package/dist/primitives/Button/index.d.ts.map +1 -0
  94. package/dist/primitives/Button/index.js +2 -0
  95. package/dist/primitives/Checkbox/Checkbox.d.ts +13 -0
  96. package/dist/primitives/Checkbox/Checkbox.d.ts.map +1 -0
  97. package/dist/primitives/Checkbox/Checkbox.js +10 -0
  98. package/dist/primitives/Checkbox/Checkbox.scss +114 -0
  99. package/dist/primitives/Checkbox/index.d.ts +3 -0
  100. package/dist/primitives/Checkbox/index.d.ts.map +1 -0
  101. package/dist/primitives/Checkbox/index.js +2 -0
  102. package/dist/primitives/TextField/TextField.d.ts +22 -0
  103. package/dist/primitives/TextField/TextField.d.ts.map +1 -0
  104. package/dist/primitives/TextField/TextField.js +14 -0
  105. package/dist/primitives/TextField/TextField.scss +93 -0
  106. package/dist/primitives/TextField/index.d.ts +3 -0
  107. package/dist/primitives/TextField/index.d.ts.map +1 -0
  108. package/dist/primitives/TextField/index.js +2 -0
  109. package/dist/styles/fonts.scss +27 -0
  110. package/dist/styles/main.scss +36 -0
  111. package/dist/styles/tokens.scss +301 -0
  112. package/dist/styles/typography.scss +232 -0
  113. package/package.json +12 -11
  114. package/src/content/Card/Card.stories.tsx +389 -0
  115. package/src/content/Card/index.ts +2 -2
  116. package/src/content/Hero/Hero.stories.tsx +299 -0
  117. package/src/content/Hero/index.ts +2 -2
  118. package/src/content/StatBlock/StatBlock.stories.tsx +331 -0
  119. package/src/content/StatBlock/index.ts +2 -2
  120. package/src/feedback/Dialog/Dialog.stories.tsx +286 -0
  121. package/src/feedback/Dialog/index.ts +1 -1
  122. package/src/feedback/PopupForm/PopupForm.stories.tsx +341 -0
  123. package/src/feedback/PopupForm/PopupForm.tsx +2 -2
  124. package/src/feedback/PopupForm/index.ts +1 -1
  125. package/src/index.ts +15 -15
  126. package/src/layout/Container/Container.stories.tsx +153 -0
  127. package/src/layout/Container/index.ts +2 -2
  128. package/src/layout/Divider/Divider.stories.tsx +204 -0
  129. package/src/layout/Divider/index.ts +2 -2
  130. package/src/layout/Grid/Grid.stories.tsx +263 -0
  131. package/src/layout/Grid/index.ts +2 -2
  132. package/src/layout/Section/Section.stories.tsx +173 -0
  133. package/src/layout/Section/index.ts +2 -2
  134. package/src/layout/Stack/Stack.stories.tsx +342 -0
  135. package/src/layout/Stack/index.ts +2 -2
  136. package/src/navigation/Footer/Footer.stories.tsx +351 -0
  137. package/src/navigation/Footer/index.ts +2 -2
  138. package/src/navigation/Header/Header.stories.tsx +346 -0
  139. package/src/navigation/Header/index.ts +2 -2
  140. package/src/primitives/Button/Button.stories.tsx +300 -0
  141. package/src/primitives/Button/index.ts +2 -2
  142. package/src/primitives/Checkbox/Checkbox.stories.tsx +204 -0
  143. package/src/primitives/Checkbox/index.ts +2 -2
  144. package/src/primitives/TextField/TextField.stories.tsx +265 -0
  145. package/src/primitives/TextField/index.ts +2 -2
@@ -0,0 +1,342 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+
3
+ import { Stack } from "./Stack"
4
+
5
+ const meta: Meta<typeof Stack> = {
6
+ title: "Components/Layout/Stack",
7
+ component: Stack,
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ A flexbox layout component for arranging items in a row or column with consistent spacing.
13
+
14
+ ## Usage
15
+
16
+ \`\`\`tsx
17
+ import { Stack } from "@buildcanada/components"
18
+
19
+ <Stack direction="vertical" spacing="md">
20
+ <div>Item 1</div>
21
+ <div>Item 2</div>
22
+ <div>Item 3</div>
23
+ </Stack>
24
+ \`\`\`
25
+
26
+ ## Horizontal Layout
27
+
28
+ \`\`\`tsx
29
+ <Stack direction="horizontal" spacing="lg" align="center">
30
+ <Button>Action 1</Button>
31
+ <Button>Action 2</Button>
32
+ </Stack>
33
+ \`\`\`
34
+
35
+ ## Spacing Options
36
+
37
+ - **none**: 0px
38
+ - **xs**: 4px
39
+ - **sm**: 8px
40
+ - **md**: 16px
41
+ - **lg**: 24px
42
+ - **xl**: 32px
43
+ `,
44
+ },
45
+ },
46
+ },
47
+ argTypes: {
48
+ direction: {
49
+ control: "radio",
50
+ options: ["vertical", "horizontal"],
51
+ description: "Stack direction (column or row)",
52
+ },
53
+ spacing: {
54
+ control: "select",
55
+ options: ["none", "xs", "sm", "md", "lg", "xl"],
56
+ description: "Gap between items",
57
+ },
58
+ align: {
59
+ control: "select",
60
+ options: ["start", "center", "end", "stretch"],
61
+ description: "Cross-axis alignment (align-items)",
62
+ },
63
+ justify: {
64
+ control: "select",
65
+ options: ["start", "center", "end", "between", "around"],
66
+ description: "Main-axis alignment (justify-content)",
67
+ },
68
+ wrap: {
69
+ description: "Whether items should wrap to next line",
70
+ },
71
+ },
72
+ }
73
+
74
+ export default meta
75
+ type Story = StoryObj<typeof Stack>
76
+
77
+ const StackItem = ({ children, height }: { children: React.ReactNode; height?: string }) => (
78
+ <div style={{
79
+ padding: "16px 24px",
80
+ backgroundColor: "#F6ECE3",
81
+ border: "1px solid #272727",
82
+ fontFamily: "sans-serif",
83
+ height: height || "auto",
84
+ }}>
85
+ {children}
86
+ </div>
87
+ )
88
+
89
+ export const Default: Story = {
90
+ args: {
91
+ direction: "vertical",
92
+ spacing: "md",
93
+ children: (
94
+ <>
95
+ <StackItem>Item 1</StackItem>
96
+ <StackItem>Item 2</StackItem>
97
+ <StackItem>Item 3</StackItem>
98
+ </>
99
+ ),
100
+ },
101
+ }
102
+
103
+ export const Vertical: Story = {
104
+ args: {
105
+ direction: "vertical",
106
+ spacing: "md",
107
+ children: (
108
+ <>
109
+ <StackItem>Item 1</StackItem>
110
+ <StackItem>Item 2</StackItem>
111
+ <StackItem>Item 3</StackItem>
112
+ </>
113
+ ),
114
+ },
115
+ }
116
+
117
+ export const Horizontal: Story = {
118
+ args: {
119
+ direction: "horizontal",
120
+ spacing: "md",
121
+ children: (
122
+ <>
123
+ <StackItem>Item 1</StackItem>
124
+ <StackItem>Item 2</StackItem>
125
+ <StackItem>Item 3</StackItem>
126
+ </>
127
+ ),
128
+ },
129
+ }
130
+
131
+ export const NoSpacing: Story = {
132
+ args: {
133
+ direction: "vertical",
134
+ spacing: "none",
135
+ children: (
136
+ <>
137
+ <StackItem>Item 1</StackItem>
138
+ <StackItem>Item 2</StackItem>
139
+ <StackItem>Item 3</StackItem>
140
+ </>
141
+ ),
142
+ },
143
+ }
144
+
145
+ export const ExtraSmallSpacing: Story = {
146
+ args: {
147
+ direction: "vertical",
148
+ spacing: "xs",
149
+ children: (
150
+ <>
151
+ <StackItem>Item 1</StackItem>
152
+ <StackItem>Item 2</StackItem>
153
+ <StackItem>Item 3</StackItem>
154
+ </>
155
+ ),
156
+ },
157
+ }
158
+
159
+ export const LargeSpacing: Story = {
160
+ args: {
161
+ direction: "vertical",
162
+ spacing: "lg",
163
+ children: (
164
+ <>
165
+ <StackItem>Item 1</StackItem>
166
+ <StackItem>Item 2</StackItem>
167
+ <StackItem>Item 3</StackItem>
168
+ </>
169
+ ),
170
+ },
171
+ }
172
+
173
+ export const AlignCenter: Story = {
174
+ args: {
175
+ direction: "horizontal",
176
+ spacing: "md",
177
+ align: "center",
178
+ children: (
179
+ <>
180
+ <StackItem height="60px">Tall</StackItem>
181
+ <StackItem height="40px">Medium</StackItem>
182
+ <StackItem height="80px">Taller</StackItem>
183
+ </>
184
+ ),
185
+ },
186
+ }
187
+
188
+ export const AlignStart: Story = {
189
+ args: {
190
+ direction: "horizontal",
191
+ spacing: "md",
192
+ align: "start",
193
+ children: (
194
+ <>
195
+ <StackItem height="60px">Tall</StackItem>
196
+ <StackItem height="40px">Medium</StackItem>
197
+ <StackItem height="80px">Taller</StackItem>
198
+ </>
199
+ ),
200
+ },
201
+ }
202
+
203
+ export const AlignEnd: Story = {
204
+ args: {
205
+ direction: "horizontal",
206
+ spacing: "md",
207
+ align: "end",
208
+ children: (
209
+ <>
210
+ <StackItem height="60px">Tall</StackItem>
211
+ <StackItem height="40px">Medium</StackItem>
212
+ <StackItem height="80px">Taller</StackItem>
213
+ </>
214
+ ),
215
+ },
216
+ }
217
+
218
+ export const JustifyBetween: Story = {
219
+ args: {
220
+ direction: "horizontal",
221
+ spacing: "md",
222
+ justify: "between",
223
+ children: (
224
+ <>
225
+ <StackItem>Left</StackItem>
226
+ <StackItem>Center</StackItem>
227
+ <StackItem>Right</StackItem>
228
+ </>
229
+ ),
230
+ },
231
+ decorators: [
232
+ (Story) => (
233
+ <div style={{ width: "100%" }}>
234
+ <Story />
235
+ </div>
236
+ ),
237
+ ],
238
+ }
239
+
240
+ export const JustifyCenter: Story = {
241
+ args: {
242
+ direction: "horizontal",
243
+ spacing: "md",
244
+ justify: "center",
245
+ children: (
246
+ <>
247
+ <StackItem>Item 1</StackItem>
248
+ <StackItem>Item 2</StackItem>
249
+ <StackItem>Item 3</StackItem>
250
+ </>
251
+ ),
252
+ },
253
+ decorators: [
254
+ (Story) => (
255
+ <div style={{ width: "100%" }}>
256
+ <Story />
257
+ </div>
258
+ ),
259
+ ],
260
+ }
261
+
262
+ export const WithWrap: Story = {
263
+ args: {
264
+ direction: "horizontal",
265
+ spacing: "md",
266
+ wrap: true,
267
+ children: (
268
+ <>
269
+ <StackItem>Item 1</StackItem>
270
+ <StackItem>Item 2</StackItem>
271
+ <StackItem>Item 3</StackItem>
272
+ <StackItem>Item 4</StackItem>
273
+ <StackItem>Item 5</StackItem>
274
+ <StackItem>Item 6</StackItem>
275
+ <StackItem>Item 7</StackItem>
276
+ <StackItem>Item 8</StackItem>
277
+ </>
278
+ ),
279
+ },
280
+ decorators: [
281
+ (Story) => (
282
+ <div style={{ maxWidth: "400px" }}>
283
+ <Story />
284
+ </div>
285
+ ),
286
+ ],
287
+ }
288
+
289
+ export const AllSpacings: Story = {
290
+ render: () => (
291
+ <Stack direction="vertical" spacing="lg">
292
+ <div>
293
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>None</p>
294
+ <Stack direction="horizontal" spacing="none">
295
+ <StackItem>1</StackItem>
296
+ <StackItem>2</StackItem>
297
+ <StackItem>3</StackItem>
298
+ </Stack>
299
+ </div>
300
+ <div>
301
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Extra Small</p>
302
+ <Stack direction="horizontal" spacing="xs">
303
+ <StackItem>1</StackItem>
304
+ <StackItem>2</StackItem>
305
+ <StackItem>3</StackItem>
306
+ </Stack>
307
+ </div>
308
+ <div>
309
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Small</p>
310
+ <Stack direction="horizontal" spacing="sm">
311
+ <StackItem>1</StackItem>
312
+ <StackItem>2</StackItem>
313
+ <StackItem>3</StackItem>
314
+ </Stack>
315
+ </div>
316
+ <div>
317
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Medium</p>
318
+ <Stack direction="horizontal" spacing="md">
319
+ <StackItem>1</StackItem>
320
+ <StackItem>2</StackItem>
321
+ <StackItem>3</StackItem>
322
+ </Stack>
323
+ </div>
324
+ <div>
325
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Large</p>
326
+ <Stack direction="horizontal" spacing="lg">
327
+ <StackItem>1</StackItem>
328
+ <StackItem>2</StackItem>
329
+ <StackItem>3</StackItem>
330
+ </Stack>
331
+ </div>
332
+ <div>
333
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Extra Large</p>
334
+ <Stack direction="horizontal" spacing="xl">
335
+ <StackItem>1</StackItem>
336
+ <StackItem>2</StackItem>
337
+ <StackItem>3</StackItem>
338
+ </Stack>
339
+ </div>
340
+ </Stack>
341
+ ),
342
+ }
@@ -5,5 +5,5 @@ export {
5
5
  type StackSpacing,
6
6
  type StackAlign,
7
7
  type StackJustify,
8
- } from "./Stack"
9
- export { default } from "./Stack"
8
+ } from "./Stack.js"
9
+ export { default } from "./Stack.js"
@@ -0,0 +1,351 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { within, userEvent, expect, fn } from "@storybook/test"
3
+
4
+ import { Footer } from "./Footer"
5
+
6
+ const meta: Meta<typeof Footer> = {
7
+ title: "Components/Navigation/Footer",
8
+ component: Footer,
9
+ parameters: {
10
+ layout: "fullscreen",
11
+ docs: {
12
+ description: {
13
+ component: `
14
+ A site footer component with logo, navigation links, social links, newsletter signup, and optional quote.
15
+
16
+ ## Usage
17
+
18
+ \`\`\`tsx
19
+ import { Footer } from "@buildcanada/components"
20
+
21
+ <Footer
22
+ logo={<Logo />}
23
+ links={[
24
+ { label: "Home", href: "/" },
25
+ { label: "About", href: "/about" },
26
+ { label: "Privacy", href: "/privacy" },
27
+ ]}
28
+ socialLinks={[
29
+ { platform: "twitter", href: "https://twitter.com/..." },
30
+ { platform: "github", href: "https://github.com/..." },
31
+ ]}
32
+ copyright="© 2024 Company Name"
33
+ />
34
+ \`\`\`
35
+
36
+ ## With Newsletter
37
+
38
+ \`\`\`tsx
39
+ <Footer
40
+ logo={<Logo />}
41
+ links={links}
42
+ newsletter={{
43
+ heading: "Stay Updated",
44
+ description: "Get the latest news delivered to your inbox.",
45
+ placeholder: "Enter your email",
46
+ buttonText: "Subscribe",
47
+ onSubmit: (email) => console.log(email),
48
+ }}
49
+ copyright="© 2024 Company Name"
50
+ />
51
+ \`\`\`
52
+
53
+ ## Social Platforms
54
+
55
+ Supported platforms: twitter, linkedin, github, email, bluesky
56
+ `,
57
+ },
58
+ },
59
+ },
60
+ }
61
+
62
+ export default meta
63
+ type Story = StoryObj<typeof Footer>
64
+
65
+ const Logo = () => (
66
+ <span style={{
67
+ fontFamily: "'Soehne Kraftig', 'Helvetica Neue', Helvetica, Arial, sans-serif",
68
+ fontSize: "18px",
69
+ fontWeight: 500,
70
+ color: "#ffffff",
71
+ letterSpacing: "-0.01em",
72
+ }}>
73
+ Build Canada
74
+ </span>
75
+ )
76
+
77
+ const basicLinks = [
78
+ { label: "Home", href: "/" },
79
+ { label: "About", href: "/about" },
80
+ { label: "Projects", href: "/projects" },
81
+ { label: "Contact", href: "/contact" },
82
+ ]
83
+
84
+ const extendedLinks = [
85
+ { label: "Home", href: "/" },
86
+ { label: "About", href: "/about" },
87
+ { label: "Projects", href: "/projects" },
88
+ { label: "Research", href: "/research" },
89
+ { label: "Data", href: "/data" },
90
+ { label: "Blog", href: "/blog" },
91
+ { label: "Privacy", href: "/privacy" },
92
+ { label: "Terms", href: "/terms" },
93
+ ]
94
+
95
+ const socialLinks = [
96
+ { platform: "twitter" as const, href: "https://twitter.com/buildcanada" },
97
+ { platform: "linkedin" as const, href: "https://linkedin.com/company/buildcanada" },
98
+ { platform: "github" as const, href: "https://github.com/buildcanada" },
99
+ { platform: "email" as const, href: "mailto:hello@buildcanada.com", label: "Email us" },
100
+ ]
101
+
102
+ const socialLinksWithBluesky = [
103
+ { platform: "twitter" as const, href: "https://twitter.com/buildcanada" },
104
+ { platform: "bluesky" as const, href: "https://bsky.app/profile/buildcanada" },
105
+ { platform: "linkedin" as const, href: "https://linkedin.com/company/buildcanada" },
106
+ { platform: "github" as const, href: "https://github.com/buildcanada" },
107
+ ]
108
+
109
+ export const Default: Story = {
110
+ args: {
111
+ logo: <Logo />,
112
+ links: basicLinks,
113
+ socialLinks: socialLinks,
114
+ copyright: "© 2024 Build Canada. All rights reserved.",
115
+ },
116
+ }
117
+
118
+ export const WithNewsletter: Story = {
119
+ args: {
120
+ logo: <Logo />,
121
+ links: basicLinks,
122
+ socialLinks: socialLinks,
123
+ newsletter: {
124
+ heading: "Stay Updated",
125
+ description: "Get the latest insights delivered to your inbox.",
126
+ placeholder: "Enter your email",
127
+ buttonText: "Subscribe",
128
+ onSubmit: (email) => console.log("Newsletter signup:", email),
129
+ },
130
+ copyright: "© 2024 Build Canada. All rights reserved.",
131
+ },
132
+ }
133
+
134
+ export const WithQuote: Story = {
135
+ args: {
136
+ logo: <Logo />,
137
+ links: basicLinks,
138
+ socialLinks: socialLinks,
139
+ quote: {
140
+ text: "The measure of a great democracy is how well it serves its citizens through transparent and accountable governance.",
141
+ attribution: "Build Canada Mission Statement",
142
+ },
143
+ copyright: "© 2024 Build Canada. All rights reserved.",
144
+ },
145
+ }
146
+
147
+ export const FullFeatured: Story = {
148
+ args: {
149
+ logo: <Logo />,
150
+ links: extendedLinks,
151
+ socialLinks: socialLinks,
152
+ newsletter: {
153
+ heading: "Join Our Newsletter",
154
+ description: "Weekly insights on Canadian government spending and policy.",
155
+ placeholder: "you@example.com",
156
+ buttonText: "Subscribe",
157
+ },
158
+ quote: {
159
+ text: "Democracy requires an informed citizenry. We make government data accessible to all.",
160
+ attribution: "Build Canada",
161
+ },
162
+ copyright: "© 2024 Build Canada. All rights reserved.",
163
+ },
164
+ }
165
+
166
+ export const MinimalFooter: Story = {
167
+ args: {
168
+ copyright: "© 2024 Build Canada",
169
+ },
170
+ }
171
+
172
+ export const WithLogoOnly: Story = {
173
+ args: {
174
+ logo: <Logo />,
175
+ copyright: "© 2024 Build Canada. All rights reserved.",
176
+ },
177
+ }
178
+
179
+ export const WithSocialOnly: Story = {
180
+ args: {
181
+ socialLinks: socialLinks,
182
+ copyright: "© 2024 Build Canada",
183
+ },
184
+ }
185
+
186
+ export const WithBluesky: Story = {
187
+ args: {
188
+ logo: <Logo />,
189
+ links: basicLinks,
190
+ socialLinks: socialLinksWithBluesky,
191
+ copyright: "© 2024 Build Canada. All rights reserved.",
192
+ },
193
+ }
194
+
195
+ export const CanadaSpendsFooter: Story = {
196
+ args: {
197
+ logo: (
198
+ <span style={{ color: "#fff", fontWeight: 600, fontSize: "18px", fontFamily: "sans-serif" }}>
199
+ Canada Spends
200
+ </span>
201
+ ),
202
+ links: [
203
+ { label: "Charts", href: "/charts" },
204
+ { label: "Data", href: "/data" },
205
+ { label: "Topics", href: "/topics" },
206
+ { label: "About", href: "/about" },
207
+ { label: "Methodology", href: "/methodology" },
208
+ { label: "API", href: "/api" },
209
+ ],
210
+ socialLinks: [
211
+ { platform: "twitter" as const, href: "https://twitter.com/canadaspends" },
212
+ { platform: "github" as const, href: "https://github.com/buildcanada/canada-spends" },
213
+ ],
214
+ newsletter: {
215
+ heading: "Data Updates",
216
+ description: "Get notified when new datasets are published.",
217
+ placeholder: "your@email.com",
218
+ buttonText: "Notify Me",
219
+ },
220
+ copyright: "© 2024 Canada Spends. A Build Canada Project.",
221
+ },
222
+ }
223
+
224
+ export const BuildCanadaFooter: Story = {
225
+ args: {
226
+ logo: (
227
+ <span style={{ color: "#fff", fontWeight: 600, fontSize: "18px", fontFamily: "sans-serif" }}>
228
+ Build Canada
229
+ </span>
230
+ ),
231
+ links: [
232
+ { label: "Home", href: "/" },
233
+ { label: "About", href: "/about" },
234
+ { label: "Projects", href: "/projects" },
235
+ { label: "Memos", href: "/memos" },
236
+ { label: "Team", href: "/team" },
237
+ { label: "Contact", href: "/contact" },
238
+ ],
239
+ socialLinks: socialLinks,
240
+ newsletter: {
241
+ heading: "Stay Informed",
242
+ description: "Join our mailing list for weekly updates on Canadian policy and data.",
243
+ placeholder: "Enter your email",
244
+ buttonText: "Subscribe",
245
+ },
246
+ quote: {
247
+ text: "We believe an informed citizenry is essential to a functioning democracy.",
248
+ attribution: "Build Canada",
249
+ },
250
+ copyright: "© 2024 Build Canada. All rights reserved.",
251
+ },
252
+ }
253
+
254
+ export const LongLinkList: Story = {
255
+ args: {
256
+ logo: <Logo />,
257
+ links: [
258
+ { label: "Home", href: "/" },
259
+ { label: "About Us", href: "/about" },
260
+ { label: "Our Mission", href: "/mission" },
261
+ { label: "Projects", href: "/projects" },
262
+ { label: "Canada Spends", href: "/canada-spends" },
263
+ { label: "Research", href: "/research" },
264
+ { label: "Reports", href: "/reports" },
265
+ { label: "Data", href: "/data" },
266
+ { label: "Blog", href: "/blog" },
267
+ { label: "Careers", href: "/careers" },
268
+ { label: "Press", href: "/press" },
269
+ { label: "Contact", href: "/contact" },
270
+ { label: "Privacy Policy", href: "/privacy" },
271
+ { label: "Terms of Use", href: "/terms" },
272
+ ],
273
+ socialLinks: socialLinks,
274
+ copyright: "© 2024 Build Canada. All rights reserved.",
275
+ },
276
+ }
277
+
278
+ // Interactive test: Footer links
279
+ export const LinksTest: Story = {
280
+ args: {
281
+ links: basicLinks,
282
+ copyright: "© 2024 Build Canada",
283
+ },
284
+ play: async ({ canvasElement }) => {
285
+ const canvas = within(canvasElement)
286
+
287
+ const homeLink = canvas.getByRole("link", { name: /home/i })
288
+ const aboutLink = canvas.getByRole("link", { name: /about/i })
289
+
290
+ await expect(homeLink).toBeInTheDocument()
291
+ await expect(aboutLink).toBeInTheDocument()
292
+ await expect(homeLink).toHaveAttribute("href", "/")
293
+ },
294
+ }
295
+
296
+ // Interactive test: Social links
297
+ export const SocialLinksTest: Story = {
298
+ args: {
299
+ socialLinks: socialLinks,
300
+ copyright: "© 2024 Build Canada",
301
+ },
302
+ play: async ({ canvasElement }) => {
303
+ const canvas = within(canvasElement)
304
+
305
+ // Check that social links are present (they should be links with icons)
306
+ const twitterLink = canvas.getByRole("link", { name: /twitter/i })
307
+ const githubLink = canvas.getByRole("link", { name: /github/i })
308
+
309
+ await expect(twitterLink).toBeInTheDocument()
310
+ await expect(githubLink).toBeInTheDocument()
311
+ },
312
+ }
313
+
314
+ // Interactive test: Newsletter form
315
+ export const NewsletterTest: Story = {
316
+ args: {
317
+ newsletter: {
318
+ heading: "Subscribe",
319
+ description: "Get updates",
320
+ placeholder: "your@email.com",
321
+ buttonText: "Subscribe",
322
+ onSubmit: fn(),
323
+ },
324
+ copyright: "© 2024 Build Canada",
325
+ },
326
+ play: async ({ canvasElement, args }) => {
327
+ const canvas = within(canvasElement)
328
+
329
+ const emailInput = canvas.getByPlaceholderText("your@email.com")
330
+ const submitButton = canvas.getByRole("button", { name: /subscribe/i })
331
+
332
+ await expect(emailInput).toBeInTheDocument()
333
+ await expect(submitButton).toBeInTheDocument()
334
+
335
+ await userEvent.type(emailInput, "test@example.com")
336
+ await expect(emailInput).toHaveValue("test@example.com")
337
+ },
338
+ }
339
+
340
+ // Interactive test: Copyright text
341
+ export const CopyrightTest: Story = {
342
+ args: {
343
+ copyright: "© 2024 Test Company. All rights reserved.",
344
+ },
345
+ play: async ({ canvasElement }) => {
346
+ const canvas = within(canvasElement)
347
+
348
+ const copyright = canvas.getByText(/2024 Test Company/i)
349
+ await expect(copyright).toBeInTheDocument()
350
+ },
351
+ }
@@ -1,2 +1,2 @@
1
- export { Footer, type FooterProps, type FooterLink, type SocialLink } from "./Footer"
2
- export { default } from "./Footer"
1
+ export { Footer, type FooterProps, type FooterLink, type SocialLink } from "./Footer.js"
2
+ export { default } from "./Footer.js"