@buildcanada/components 0.3.4 → 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 (69) hide show
  1. package/package.json +3 -2
  2. package/src/assets/fonts/financier-text-regular.woff2 +0 -0
  3. package/src/assets/fonts/founders-grotesk-mono-regular.woff2 +0 -0
  4. package/src/assets/fonts/soehne-kraftig.woff2 +0 -0
  5. package/src/content/Card/Card.scss +281 -0
  6. package/src/content/Card/Card.stories.tsx +389 -0
  7. package/src/content/Card/Card.tsx +170 -0
  8. package/src/content/Card/index.ts +22 -0
  9. package/src/content/Hero/Hero.scss +150 -0
  10. package/src/content/Hero/Hero.stories.tsx +299 -0
  11. package/src/content/Hero/Hero.tsx +63 -0
  12. package/src/content/Hero/index.ts +13 -0
  13. package/src/content/StatBlock/StatBlock.scss +83 -0
  14. package/src/content/StatBlock/StatBlock.stories.tsx +331 -0
  15. package/src/content/StatBlock/StatBlock.tsx +52 -0
  16. package/src/content/StatBlock/index.ts +2 -0
  17. package/src/feedback/Dialog/Dialog.scss +158 -0
  18. package/src/feedback/Dialog/Dialog.stories.tsx +286 -0
  19. package/src/feedback/Dialog/Dialog.tsx +120 -0
  20. package/src/feedback/Dialog/index.ts +1 -0
  21. package/src/feedback/PopupForm/PopupForm.scss +34 -0
  22. package/src/feedback/PopupForm/PopupForm.stories.tsx +341 -0
  23. package/src/feedback/PopupForm/PopupForm.tsx +90 -0
  24. package/src/feedback/PopupForm/index.ts +1 -0
  25. package/src/index.ts +61 -0
  26. package/src/layout/Container/Container.scss +40 -0
  27. package/src/layout/Container/Container.stories.tsx +153 -0
  28. package/src/layout/Container/Container.tsx +29 -0
  29. package/src/layout/Container/index.ts +2 -0
  30. package/src/layout/Divider/Divider.scss +117 -0
  31. package/src/layout/Divider/Divider.stories.tsx +204 -0
  32. package/src/layout/Divider/Divider.tsx +32 -0
  33. package/src/layout/Divider/index.ts +2 -0
  34. package/src/layout/Grid/Grid.scss +81 -0
  35. package/src/layout/Grid/Grid.stories.tsx +263 -0
  36. package/src/layout/Grid/Grid.tsx +75 -0
  37. package/src/layout/Grid/index.ts +2 -0
  38. package/src/layout/Section/Section.scss +74 -0
  39. package/src/layout/Section/Section.stories.tsx +173 -0
  40. package/src/layout/Section/Section.tsx +37 -0
  41. package/src/layout/Section/index.ts +2 -0
  42. package/src/layout/Stack/Stack.scss +61 -0
  43. package/src/layout/Stack/Stack.stories.tsx +342 -0
  44. package/src/layout/Stack/Stack.tsx +48 -0
  45. package/src/layout/Stack/index.ts +9 -0
  46. package/src/navigation/Footer/Footer.scss +233 -0
  47. package/src/navigation/Footer/Footer.stories.tsx +351 -0
  48. package/src/navigation/Footer/Footer.tsx +174 -0
  49. package/src/navigation/Footer/index.ts +2 -0
  50. package/src/navigation/Header/Header.scss +325 -0
  51. package/src/navigation/Header/Header.stories.tsx +346 -0
  52. package/src/navigation/Header/Header.tsx +185 -0
  53. package/src/navigation/Header/index.ts +2 -0
  54. package/src/primitives/Button/Button.scss +218 -0
  55. package/src/primitives/Button/Button.stories.tsx +300 -0
  56. package/src/primitives/Button/Button.tsx +120 -0
  57. package/src/primitives/Button/index.ts +2 -0
  58. package/src/primitives/Checkbox/Checkbox.scss +114 -0
  59. package/src/primitives/Checkbox/Checkbox.stories.tsx +204 -0
  60. package/src/primitives/Checkbox/Checkbox.tsx +75 -0
  61. package/src/primitives/Checkbox/index.ts +2 -0
  62. package/src/primitives/TextField/TextField.scss +93 -0
  63. package/src/primitives/TextField/TextField.stories.tsx +265 -0
  64. package/src/primitives/TextField/TextField.tsx +105 -0
  65. package/src/primitives/TextField/index.ts +2 -0
  66. package/src/styles/fonts.scss +27 -0
  67. package/src/styles/main.scss +36 -0
  68. package/src/styles/tokens.scss +301 -0
  69. package/src/styles/typography.scss +232 -0
@@ -0,0 +1,13 @@
1
+ export {
2
+ Hero,
3
+ HeroTitle,
4
+ HeroSubtitle,
5
+ HeroActions,
6
+ type HeroProps,
7
+ type HeroVariant,
8
+ type HeroBackground,
9
+ type HeroTitleProps,
10
+ type HeroSubtitleProps,
11
+ type HeroActionsProps,
12
+ } from "./Hero.js"
13
+ export { default } from "./Hero.js"
@@ -0,0 +1,83 @@
1
+ @use "../../styles/tokens" as *;
2
+ @use "../../styles/typography" as *;
3
+
4
+ /*******************************************************************************
5
+ * StatBlock Component
6
+ *
7
+ * Large formatted number with label, used for data display (canadaspends.com)
8
+ ******************************************************************************/
9
+
10
+ .bc-stat-block {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: calc($space-1 / 2);
14
+
15
+ /***************************************************************************
16
+ * Size Variants
17
+ ***************************************************************************/
18
+
19
+ &--sm {
20
+ .bc-stat-block__value {
21
+ @include h2;
22
+ }
23
+
24
+ .bc-stat-block__label {
25
+ @include label-sm;
26
+ }
27
+ }
28
+
29
+ &--md {
30
+ .bc-stat-block__value {
31
+ @include display-2;
32
+ }
33
+
34
+ .bc-stat-block__label {
35
+ @include label;
36
+ }
37
+ }
38
+
39
+ &--lg {
40
+ .bc-stat-block__value {
41
+ @include display-1;
42
+ }
43
+
44
+ .bc-stat-block__label {
45
+ @include h4;
46
+ }
47
+ }
48
+
49
+ /***************************************************************************
50
+ * Elements
51
+ ***************************************************************************/
52
+
53
+ &__value {
54
+ color: $charcoal;
55
+ font-variant-numeric: tabular-nums;
56
+ }
57
+
58
+ &__label {
59
+ color: $text-secondary;
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.05em;
62
+ }
63
+
64
+ &__description {
65
+ @include body-3;
66
+ color: $text-muted;
67
+ margin-top: calc($space-1 / 2);
68
+ }
69
+
70
+ &__change {
71
+ @include mono-sm;
72
+ color: $text-secondary;
73
+ margin-top: calc($space-1 / 2);
74
+
75
+ &--up {
76
+ color: $emerald-600;
77
+ }
78
+
79
+ &--down {
80
+ color: $auburn;
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,331 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+
3
+ import { StatBlock } from "./StatBlock"
4
+
5
+ const meta: Meta<typeof StatBlock> = {
6
+ title: "Components/Content/StatBlock",
7
+ component: StatBlock,
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ A component for displaying key statistics with optional trend indicators.
13
+
14
+ ## Usage
15
+
16
+ \`\`\`tsx
17
+ import { StatBlock } from "@buildcanada/components"
18
+
19
+ <StatBlock
20
+ value="$456.2B"
21
+ label="Federal Spending"
22
+ change="+8.3%"
23
+ trend="up"
24
+ />
25
+ \`\`\`
26
+
27
+ ## With Description
28
+
29
+ \`\`\`tsx
30
+ <StatBlock
31
+ value="$1.2T"
32
+ label="Total Revenue"
33
+ description="Combined federal and provincial revenues"
34
+ change="+7.8%"
35
+ trend="up"
36
+ size="lg"
37
+ />
38
+ \`\`\`
39
+
40
+ ## Trend Indicators
41
+
42
+ - **up**: Green indicator for positive trends
43
+ - **down**: Red indicator for negative trends
44
+ - **neutral**: Gray indicator for no change
45
+ `,
46
+ },
47
+ },
48
+ },
49
+ argTypes: {
50
+ size: {
51
+ control: "select",
52
+ options: ["sm", "md", "lg"],
53
+ description: "Size of the stat display",
54
+ },
55
+ trend: {
56
+ control: "select",
57
+ options: [undefined, "up", "down", "neutral"],
58
+ description: "Trend direction for the change indicator",
59
+ },
60
+ value: { description: "The main statistic value to display" },
61
+ label: { description: "Label describing the statistic" },
62
+ description: { description: "Additional context or description" },
63
+ change: { description: "Change value (e.g., '+8.3%', '-2.1%')" },
64
+ },
65
+ }
66
+
67
+ export default meta
68
+ type Story = StoryObj<typeof StatBlock>
69
+
70
+ export const Default: Story = {
71
+ args: {
72
+ value: "$456.2B",
73
+ label: "Federal Spending",
74
+ size: "md",
75
+ },
76
+ }
77
+
78
+ export const WithDescription: Story = {
79
+ args: {
80
+ value: "$456.2B",
81
+ label: "Federal Spending",
82
+ description: "Total federal government expenditure for fiscal year 2023-24",
83
+ size: "md",
84
+ },
85
+ }
86
+
87
+ export const TrendUp: Story = {
88
+ args: {
89
+ value: "$89.5B",
90
+ label: "Healthcare Budget",
91
+ change: "+12.3%",
92
+ trend: "up",
93
+ size: "md",
94
+ },
95
+ }
96
+
97
+ export const TrendDown: Story = {
98
+ args: {
99
+ value: "2.1M",
100
+ label: "Employment",
101
+ change: "-3.4%",
102
+ trend: "down",
103
+ size: "md",
104
+ },
105
+ }
106
+
107
+ export const TrendNeutral: Story = {
108
+ args: {
109
+ value: "14",
110
+ label: "Provinces & Territories",
111
+ change: "No change",
112
+ trend: "neutral",
113
+ size: "md",
114
+ },
115
+ }
116
+
117
+ export const Small: Story = {
118
+ args: {
119
+ value: "$12.8B",
120
+ label: "Education",
121
+ change: "+5.2%",
122
+ trend: "up",
123
+ size: "sm",
124
+ },
125
+ }
126
+
127
+ export const Medium: Story = {
128
+ args: {
129
+ value: "$12.8B",
130
+ label: "Education",
131
+ change: "+5.2%",
132
+ trend: "up",
133
+ size: "md",
134
+ },
135
+ }
136
+
137
+ export const Large: Story = {
138
+ args: {
139
+ value: "$12.8B",
140
+ label: "Education",
141
+ change: "+5.2%",
142
+ trend: "up",
143
+ size: "lg",
144
+ },
145
+ }
146
+
147
+ export const PercentageValue: Story = {
148
+ args: {
149
+ value: "42.5%",
150
+ label: "Debt-to-GDP Ratio",
151
+ description: "Compared to 38.2% in the previous year",
152
+ size: "md",
153
+ },
154
+ }
155
+
156
+ export const LargeNumber: Story = {
157
+ args: {
158
+ value: "38,941,457",
159
+ label: "Population of Canada",
160
+ description: "2023 Census estimate",
161
+ size: "lg",
162
+ },
163
+ }
164
+
165
+ export const WithFullContext: Story = {
166
+ args: {
167
+ value: "$1.2T",
168
+ label: "Total Government Revenue",
169
+ description: "Combined federal, provincial, and territorial revenues",
170
+ change: "+7.8% YoY",
171
+ trend: "up",
172
+ size: "lg",
173
+ },
174
+ }
175
+
176
+ export const StatBlocksRow: Story = {
177
+ render: () => (
178
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: "24px" }}>
179
+ <StatBlock
180
+ value="$456.2B"
181
+ label="Federal Spending"
182
+ change="+8.3%"
183
+ trend="up"
184
+ size="md"
185
+ />
186
+ <StatBlock
187
+ value="$89.5B"
188
+ label="Healthcare"
189
+ change="+12.3%"
190
+ trend="up"
191
+ size="md"
192
+ />
193
+ <StatBlock
194
+ value="$45.1B"
195
+ label="Defense"
196
+ change="-2.1%"
197
+ trend="down"
198
+ size="md"
199
+ />
200
+ <StatBlock
201
+ value="$67.3B"
202
+ label="Education"
203
+ change="+5.7%"
204
+ trend="up"
205
+ size="md"
206
+ />
207
+ </div>
208
+ ),
209
+ }
210
+
211
+ export const AllSizes: Story = {
212
+ render: () => (
213
+ <div style={{ display: "flex", flexDirection: "column", gap: "32px" }}>
214
+ <div>
215
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Small</p>
216
+ <StatBlock
217
+ value="$456.2B"
218
+ label="Federal Spending"
219
+ change="+8.3%"
220
+ trend="up"
221
+ size="sm"
222
+ />
223
+ </div>
224
+ <div>
225
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Medium</p>
226
+ <StatBlock
227
+ value="$456.2B"
228
+ label="Federal Spending"
229
+ change="+8.3%"
230
+ trend="up"
231
+ size="md"
232
+ />
233
+ </div>
234
+ <div>
235
+ <p style={{ fontFamily: "sans-serif", marginBottom: "8px" }}>Large</p>
236
+ <StatBlock
237
+ value="$456.2B"
238
+ label="Federal Spending"
239
+ change="+8.3%"
240
+ trend="up"
241
+ size="lg"
242
+ />
243
+ </div>
244
+ </div>
245
+ ),
246
+ }
247
+
248
+ export const AllTrends: Story = {
249
+ render: () => (
250
+ <div style={{ display: "flex", flexWrap: "wrap", gap: "24px" }}>
251
+ <StatBlock
252
+ value="$89.5B"
253
+ label="Healthcare"
254
+ change="+12.3%"
255
+ trend="up"
256
+ size="md"
257
+ />
258
+ <StatBlock
259
+ value="$45.1B"
260
+ label="Defense"
261
+ change="-2.1%"
262
+ trend="down"
263
+ size="md"
264
+ />
265
+ <StatBlock
266
+ value="14"
267
+ label="Provinces"
268
+ change="No change"
269
+ trend="neutral"
270
+ size="md"
271
+ />
272
+ </div>
273
+ ),
274
+ }
275
+
276
+ export const DashboardExample: Story = {
277
+ render: () => (
278
+ <div style={{
279
+ backgroundColor: "#F6ECE3",
280
+ padding: "32px",
281
+ borderRadius: "0"
282
+ }}>
283
+ <h2 style={{
284
+ fontFamily: "sans-serif",
285
+ margin: "0 0 24px",
286
+ fontSize: "24px",
287
+ fontWeight: 500
288
+ }}>
289
+ 2024 Budget Overview
290
+ </h2>
291
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: "16px" }}>
292
+ <div style={{ backgroundColor: "#ffffff", padding: "16px" }}>
293
+ <StatBlock
294
+ value="$496.8B"
295
+ label="Total Revenue"
296
+ change="+6.2%"
297
+ trend="up"
298
+ size="sm"
299
+ />
300
+ </div>
301
+ <div style={{ backgroundColor: "#ffffff", padding: "16px" }}>
302
+ <StatBlock
303
+ value="$537.4B"
304
+ label="Total Expenses"
305
+ change="+4.8%"
306
+ trend="up"
307
+ size="sm"
308
+ />
309
+ </div>
310
+ <div style={{ backgroundColor: "#ffffff", padding: "16px" }}>
311
+ <StatBlock
312
+ value="$40.6B"
313
+ label="Deficit"
314
+ change="-15.3%"
315
+ trend="down"
316
+ size="sm"
317
+ />
318
+ </div>
319
+ <div style={{ backgroundColor: "#ffffff", padding: "16px" }}>
320
+ <StatBlock
321
+ value="1.12T"
322
+ label="Federal Debt"
323
+ change="+3.7%"
324
+ trend="up"
325
+ size="sm"
326
+ />
327
+ </div>
328
+ </div>
329
+ </div>
330
+ ),
331
+ }
@@ -0,0 +1,52 @@
1
+ import cx from "classnames"
2
+
3
+ export type StatBlockSize = "sm" | "md" | "lg"
4
+ export type StatBlockTrend = "up" | "down" | "neutral"
5
+
6
+ export interface StatBlockProps {
7
+ value: string | number
8
+ label: string
9
+ description?: string
10
+ change?: string
11
+ trend?: StatBlockTrend
12
+ size?: StatBlockSize
13
+ className?: string
14
+ style?: React.CSSProperties
15
+ }
16
+
17
+ export function StatBlock({
18
+ value,
19
+ label,
20
+ description,
21
+ change,
22
+ trend,
23
+ size = "md",
24
+ className,
25
+ style,
26
+ }: StatBlockProps) {
27
+ const classes = cx("bc-stat-block", `bc-stat-block--${size}`, className)
28
+
29
+ return (
30
+ <div className={classes} style={style}>
31
+ <span className="bc-stat-block__value">{value}</span>
32
+ <span className="bc-stat-block__label">{label}</span>
33
+ {description && (
34
+ <span className="bc-stat-block__description">{description}</span>
35
+ )}
36
+ {change && (
37
+ <span
38
+ className={cx("bc-stat-block__change", {
39
+ "bc-stat-block__change--up": trend === "up",
40
+ "bc-stat-block__change--down": trend === "down",
41
+ })}
42
+ >
43
+ {trend === "up" && "↑ "}
44
+ {trend === "down" && "↓ "}
45
+ {change}
46
+ </span>
47
+ )}
48
+ </div>
49
+ )
50
+ }
51
+
52
+ export default StatBlock
@@ -0,0 +1,2 @@
1
+ export { StatBlock, type StatBlockProps, type StatBlockSize, type StatBlockTrend } from "./StatBlock.js"
2
+ export { default } from "./StatBlock.js"
@@ -0,0 +1,158 @@
1
+ @use "../../styles/tokens" as *;
2
+
3
+ /*******************************************************************************
4
+ * Dialog Component
5
+ *
6
+ * A non-modal floating panel that doesn't block interaction with the UI.
7
+ * Sizes to its contents and can be positioned in corners.
8
+ ******************************************************************************/
9
+
10
+ .bc-dialog {
11
+ position: fixed;
12
+ z-index: $z-popover;
13
+ background: $white;
14
+ border: 1px solid $border-default;
15
+ box-shadow: $shadow-lg;
16
+ max-width: calc(100vw - var(--bc-dialog-offset, 16px) * 2);
17
+ max-height: calc(100dvh - var(--bc-dialog-offset, 16px) * 2);
18
+
19
+ // Animation
20
+ animation: bc-dialog-enter $transition-base;
21
+ }
22
+
23
+ @keyframes bc-dialog-enter {
24
+ from {
25
+ opacity: 0;
26
+ transform: scale(0.95);
27
+ }
28
+ to {
29
+ opacity: 1;
30
+ transform: scale(1);
31
+ }
32
+ }
33
+
34
+ /*******************************************************************************
35
+ * Dialog Positions
36
+ ******************************************************************************/
37
+
38
+ .bc-dialog--top-left {
39
+ top: var(--bc-dialog-offset, 16px);
40
+ left: var(--bc-dialog-offset, 16px);
41
+ }
42
+
43
+ .bc-dialog--top-right {
44
+ top: var(--bc-dialog-offset, 16px);
45
+ right: var(--bc-dialog-offset, 16px);
46
+ }
47
+
48
+ .bc-dialog--bottom-left {
49
+ bottom: var(--bc-dialog-offset, 16px);
50
+ left: var(--bc-dialog-offset, 16px);
51
+ }
52
+
53
+ .bc-dialog--bottom-right {
54
+ bottom: var(--bc-dialog-offset, 16px);
55
+ right: var(--bc-dialog-offset, 16px);
56
+ }
57
+
58
+ .bc-dialog--center {
59
+ top: 50%;
60
+ left: 50%;
61
+ transform: translate(-50%, -50%);
62
+ animation: bc-dialog-enter-center $transition-base;
63
+ }
64
+
65
+ @keyframes bc-dialog-enter-center {
66
+ from {
67
+ opacity: 0;
68
+ transform: translate(-50%, -50%) scale(0.95);
69
+ }
70
+ to {
71
+ opacity: 1;
72
+ transform: translate(-50%, -50%) scale(1);
73
+ }
74
+ }
75
+
76
+ /*******************************************************************************
77
+ * Dialog Container
78
+ ******************************************************************************/
79
+
80
+ .bc-dialog__container {
81
+ display: flex;
82
+ flex-direction: column;
83
+ overflow: hidden;
84
+ }
85
+
86
+ /*******************************************************************************
87
+ * Dialog Header
88
+ ******************************************************************************/
89
+
90
+ .bc-dialog__header {
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: space-between;
94
+ gap: $space-2;
95
+ padding: $space-2 $space-2 0 $space-3;
96
+ flex-shrink: 0;
97
+ }
98
+
99
+ .bc-dialog__title {
100
+ font-family: "Soehne Kraftig", "Helvetica Neue", Helvetica, Arial, sans-serif;
101
+ font-size: 1.125rem;
102
+ font-weight: 500;
103
+ line-height: 1.4;
104
+ color: $charcoal;
105
+ margin: 0;
106
+ }
107
+
108
+ .bc-dialog__close {
109
+ display: flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ width: 32px;
113
+ height: 32px;
114
+ padding: 0;
115
+ border: none;
116
+ background: transparent;
117
+ color: $gray-600;
118
+ cursor: pointer;
119
+ transition: background-color $transition-fast, color $transition-fast;
120
+ flex-shrink: 0;
121
+
122
+ &:hover {
123
+ background-color: $gray-100;
124
+ color: $charcoal;
125
+ }
126
+
127
+ &:focus-visible {
128
+ outline: 2px solid $auburn;
129
+ outline-offset: 2px;
130
+ }
131
+
132
+ svg {
133
+ width: 16px;
134
+ height: 16px;
135
+ }
136
+ }
137
+
138
+ /*******************************************************************************
139
+ * Dialog Description
140
+ ******************************************************************************/
141
+
142
+ .bc-dialog__description {
143
+ font-family: "Financier Text Regular", Georgia, "Times New Roman", serif;
144
+ font-size: 0.875rem;
145
+ line-height: 1.5;
146
+ color: $gray-600;
147
+ margin: 0;
148
+ padding: $space-1 $space-3 0;
149
+ }
150
+
151
+ /*******************************************************************************
152
+ * Dialog Content
153
+ ******************************************************************************/
154
+
155
+ .bc-dialog__content {
156
+ overflow-y: auto;
157
+ padding: $space-3;
158
+ }