@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,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
|
+
}
|
|
@@ -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"
|