@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,170 @@
1
+ import cx from "classnames"
2
+
3
+ export type CardVariant = "default" | "project" | "memo" | "feature" | "stat" | "profile"
4
+
5
+ export interface CardProps {
6
+ children: React.ReactNode
7
+ className?: string
8
+ style?: React.CSSProperties
9
+ variant?: CardVariant
10
+ href?: string
11
+ onClick?: () => void
12
+ }
13
+
14
+ export function Card({
15
+ children,
16
+ className,
17
+ style,
18
+ variant = "default",
19
+ href,
20
+ onClick,
21
+ }: CardProps) {
22
+ const isInteractive = Boolean(href || onClick)
23
+ const isButton = Boolean(onClick)
24
+
25
+ const classes = cx(
26
+ "bc-card",
27
+ `bc-card--${variant}`,
28
+ {
29
+ "bc-card--interactive": isInteractive,
30
+ "bc-card--button": isButton,
31
+ },
32
+ className
33
+ )
34
+
35
+ if (href) {
36
+ return (
37
+ <a href={href} className={classes} style={style}>
38
+ {children}
39
+ </a>
40
+ )
41
+ }
42
+
43
+ if (onClick) {
44
+ return (
45
+ <button type="button" className={classes} style={style} onClick={onClick}>
46
+ {children}
47
+ </button>
48
+ )
49
+ }
50
+
51
+ return (
52
+ <div className={classes} style={style}>
53
+ {children}
54
+ </div>
55
+ )
56
+ }
57
+
58
+ /*******************************************************************************
59
+ * Card Subcomponents
60
+ ******************************************************************************/
61
+
62
+ export interface CardImageProps {
63
+ src: string
64
+ alt: string
65
+ className?: string
66
+ }
67
+
68
+ export function CardImage({ src, alt, className }: CardImageProps) {
69
+ return (
70
+ <div className={cx("bc-card__image", className)}>
71
+ <img src={src} alt={alt} />
72
+ </div>
73
+ )
74
+ }
75
+
76
+ export interface CardIconProps {
77
+ children: React.ReactNode
78
+ className?: string
79
+ }
80
+
81
+ export function CardIcon({ children, className }: CardIconProps) {
82
+ return <div className={cx("bc-card__icon", className)}>{children}</div>
83
+ }
84
+
85
+ export interface CardContentProps {
86
+ children: React.ReactNode
87
+ className?: string
88
+ }
89
+
90
+ export function CardContent({ children, className }: CardContentProps) {
91
+ return <div className={cx("bc-card__content", className)}>{children}</div>
92
+ }
93
+
94
+ export interface CardTitleProps {
95
+ children: React.ReactNode
96
+ className?: string
97
+ as?: "h2" | "h3" | "h4" | "h5" | "h6"
98
+ }
99
+
100
+ export function CardTitle({ children, className, as: Component = "h3" }: CardTitleProps) {
101
+ return <Component className={cx("bc-card__title", className)}>{children}</Component>
102
+ }
103
+
104
+ export interface CardDescriptionProps {
105
+ children: React.ReactNode
106
+ className?: string
107
+ }
108
+
109
+ export function CardDescription({ children, className }: CardDescriptionProps) {
110
+ return <p className={cx("bc-card__description", className)}>{children}</p>
111
+ }
112
+
113
+ export interface CardMetaProps {
114
+ children: React.ReactNode
115
+ className?: string
116
+ }
117
+
118
+ export function CardMeta({ children, className }: CardMetaProps) {
119
+ return <div className={cx("bc-card__meta", className)}>{children}</div>
120
+ }
121
+
122
+ export interface CardStatProps {
123
+ value: string | number
124
+ label: string
125
+ change?: string
126
+ changeDirection?: "up" | "down" | "neutral"
127
+ className?: string
128
+ }
129
+
130
+ export function CardStat({ value, label, change, changeDirection, className }: CardStatProps) {
131
+ return (
132
+ <div className={cx("bc-card__stat", className)}>
133
+ <span className="bc-card__stat-value">{value}</span>
134
+ <span className="bc-card__stat-label">{label}</span>
135
+ {change && (
136
+ <span
137
+ className={cx("bc-card__stat-change", {
138
+ "bc-card__stat-change--up": changeDirection === "up",
139
+ "bc-card__stat-change--down": changeDirection === "down",
140
+ })}
141
+ >
142
+ {change}
143
+ </span>
144
+ )}
145
+ </div>
146
+ )
147
+ }
148
+
149
+ export interface CardAuthorProps {
150
+ name: string
151
+ role?: string
152
+ avatar?: string
153
+ className?: string
154
+ }
155
+
156
+ export function CardAuthor({ name, role, avatar, className }: CardAuthorProps) {
157
+ return (
158
+ <div className={cx("bc-card__author", className)}>
159
+ {avatar && (
160
+ <img src={avatar} alt={name} className="bc-card__author-avatar" />
161
+ )}
162
+ <div className="bc-card__author-info">
163
+ <span className="bc-card__author-name">{name}</span>
164
+ {role && <span className="bc-card__author-role">{role}</span>}
165
+ </div>
166
+ </div>
167
+ )
168
+ }
169
+
170
+ export default Card
@@ -0,0 +1,22 @@
1
+ export {
2
+ Card,
3
+ CardImage,
4
+ CardIcon,
5
+ CardContent,
6
+ CardTitle,
7
+ CardDescription,
8
+ CardMeta,
9
+ CardStat,
10
+ CardAuthor,
11
+ type CardProps,
12
+ type CardVariant,
13
+ type CardImageProps,
14
+ type CardIconProps,
15
+ type CardContentProps,
16
+ type CardTitleProps,
17
+ type CardDescriptionProps,
18
+ type CardMetaProps,
19
+ type CardStatProps,
20
+ type CardAuthorProps,
21
+ } from "./Card.js"
22
+ export { default } from "./Card.js"
@@ -0,0 +1,150 @@
1
+ @use "../../styles/tokens" as *;
2
+ @use "../../styles/typography" as *;
3
+
4
+ /*******************************************************************************
5
+ * Hero Component
6
+ ******************************************************************************/
7
+
8
+ .bc-hero {
9
+ width: 100%;
10
+ padding: $space-8 0;
11
+
12
+ @include md-up {
13
+ padding: $space-10 0;
14
+ }
15
+
16
+ /***************************************************************************
17
+ * Background Variants
18
+ ***************************************************************************/
19
+
20
+ &--bg-white {
21
+ background-color: $white;
22
+ color: $text-primary;
23
+ }
24
+
25
+ &--bg-linen {
26
+ background-color: $linen;
27
+ color: $text-primary;
28
+ }
29
+
30
+ &--bg-charcoal {
31
+ background-color: $charcoal;
32
+ color: $text-inverse;
33
+
34
+ .bc-hero__subtitle {
35
+ color: rgba($white, 0.8);
36
+ }
37
+ }
38
+
39
+ /***************************************************************************
40
+ * Inner Container
41
+ ***************************************************************************/
42
+
43
+ &__inner {
44
+ max-width: 1024px;
45
+ margin: 0 auto;
46
+ padding: 0 $space-3;
47
+
48
+ @include md-up {
49
+ padding: 0 $space-5;
50
+ }
51
+ }
52
+
53
+ /***************************************************************************
54
+ * Variant: Home (large, centered)
55
+ ***************************************************************************/
56
+
57
+ &--home {
58
+ padding: $space-10 0;
59
+
60
+ @include md-up {
61
+ padding: $space-16 0;
62
+ }
63
+
64
+ .bc-hero__inner {
65
+ text-align: center;
66
+ max-width: 900px;
67
+ }
68
+
69
+ .bc-hero__title {
70
+ @include display-1;
71
+ margin: 0 0 $space-3;
72
+ }
73
+
74
+ .bc-hero__subtitle {
75
+ @include body-lg;
76
+ max-width: 640px;
77
+ margin: 0 auto $space-4;
78
+ }
79
+ }
80
+
81
+ /***************************************************************************
82
+ * Variant: Page (standard page header)
83
+ ***************************************************************************/
84
+
85
+ &--page {
86
+ padding: $space-6 0;
87
+
88
+ @include md-up {
89
+ padding: $space-8 0;
90
+ }
91
+
92
+ .bc-hero__title {
93
+ @include display-2;
94
+ margin: 0 0 $space-2;
95
+ }
96
+
97
+ .bc-hero__subtitle {
98
+ @include body-1;
99
+ color: $text-secondary;
100
+ margin: 0;
101
+ max-width: 640px;
102
+ }
103
+ }
104
+
105
+ /***************************************************************************
106
+ * Variant: Centered
107
+ ***************************************************************************/
108
+
109
+ &--centered {
110
+ .bc-hero__inner {
111
+ text-align: center;
112
+ }
113
+
114
+ .bc-hero__title {
115
+ @include display-2;
116
+ margin: 0 0 $space-2;
117
+ }
118
+
119
+ .bc-hero__subtitle {
120
+ @include body-1;
121
+ color: $text-secondary;
122
+ margin: 0 auto;
123
+ max-width: 640px;
124
+ }
125
+ }
126
+
127
+ /***************************************************************************
128
+ * Subcomponents
129
+ ***************************************************************************/
130
+
131
+ &__title {
132
+ color: inherit;
133
+ }
134
+
135
+ &__subtitle {
136
+ color: $text-secondary;
137
+ }
138
+
139
+ &__actions {
140
+ display: flex;
141
+ flex-wrap: wrap;
142
+ gap: $space-2;
143
+ margin-top: $space-4;
144
+
145
+ .bc-hero--home &,
146
+ .bc-hero--centered & {
147
+ justify-content: center;
148
+ }
149
+ }
150
+ }
@@ -0,0 +1,299 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { within, expect } from "@storybook/test"
3
+
4
+ import { Hero, HeroTitle, HeroSubtitle, HeroActions } from "./Hero"
5
+ import { Button } from "../../primitives/Button"
6
+
7
+ const meta: Meta<typeof Hero> = {
8
+ title: "Components/Content/Hero",
9
+ component: Hero,
10
+ parameters: {
11
+ docs: {
12
+ description: {
13
+ component: `
14
+ A hero section component for page headers with title, subtitle, and call-to-action buttons.
15
+
16
+ ## Usage
17
+
18
+ \`\`\`tsx
19
+ import { Hero, HeroTitle, HeroSubtitle, HeroActions } from "@buildcanada/components"
20
+ import { Button } from "@buildcanada/components"
21
+
22
+ <Hero variant="home" background="linen">
23
+ <HeroTitle>Welcome to Build Canada</HeroTitle>
24
+ <HeroSubtitle>
25
+ Making government data accessible for all Canadians.
26
+ </HeroSubtitle>
27
+ <HeroActions>
28
+ <Button text="Get Started" variant="solid-auburn" />
29
+ <Button text="Learn More" variant="outline-charcoal" icon={null} />
30
+ </HeroActions>
31
+ </Hero>
32
+ \`\`\`
33
+
34
+ ## Variants
35
+
36
+ - **home**: Large, impactful hero for homepages
37
+ - **page**: Standard page header with title and description
38
+ - **centered**: Center-aligned for special sections or CTAs
39
+
40
+ ## Sub-components
41
+
42
+ - \`HeroTitle\`: Main heading (h1)
43
+ - \`HeroSubtitle\`: Supporting text
44
+ - \`HeroActions\`: Container for CTA buttons
45
+ `,
46
+ },
47
+ },
48
+ },
49
+ argTypes: {
50
+ variant: {
51
+ control: "select",
52
+ options: ["home", "page", "centered"],
53
+ description: "Layout variant of the hero",
54
+ },
55
+ background: {
56
+ control: "select",
57
+ options: ["white", "linen", "charcoal"],
58
+ description: "Background color",
59
+ },
60
+ },
61
+ }
62
+
63
+ export default meta
64
+ type Story = StoryObj<typeof Hero>
65
+
66
+ export const Default: Story = {
67
+ args: {
68
+ variant: "page",
69
+ background: "linen",
70
+ children: (
71
+ <>
72
+ <HeroTitle>Page Title</HeroTitle>
73
+ <HeroSubtitle>
74
+ A brief description of what this page is about and what
75
+ users can expect to find here.
76
+ </HeroSubtitle>
77
+ </>
78
+ ),
79
+ },
80
+ }
81
+
82
+ export const HomeHero: Story = {
83
+ args: {
84
+ variant: "home",
85
+ background: "linen",
86
+ children: (
87
+ <>
88
+ <HeroTitle>Build Canada</HeroTitle>
89
+ <HeroSubtitle>
90
+ Making government data accessible and understandable for all Canadians.
91
+ Explore spending, analyze trends, and discover insights.
92
+ </HeroSubtitle>
93
+ <HeroActions>
94
+ <Button text="Explore Data" variant="solid-auburn" />
95
+ <Button text="Learn More" variant="outline-charcoal" icon={null} />
96
+ </HeroActions>
97
+ </>
98
+ ),
99
+ },
100
+ }
101
+
102
+ export const PageHero: Story = {
103
+ args: {
104
+ variant: "page",
105
+ background: "linen",
106
+ children: (
107
+ <>
108
+ <HeroTitle>About Us</HeroTitle>
109
+ <HeroSubtitle>
110
+ Learn about our mission, team, and the work we do to make
111
+ government spending transparent.
112
+ </HeroSubtitle>
113
+ </>
114
+ ),
115
+ },
116
+ }
117
+
118
+ export const CenteredHero: Story = {
119
+ args: {
120
+ variant: "centered",
121
+ background: "linen",
122
+ children: (
123
+ <>
124
+ <HeroTitle>Canada Spends</HeroTitle>
125
+ <HeroSubtitle>
126
+ Interactive visualizations of government spending across
127
+ all levels of government in Canada.
128
+ </HeroSubtitle>
129
+ <HeroActions>
130
+ <Button text="View Charts" variant="solid-auburn" />
131
+ </HeroActions>
132
+ </>
133
+ ),
134
+ },
135
+ }
136
+
137
+ export const WhiteBackground: Story = {
138
+ args: {
139
+ variant: "page",
140
+ background: "white",
141
+ children: (
142
+ <>
143
+ <HeroTitle>Research & Reports</HeroTitle>
144
+ <HeroSubtitle>
145
+ In-depth analysis and reports on Canadian government policy
146
+ and spending patterns.
147
+ </HeroSubtitle>
148
+ </>
149
+ ),
150
+ },
151
+ }
152
+
153
+ export const CharcoalBackground: Story = {
154
+ args: {
155
+ variant: "centered",
156
+ background: "charcoal",
157
+ children: (
158
+ <>
159
+ <HeroTitle>Join Our Newsletter</HeroTitle>
160
+ <HeroSubtitle>
161
+ Get the latest insights and analysis delivered directly to your inbox.
162
+ </HeroSubtitle>
163
+ <HeroActions>
164
+ <Button text="Subscribe" variant="solid-auburn" />
165
+ </HeroActions>
166
+ </>
167
+ ),
168
+ },
169
+ }
170
+
171
+ export const WithMultipleActions: Story = {
172
+ args: {
173
+ variant: "home",
174
+ background: "linen",
175
+ children: (
176
+ <>
177
+ <HeroTitle>Open Government Data</HeroTitle>
178
+ <HeroSubtitle>
179
+ Access, analyze, and visualize government spending data
180
+ with our free and open-source tools.
181
+ </HeroSubtitle>
182
+ <HeroActions>
183
+ <Button text="Get Started" variant="solid-auburn" />
184
+ <Button text="View Demo" variant="outline-charcoal" icon={null} />
185
+ <Button text="Documentation" variant="outline-charcoal" icon={null} />
186
+ </HeroActions>
187
+ </>
188
+ ),
189
+ },
190
+ }
191
+
192
+ export const MinimalHero: Story = {
193
+ args: {
194
+ variant: "page",
195
+ background: "linen",
196
+ children: (
197
+ <HeroTitle>Contact</HeroTitle>
198
+ ),
199
+ },
200
+ }
201
+
202
+ export const LongContent: Story = {
203
+ args: {
204
+ variant: "home",
205
+ background: "linen",
206
+ children: (
207
+ <>
208
+ <HeroTitle>Understanding Government Spending in Canada</HeroTitle>
209
+ <HeroSubtitle>
210
+ Our platform provides comprehensive data visualization and analysis tools
211
+ that help citizens, researchers, and policymakers understand how public
212
+ money is spent across federal, provincial, and municipal governments.
213
+ From healthcare to infrastructure, education to defense, explore the
214
+ full picture of Canadian government finances.
215
+ </HeroSubtitle>
216
+ <HeroActions>
217
+ <Button text="Explore the Data" variant="solid-auburn" />
218
+ <Button text="Read Our Methodology" variant="outline-charcoal" icon={null} />
219
+ </HeroActions>
220
+ </>
221
+ ),
222
+ },
223
+ }
224
+
225
+ export const AllVariants: Story = {
226
+ render: () => (
227
+ <div style={{ display: "flex", flexDirection: "column", gap: "0" }}>
228
+ <Hero variant="home" background="linen">
229
+ <HeroTitle>Home Variant</HeroTitle>
230
+ <HeroSubtitle>Large, impactful hero for homepages with prominent CTAs.</HeroSubtitle>
231
+ <HeroActions>
232
+ <Button text="Primary Action" variant="solid-auburn" />
233
+ <Button text="Secondary" variant="outline-charcoal" icon={null} />
234
+ </HeroActions>
235
+ </Hero>
236
+ <Hero variant="page" background="white">
237
+ <HeroTitle>Page Variant</HeroTitle>
238
+ <HeroSubtitle>Standard page header with title and optional description.</HeroSubtitle>
239
+ </Hero>
240
+ <Hero variant="centered" background="charcoal">
241
+ <HeroTitle>Centered Variant</HeroTitle>
242
+ <HeroSubtitle>Center-aligned content for special sections or CTAs.</HeroSubtitle>
243
+ <HeroActions>
244
+ <Button text="Take Action" variant="solid-auburn" />
245
+ </HeroActions>
246
+ </Hero>
247
+ </div>
248
+ ),
249
+ }
250
+
251
+ // Interactive test: Title and subtitle render correctly
252
+ export const ContentTest: Story = {
253
+ args: {
254
+ variant: "page",
255
+ background: "linen",
256
+ children: (
257
+ <>
258
+ <HeroTitle>Test Title</HeroTitle>
259
+ <HeroSubtitle>Test subtitle text content.</HeroSubtitle>
260
+ </>
261
+ ),
262
+ },
263
+ play: async ({ canvasElement }) => {
264
+ const canvas = within(canvasElement)
265
+
266
+ const title = canvas.getByText("Test Title")
267
+ const subtitle = canvas.getByText("Test subtitle text content.")
268
+
269
+ await expect(title).toBeInTheDocument()
270
+ await expect(subtitle).toBeInTheDocument()
271
+ },
272
+ }
273
+
274
+ // Interactive test: Action buttons are rendered
275
+ export const ActionsTest: Story = {
276
+ args: {
277
+ variant: "home",
278
+ background: "linen",
279
+ children: (
280
+ <>
281
+ <HeroTitle>Hero with Actions</HeroTitle>
282
+ <HeroSubtitle>Testing action buttons.</HeroSubtitle>
283
+ <HeroActions>
284
+ <Button text="Primary Button" variant="solid-auburn" />
285
+ <Button text="Secondary Button" variant="outline-charcoal" icon={null} />
286
+ </HeroActions>
287
+ </>
288
+ ),
289
+ },
290
+ play: async ({ canvasElement }) => {
291
+ const canvas = within(canvasElement)
292
+
293
+ const primaryBtn = canvas.getByRole("button", { name: /primary button/i })
294
+ const secondaryBtn = canvas.getByRole("button", { name: /secondary button/i })
295
+
296
+ await expect(primaryBtn).toBeInTheDocument()
297
+ await expect(secondaryBtn).toBeInTheDocument()
298
+ },
299
+ }
@@ -0,0 +1,63 @@
1
+ import cx from "classnames"
2
+
3
+ export type HeroVariant = "home" | "page" | "centered"
4
+ export type HeroBackground = "white" | "linen" | "charcoal"
5
+
6
+ export interface HeroProps {
7
+ children: React.ReactNode
8
+ className?: string
9
+ style?: React.CSSProperties
10
+ variant?: HeroVariant
11
+ background?: HeroBackground
12
+ }
13
+
14
+ export function Hero({
15
+ children,
16
+ className,
17
+ style,
18
+ variant = "page",
19
+ background = "linen",
20
+ }: HeroProps) {
21
+ const classes = cx(
22
+ "bc-hero",
23
+ `bc-hero--${variant}`,
24
+ `bc-hero--bg-${background}`,
25
+ className
26
+ )
27
+
28
+ return (
29
+ <div className={classes} style={style}>
30
+ <div className="bc-hero__inner">{children}</div>
31
+ </div>
32
+ )
33
+ }
34
+
35
+ export interface HeroTitleProps {
36
+ children: React.ReactNode
37
+ className?: string
38
+ as?: "h1" | "h2"
39
+ }
40
+
41
+ export function HeroTitle({ children, className, as: Component = "h1" }: HeroTitleProps) {
42
+ return <Component className={cx("bc-hero__title", className)}>{children}</Component>
43
+ }
44
+
45
+ export interface HeroSubtitleProps {
46
+ children: React.ReactNode
47
+ className?: string
48
+ }
49
+
50
+ export function HeroSubtitle({ children, className }: HeroSubtitleProps) {
51
+ return <p className={cx("bc-hero__subtitle", className)}>{children}</p>
52
+ }
53
+
54
+ export interface HeroActionsProps {
55
+ children: React.ReactNode
56
+ className?: string
57
+ }
58
+
59
+ export function HeroActions({ children, className }: HeroActionsProps) {
60
+ return <div className={cx("bc-hero__actions", className)}>{children}</div>
61
+ }
62
+
63
+ export default Hero