@nationaldesignstudio/react 0.2.0 → 0.5.0
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/component-registry.md +1310 -127
- package/dist/components/atoms/background/background.d.ts +13 -27
- package/dist/components/atoms/button/button.d.ts +64 -72
- package/dist/components/atoms/button/button.figma.d.ts +1 -0
- package/dist/components/atoms/button/icon-button.d.ts +62 -110
- package/dist/components/atoms/input/input-group.d.ts +278 -0
- package/dist/components/atoms/input/input.d.ts +121 -0
- package/dist/components/atoms/popover/popover.d.ts +195 -0
- package/dist/components/atoms/select/select.d.ts +131 -0
- package/dist/components/atoms/tooltip/tooltip.d.ts +161 -0
- package/dist/components/organisms/card/card.d.ts +3 -3
- package/dist/components/sections/hero/hero.d.ts +2 -2
- package/dist/components/sections/prose/prose.d.ts +3 -3
- package/dist/components/sections/river/river.d.ts +1 -1
- package/dist/components/sections/tout/tout.d.ts +4 -4
- package/dist/components/shared/floating-arrow.d.ts +34 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13935 -7622
- package/dist/index.js.map +1 -1
- package/dist/lib/form-control.d.ts +106 -0
- package/dist/tokens.css +4725 -19065
- package/package.json +2 -1
- package/src/components/atoms/accordion/accordion.stories.tsx +1 -1
- package/src/components/atoms/accordion/accordion.tsx +2 -2
- package/src/components/atoms/background/background.tsx +71 -109
- package/src/components/atoms/button/button.figma.tsx +37 -0
- package/src/components/atoms/button/button.stories.tsx +253 -115
- package/src/components/atoms/button/button.test.tsx +289 -5
- package/src/components/atoms/button/button.tsx +40 -101
- package/src/components/atoms/button/button.visual.test.tsx +28 -32
- package/src/components/atoms/button/icon-button.stories.tsx +44 -101
- package/src/components/atoms/button/icon-button.test.tsx +26 -94
- package/src/components/atoms/button/icon-button.tsx +81 -224
- package/src/components/atoms/input/index.ts +17 -0
- package/src/components/atoms/input/input-group.stories.tsx +646 -0
- package/src/components/atoms/input/input-group.test.tsx +362 -0
- package/src/components/atoms/input/input-group.tsx +409 -0
- package/src/components/atoms/input/input.stories.tsx +228 -0
- package/src/components/atoms/input/input.test.tsx +167 -0
- package/src/components/atoms/input/input.tsx +104 -0
- package/src/components/atoms/pager-control/pager-control.stories.tsx +6 -8
- package/src/components/atoms/pager-control/pager-control.tsx +12 -12
- package/src/components/atoms/popover/index.ts +30 -0
- package/src/components/atoms/popover/popover.stories.tsx +531 -0
- package/src/components/atoms/popover/popover.test.tsx +486 -0
- package/src/components/atoms/popover/popover.tsx +488 -0
- package/src/components/atoms/select/index.ts +18 -0
- package/src/components/atoms/select/select.stories.tsx +455 -0
- package/src/components/atoms/select/select.tsx +324 -0
- package/src/components/atoms/tooltip/index.ts +24 -0
- package/src/components/atoms/tooltip/tooltip.stories.tsx +348 -0
- package/src/components/atoms/tooltip/tooltip.test.tsx +363 -0
- package/src/components/atoms/tooltip/tooltip.tsx +347 -0
- package/src/components/dev-tools/dev-toolbar/dev-toolbar.stories.tsx +8 -17
- package/src/components/dev-tools/dev-toolbar/dev-toolbar.tsx +3 -3
- package/src/components/foundation/typography/typography.stories.tsx +401 -0
- package/src/components/organisms/card/card.stories.tsx +19 -19
- package/src/components/organisms/card/card.test.tsx +1 -1
- package/src/components/organisms/card/card.tsx +3 -3
- package/src/components/organisms/card/card.visual.test.tsx +11 -11
- package/src/components/organisms/navbar/navbar.tsx +2 -2
- package/src/components/organisms/navbar/navbar.visual.test.tsx +2 -2
- package/src/components/organisms/us-gov-banner/us-gov-banner.tsx +2 -2
- package/src/components/sections/banner/banner.stories.tsx +1 -5
- package/src/components/sections/banner/banner.test.tsx +2 -2
- package/src/components/sections/banner/banner.tsx +6 -6
- package/src/components/sections/card-grid/card-grid.tsx +5 -5
- package/src/components/sections/faq-section/faq-section.tsx +2 -2
- package/src/components/sections/hero/hero.stories.tsx +7 -7
- package/src/components/sections/hero/hero.test.tsx +5 -5
- package/src/components/sections/hero/hero.tsx +10 -11
- package/src/components/sections/prose/prose.test.tsx +2 -2
- package/src/components/sections/prose/prose.tsx +6 -7
- package/src/components/sections/river/river.stories.tsx +8 -8
- package/src/components/sections/river/river.test.tsx +4 -4
- package/src/components/sections/river/river.tsx +8 -16
- package/src/components/sections/tout/tout.stories.tsx +7 -31
- package/src/components/sections/tout/tout.test.tsx +1 -1
- package/src/components/sections/tout/tout.tsx +11 -11
- package/src/components/sections/two-column-section/two-column-section.tsx +7 -9
- package/src/components/shared/floating-arrow.tsx +78 -0
- package/src/components/shared/index.ts +5 -0
- package/src/index.ts +98 -0
- package/src/lib/form-control.ts +71 -0
- package/src/stories/grid-system.stories.tsx +309 -0
- package/src/stories/{Introduction.mdx → introduction.mdx} +29 -15
- package/src/stories/{ThemeProvider.stories.tsx → theme-provider.stories.tsx} +8 -22
- package/src/stories/{TokenShowcase.stories.tsx → token-showcase.stories.tsx} +1 -20
- package/src/stories/token-showcase.tsx +777 -0
- package/src/styles.css +3 -0
- package/src/tests/token-resolution.test.tsx +298 -0
- package/src/theme/hooks.ts +1 -1
- package/src/theme/index.ts +1 -1
- package/src/theme/theme-provider.test.tsx +270 -0
- package/src/theme/{ThemeProvider.tsx → theme-provider.tsx} +18 -2
- package/src/stories/GridSystem.stories.tsx +0 -84
- package/src/stories/TokenShowcase.tsx +0 -1429
|
@@ -24,7 +24,7 @@ describe("Card Visual Regression", () => {
|
|
|
24
24
|
<CardContent>
|
|
25
25
|
<CardBody>
|
|
26
26
|
<CardEyebrow>Optional Eyebrow</CardEyebrow>
|
|
27
|
-
<div className="flex flex-col gap-
|
|
27
|
+
<div className="flex flex-col gap-6">
|
|
28
28
|
<CardTitle>Card Title</CardTitle>
|
|
29
29
|
<CardDescription>
|
|
30
30
|
Use cards when citizens need to scan items at a glance.
|
|
@@ -32,10 +32,10 @@ describe("Card Visual Regression", () => {
|
|
|
32
32
|
</div>
|
|
33
33
|
</CardBody>
|
|
34
34
|
<CardActions>
|
|
35
|
-
<Button size="
|
|
35
|
+
<Button size="md" variant="primary">
|
|
36
36
|
Primary
|
|
37
37
|
</Button>
|
|
38
|
-
<Button size="
|
|
38
|
+
<Button size="md" variant="primary-outline">
|
|
39
39
|
Secondary
|
|
40
40
|
</Button>
|
|
41
41
|
</CardActions>
|
|
@@ -59,7 +59,7 @@ describe("Card Visual Regression", () => {
|
|
|
59
59
|
<CardContent>
|
|
60
60
|
<CardBody>
|
|
61
61
|
<CardEyebrow>Eyebrow</CardEyebrow>
|
|
62
|
-
<div className="flex flex-col gap-
|
|
62
|
+
<div className="flex flex-col gap-8">
|
|
63
63
|
<CardTitle>
|
|
64
64
|
Cards can support multi line headings easily.
|
|
65
65
|
</CardTitle>
|
|
@@ -69,10 +69,10 @@ describe("Card Visual Regression", () => {
|
|
|
69
69
|
</div>
|
|
70
70
|
</CardBody>
|
|
71
71
|
<CardActions>
|
|
72
|
-
<Button size="sm" variant="
|
|
72
|
+
<Button size="sm" variant="primary">
|
|
73
73
|
Primary
|
|
74
74
|
</Button>
|
|
75
|
-
<Button size="sm" variant="
|
|
75
|
+
<Button size="sm" variant="primary-outline">
|
|
76
76
|
Secondary
|
|
77
77
|
</Button>
|
|
78
78
|
</CardActions>
|
|
@@ -93,7 +93,7 @@ describe("Card Visual Regression", () => {
|
|
|
93
93
|
<CardContent>
|
|
94
94
|
<CardBody>
|
|
95
95
|
<CardEyebrow>Category</CardEyebrow>
|
|
96
|
-
<div className="flex flex-col gap-
|
|
96
|
+
<div className="flex flex-col gap-6">
|
|
97
97
|
<CardTitle>Card Without Image</CardTitle>
|
|
98
98
|
<CardDescription>
|
|
99
99
|
Cards can be used without images for text-focused content.
|
|
@@ -101,7 +101,7 @@ describe("Card Visual Regression", () => {
|
|
|
101
101
|
</div>
|
|
102
102
|
</CardBody>
|
|
103
103
|
<CardActions>
|
|
104
|
-
<Button size="
|
|
104
|
+
<Button size="md" variant="primary">
|
|
105
105
|
Learn More
|
|
106
106
|
</Button>
|
|
107
107
|
</CardActions>
|
|
@@ -124,7 +124,7 @@ describe("Card Visual Regression", () => {
|
|
|
124
124
|
<CardImage />
|
|
125
125
|
<CardContent>
|
|
126
126
|
<CardBody>
|
|
127
|
-
<div className="flex flex-col gap-
|
|
127
|
+
<div className="flex flex-col gap-6">
|
|
128
128
|
<CardTitle>Card Title</CardTitle>
|
|
129
129
|
<CardDescription>
|
|
130
130
|
The eyebrow is optional and can be omitted when not needed.
|
|
@@ -132,7 +132,7 @@ describe("Card Visual Regression", () => {
|
|
|
132
132
|
</div>
|
|
133
133
|
</CardBody>
|
|
134
134
|
<CardActions>
|
|
135
|
-
<Button size="
|
|
135
|
+
<Button size="md" variant="primary">
|
|
136
136
|
Primary
|
|
137
137
|
</Button>
|
|
138
138
|
</CardActions>
|
|
@@ -156,7 +156,7 @@ describe("Card Visual Regression", () => {
|
|
|
156
156
|
<CardContent>
|
|
157
157
|
<CardBody>
|
|
158
158
|
<CardEyebrow>Information</CardEyebrow>
|
|
159
|
-
<div className="flex flex-col gap-
|
|
159
|
+
<div className="flex flex-col gap-6">
|
|
160
160
|
<CardTitle>Informational Card</CardTitle>
|
|
161
161
|
<CardDescription>
|
|
162
162
|
Cards without actions can be used for purely informational
|
|
@@ -138,7 +138,7 @@ const NavbarLink = React.forwardRef<HTMLAnchorElement, NavbarLinkProps>(
|
|
|
138
138
|
<Comp
|
|
139
139
|
ref={ref}
|
|
140
140
|
className={cn(
|
|
141
|
-
"typography-
|
|
141
|
+
"typography-body-small font-medium text-gray-900 transition-colors hover:text-gray-700",
|
|
142
142
|
active && "text-gray-1100",
|
|
143
143
|
className,
|
|
144
144
|
)}
|
|
@@ -301,7 +301,7 @@ const NavbarMobileMenuLink = React.forwardRef<
|
|
|
301
301
|
<Comp
|
|
302
302
|
ref={ref}
|
|
303
303
|
className={cn(
|
|
304
|
-
"typography-
|
|
304
|
+
"typography-body-medium font-medium text-gray-900 transition-colors hover:text-gray-700",
|
|
305
305
|
"py-spacing-component-navbar-padding-y-mobile",
|
|
306
306
|
active && "text-gray-1100",
|
|
307
307
|
className,
|
|
@@ -26,7 +26,7 @@ describe("Navbar Visual Regression", () => {
|
|
|
26
26
|
<NavbarLink href="#">Contact</NavbarLink>
|
|
27
27
|
</NavbarLinks>
|
|
28
28
|
<NavbarActions>
|
|
29
|
-
<Button size="sm" variant="
|
|
29
|
+
<Button size="sm" variant="primary">
|
|
30
30
|
Sign In
|
|
31
31
|
</Button>
|
|
32
32
|
</NavbarActions>
|
|
@@ -55,7 +55,7 @@ describe("Navbar Visual Regression", () => {
|
|
|
55
55
|
<NavbarLink href="#">Contact</NavbarLink>
|
|
56
56
|
</NavbarLinks>
|
|
57
57
|
<NavbarActions>
|
|
58
|
-
<Button size="sm" variant="
|
|
58
|
+
<Button size="sm" variant="primary">
|
|
59
59
|
Sign In
|
|
60
60
|
</Button>
|
|
61
61
|
</NavbarActions>
|
|
@@ -3,8 +3,8 @@ import { tv, type VariantProps } from "tailwind-variants";
|
|
|
3
3
|
|
|
4
4
|
const usGovBannerVariants = tv({
|
|
5
5
|
slots: {
|
|
6
|
-
root: "flex w-full items-center justify-center py-
|
|
7
|
-
content: "flex items-center gap-
|
|
6
|
+
root: "flex w-full items-center justify-center py-12",
|
|
7
|
+
content: "flex items-center gap-8",
|
|
8
8
|
text: "text-[11px] leading-[13px] tracking-[0.17px]",
|
|
9
9
|
},
|
|
10
10
|
variants: {
|
|
@@ -143,11 +143,7 @@ export const CustomBackground: Story = {
|
|
|
143
143
|
<Banner
|
|
144
144
|
heading="Custom Styled Banner"
|
|
145
145
|
description="This banner has a custom background color applied via className."
|
|
146
|
-
action={
|
|
147
|
-
<Button variant="outline" colorScheme="light">
|
|
148
|
-
Action
|
|
149
|
-
</Button>
|
|
150
|
-
}
|
|
146
|
+
action={<Button variant="secondary-outline">Action</Button>}
|
|
151
147
|
className="bg-gray-1000 text-gray-50 [&_h2]:text-gray-50 [&_p]:text-gray-200"
|
|
152
148
|
/>
|
|
153
149
|
),
|
|
@@ -156,8 +156,8 @@ describe("Banner", () => {
|
|
|
156
156
|
|
|
157
157
|
const banner = page.getByTestId("banner");
|
|
158
158
|
// Mobile padding
|
|
159
|
-
await expect.element(banner).toHaveClass(/px-
|
|
160
|
-
await expect.element(banner).toHaveClass(/py-
|
|
159
|
+
await expect.element(banner).toHaveClass(/px-20/);
|
|
160
|
+
await expect.element(banner).toHaveClass(/py-32/);
|
|
161
161
|
});
|
|
162
162
|
});
|
|
163
163
|
|
|
@@ -21,9 +21,9 @@ const bannerVariants = tv({
|
|
|
21
21
|
"col-full",
|
|
22
22
|
// Responsive padding: mobile -> tablet -> desktop
|
|
23
23
|
// Uses primitive spacing tokens
|
|
24
|
-
"px-
|
|
25
|
-
"md:p-
|
|
26
|
-
"lg:px-
|
|
24
|
+
"px-20 py-32",
|
|
25
|
+
"md:p-56",
|
|
26
|
+
"lg:px-72 lg:pb-72 lg:pt-0",
|
|
27
27
|
],
|
|
28
28
|
variants: {
|
|
29
29
|
colorScheme: {
|
|
@@ -95,12 +95,12 @@ const Banner = React.forwardRef<HTMLElement, BannerProps>(
|
|
|
95
95
|
<div
|
|
96
96
|
className={cn(
|
|
97
97
|
// Uses primitive spacing tokens
|
|
98
|
-
"flex flex-col md:flex-row gap-
|
|
99
|
-
colorScheme === "dark" && "border-t border-gray-700 py-
|
|
98
|
+
"flex flex-col md:flex-row gap-20 items-start md:items-center md:justify-between",
|
|
99
|
+
colorScheme === "dark" && "border-t border-gray-700 py-36",
|
|
100
100
|
)}
|
|
101
101
|
>
|
|
102
102
|
{/* Copy section */}
|
|
103
|
-
<div className="flex flex-col gap-
|
|
103
|
+
<div className="flex flex-col gap-6 items-start">
|
|
104
104
|
<h2
|
|
105
105
|
className={cn(
|
|
106
106
|
"typography-subheading-small",
|
|
@@ -16,9 +16,9 @@ const cardGridVariants = tv({
|
|
|
16
16
|
base: [
|
|
17
17
|
"grid-container",
|
|
18
18
|
// Small (mobile): 72px y padding
|
|
19
|
-
"py-
|
|
19
|
+
"py-72",
|
|
20
20
|
// Large (desktop): 128px y padding
|
|
21
|
-
"lg:py-
|
|
21
|
+
"lg:py-128",
|
|
22
22
|
],
|
|
23
23
|
variants: {
|
|
24
24
|
variant: {
|
|
@@ -83,9 +83,9 @@ const CardGrid = React.forwardRef<HTMLElement, CardGridProps>(
|
|
|
83
83
|
<h2
|
|
84
84
|
className={cn(
|
|
85
85
|
"col-full",
|
|
86
|
-
"typography-
|
|
86
|
+
"typography-h4 text-gray-900",
|
|
87
87
|
// Gap after title: mobile default, md: 56px, lg: 64px
|
|
88
|
-
"mb-
|
|
88
|
+
"mb-36 md:mb-56 lg:mb-64",
|
|
89
89
|
)}
|
|
90
90
|
>
|
|
91
91
|
{title}
|
|
@@ -96,7 +96,7 @@ const CardGrid = React.forwardRef<HTMLElement, CardGridProps>(
|
|
|
96
96
|
className={cn(
|
|
97
97
|
"col-full",
|
|
98
98
|
// Mobile: single column
|
|
99
|
-
"grid grid-cols-1 gap-
|
|
99
|
+
"grid grid-cols-1 gap-20",
|
|
100
100
|
// Tablet: 2 columns
|
|
101
101
|
"md:grid-cols-2",
|
|
102
102
|
// Desktop: 3 columns for variant A, 2 columns for variant B
|
|
@@ -66,9 +66,9 @@ const FaqSection = React.forwardRef<HTMLElement, FaqSectionProps>(
|
|
|
66
66
|
title={title}
|
|
67
67
|
className={cn(
|
|
68
68
|
// Override title typography to be larger
|
|
69
|
-
"[&_h2]:typography-
|
|
69
|
+
"[&_h2]:typography-h4",
|
|
70
70
|
// Accordion typography overrides
|
|
71
|
-
"[&_button]:typography-body-large [&_button]:md:typography-
|
|
71
|
+
"[&_button]:typography-body-large [&_button]:md:typography-h5",
|
|
72
72
|
"[&_[data-accordion-panel]]:typography-body-medium [&_[data-accordion-panel]]:md:typography-body-large",
|
|
73
73
|
className,
|
|
74
74
|
)}
|
|
@@ -159,7 +159,7 @@ export const WithCloudflareStream: Story = {
|
|
|
159
159
|
* Mock banner component for story demonstration
|
|
160
160
|
*/
|
|
161
161
|
const MockBanner = () => (
|
|
162
|
-
<div className="bg-gray-1200 px-
|
|
162
|
+
<div className="bg-gray-1200 px-16 py-8 text-center text-14 text-text-inverted">
|
|
163
163
|
An official website of the United States government
|
|
164
164
|
</div>
|
|
165
165
|
);
|
|
@@ -168,10 +168,10 @@ const MockBanner = () => (
|
|
|
168
168
|
* Mock navigation component for story demonstration
|
|
169
169
|
*/
|
|
170
170
|
const MockNavigation = () => (
|
|
171
|
-
<nav className="flex items-center justify-between px-
|
|
172
|
-
<div className="flex items-center gap-
|
|
171
|
+
<nav className="flex items-center justify-between px-56 py-16">
|
|
172
|
+
<div className="flex items-center gap-24">
|
|
173
173
|
<div className="size-48 rounded-full bg-gray-50" />
|
|
174
|
-
<div className="flex gap-
|
|
174
|
+
<div className="flex gap-24 text-14 text-text-inverted">
|
|
175
175
|
<span className="cursor-pointer hover:opacity-80">Link 1</span>
|
|
176
176
|
<span className="cursor-pointer hover:opacity-80">Link 2</span>
|
|
177
177
|
</div>
|
|
@@ -199,7 +199,7 @@ export const WithTopSlot: Story = {
|
|
|
199
199
|
*/
|
|
200
200
|
export const WithRoundedCorners: Story = {
|
|
201
201
|
render: () => (
|
|
202
|
-
<div className="bg-bg-page p-
|
|
202
|
+
<div className="bg-bg-page p-32">
|
|
203
203
|
<Hero
|
|
204
204
|
variant="A1"
|
|
205
205
|
title="Rounded Corners"
|
|
@@ -234,7 +234,7 @@ export const WithTopAndRoundedCorners: Story = {
|
|
|
234
234
|
</>
|
|
235
235
|
}
|
|
236
236
|
>
|
|
237
|
-
<p className="mt-
|
|
237
|
+
<p className="mt-16 max-w-[560px] text-20 text-text-inverted">
|
|
238
238
|
A subtitle or description can be added as children
|
|
239
239
|
</p>
|
|
240
240
|
</Hero>
|
|
@@ -261,7 +261,7 @@ export const UsingSubComponents: Story = {
|
|
|
261
261
|
<h1 className="text-64 font-medium text-text-inverted lg:text-128">
|
|
262
262
|
Custom Layout
|
|
263
263
|
</h1>
|
|
264
|
-
<p className="mt-
|
|
264
|
+
<p className="mt-16 text-20 text-text-inverted">
|
|
265
265
|
Using HeroHeader and HeroContent sub-components
|
|
266
266
|
</p>
|
|
267
267
|
</HeroContent>
|
|
@@ -67,8 +67,8 @@ describe("Hero", () => {
|
|
|
67
67
|
render(<Hero title="Default" data-testid="hero" />);
|
|
68
68
|
|
|
69
69
|
const hero = page.getByTestId("hero");
|
|
70
|
-
// Uses semantic token bg-bg-
|
|
71
|
-
await expect.element(hero).toHaveClass(/bg-bg-
|
|
70
|
+
// Uses semantic token bg-bg-page for default dark colorScheme
|
|
71
|
+
await expect.element(hero).toHaveClass(/bg-bg-page/);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
test("applies minimum height for viewport coverage", async () => {
|
|
@@ -115,7 +115,7 @@ describe("Hero", () => {
|
|
|
115
115
|
render(<Hero title="A1 Hero" variant="A1" data-testid="hero" />);
|
|
116
116
|
|
|
117
117
|
const hero = page.getByTestId("hero");
|
|
118
|
-
await expect.element(hero).toHaveClass(/bg-bg-
|
|
118
|
+
await expect.element(hero).toHaveClass(/bg-bg-page/);
|
|
119
119
|
await expect.element(hero).toHaveClass(/min-h-\[80vh\]/);
|
|
120
120
|
});
|
|
121
121
|
|
|
@@ -123,7 +123,7 @@ describe("Hero", () => {
|
|
|
123
123
|
render(<Hero title="A2 Hero" variant="A2" data-testid="hero" />);
|
|
124
124
|
|
|
125
125
|
const hero = page.getByTestId("hero");
|
|
126
|
-
await expect.element(hero).toHaveClass(/bg-bg-
|
|
126
|
+
await expect.element(hero).toHaveClass(/bg-bg-page/);
|
|
127
127
|
await expect.element(hero).toHaveClass(/min-h-\[80vh\]/);
|
|
128
128
|
});
|
|
129
129
|
|
|
@@ -131,7 +131,7 @@ describe("Hero", () => {
|
|
|
131
131
|
render(<Hero title="A3 Hero" variant="A3" data-testid="hero" />);
|
|
132
132
|
|
|
133
133
|
const hero = page.getByTestId("hero");
|
|
134
|
-
await expect.element(hero).toHaveClass(/bg-bg-
|
|
134
|
+
await expect.element(hero).toHaveClass(/bg-bg-page/);
|
|
135
135
|
await expect.element(hero).toHaveClass(/min-h-\[80vh\]/);
|
|
136
136
|
});
|
|
137
137
|
});
|
|
@@ -18,8 +18,7 @@ export {
|
|
|
18
18
|
type BackgroundVideoProps as HeroBackgroundVideoProps,
|
|
19
19
|
} from "@/components/atoms/background";
|
|
20
20
|
|
|
21
|
-
const DEFAULT_TITLE_TYPOGRAPHY =
|
|
22
|
-
"text-64 leading-64 tracking-64 md:text-128 md:leading-128 md:tracking-128 lg:text-192 lg:leading-192 lg:tracking-192 font-medium";
|
|
21
|
+
const DEFAULT_TITLE_TYPOGRAPHY = "typography-h1-display";
|
|
23
22
|
|
|
24
23
|
const heroVariants = tv({
|
|
25
24
|
slots: {
|
|
@@ -27,8 +26,8 @@ const heroVariants = tv({
|
|
|
27
26
|
top: "relative z-10 w-full",
|
|
28
27
|
content: [
|
|
29
28
|
"relative z-10 mx-auto flex w-full max-w-screen-xl flex-1 flex-col",
|
|
30
|
-
"p-
|
|
31
|
-
"md:p-
|
|
29
|
+
"p-20",
|
|
30
|
+
"md:p-56",
|
|
32
31
|
],
|
|
33
32
|
title: DEFAULT_TITLE_TYPOGRAPHY,
|
|
34
33
|
},
|
|
@@ -36,15 +35,15 @@ const heroVariants = tv({
|
|
|
36
35
|
variant: {
|
|
37
36
|
A1: {
|
|
38
37
|
root: "min-h-[80vh]",
|
|
39
|
-
content: ["justify-end", "lg:p-
|
|
38
|
+
content: ["justify-end", "lg:p-72"],
|
|
40
39
|
},
|
|
41
40
|
A2: {
|
|
42
41
|
root: "min-h-[80vh]",
|
|
43
|
-
content: ["justify-start", "lg:p-
|
|
42
|
+
content: ["justify-start", "lg:p-64"],
|
|
44
43
|
},
|
|
45
44
|
A3: {
|
|
46
45
|
root: "min-h-[80vh]",
|
|
47
|
-
content: ["items-center justify-center", "lg:p-
|
|
46
|
+
content: ["items-center justify-center", "lg:p-64"],
|
|
48
47
|
},
|
|
49
48
|
},
|
|
50
49
|
colorScheme: {
|
|
@@ -80,9 +79,9 @@ const heroHeaderVariants = tv({
|
|
|
80
79
|
const heroContentVariants = tv({
|
|
81
80
|
base: [
|
|
82
81
|
"relative z-10 mx-auto flex w-full max-w-screen-xl flex-1 flex-col",
|
|
83
|
-
"p-
|
|
84
|
-
"md:p-
|
|
85
|
-
"lg:p-
|
|
82
|
+
"p-20",
|
|
83
|
+
"md:p-56",
|
|
84
|
+
"lg:p-72",
|
|
86
85
|
],
|
|
87
86
|
});
|
|
88
87
|
|
|
@@ -136,7 +135,7 @@ export interface HeroProps
|
|
|
136
135
|
title?: string;
|
|
137
136
|
/**
|
|
138
137
|
* Custom typography class for the title using primitive tokens.
|
|
139
|
-
* Default: "
|
|
138
|
+
* Default: "typography-h1-display"
|
|
140
139
|
*/
|
|
141
140
|
titleClassName?: string;
|
|
142
141
|
/**
|
|
@@ -131,7 +131,7 @@ describe("Prose", () => {
|
|
|
131
131
|
);
|
|
132
132
|
|
|
133
133
|
const heading = page.getByRole("heading", { name: "H2 Test" });
|
|
134
|
-
await expect.element(heading).toHaveClass(/typography-
|
|
134
|
+
await expect.element(heading).toHaveClass(/typography-h3/);
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
test("h3 heading has correct typography class", async () => {
|
|
@@ -144,7 +144,7 @@ describe("Prose", () => {
|
|
|
144
144
|
);
|
|
145
145
|
|
|
146
146
|
const heading = page.getByRole("heading", { name: "H3 Test" });
|
|
147
|
-
await expect.element(heading).toHaveClass(/typography-
|
|
147
|
+
await expect.element(heading).toHaveClass(/typography-h4/);
|
|
148
148
|
});
|
|
149
149
|
});
|
|
150
150
|
|
|
@@ -23,7 +23,7 @@ const Prose = React.forwardRef<HTMLDivElement, ProseProps>(
|
|
|
23
23
|
className={cn(
|
|
24
24
|
"flex w-full max-w-[700px] flex-col overflow-hidden",
|
|
25
25
|
// Responsive gap between sections
|
|
26
|
-
"gap-
|
|
26
|
+
"gap-56 md:gap-72 xl:gap-96",
|
|
27
27
|
className,
|
|
28
28
|
)}
|
|
29
29
|
{...props}
|
|
@@ -52,15 +52,14 @@ export interface ProseSectionProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
52
52
|
* A section within Prose content, containing a heading and body text.
|
|
53
53
|
*
|
|
54
54
|
* Responsive typography:
|
|
55
|
-
* - h2: Uses typography-
|
|
56
|
-
* - h3: Uses typography-
|
|
57
|
-
* - Body: Uses typography-body-medium
|
|
55
|
+
* - h2: Uses typography-h3
|
|
56
|
+
* - h3: Uses typography-h4
|
|
57
|
+
* - Body: Uses typography-body-medium
|
|
58
58
|
*/
|
|
59
59
|
const ProseSection = React.forwardRef<HTMLElement, ProseSectionProps>(
|
|
60
60
|
({ className, heading, as = "h2", children, ...props }, ref) => {
|
|
61
61
|
const Heading = as;
|
|
62
|
-
const headingClass =
|
|
63
|
-
as === "h2" ? "typography-headline-medium" : "typography-headline-small";
|
|
62
|
+
const headingClass = as === "h2" ? "typography-h3" : "typography-h4";
|
|
64
63
|
|
|
65
64
|
return (
|
|
66
65
|
<section
|
|
@@ -68,7 +67,7 @@ const ProseSection = React.forwardRef<HTMLElement, ProseSectionProps>(
|
|
|
68
67
|
className={cn(
|
|
69
68
|
"flex w-full flex-col",
|
|
70
69
|
// Responsive gap between heading and body
|
|
71
|
-
"gap-
|
|
70
|
+
"gap-24 md:gap-40",
|
|
72
71
|
className,
|
|
73
72
|
)}
|
|
74
73
|
{...props}
|
|
@@ -51,7 +51,7 @@ Playground.args = {
|
|
|
51
51
|
headline: "Feature Headline",
|
|
52
52
|
body: "Use rivers to present content with supporting media. They work great for feature highlights, product showcases, and storytelling sections.",
|
|
53
53
|
primaryAction: <Button>Primary Action</Button>,
|
|
54
|
-
secondaryAction: <Button variant="
|
|
54
|
+
secondaryAction: <Button variant="outline">Secondary</Button>,
|
|
55
55
|
media: <PlaceholderImage />,
|
|
56
56
|
};
|
|
57
57
|
|
|
@@ -69,7 +69,7 @@ export const VariantA: Story = {
|
|
|
69
69
|
headline="Text Left, Media Right"
|
|
70
70
|
body="Variant A places the text content on the left (9 columns) and media on the right (15 columns) on desktop viewports. On mobile and tablet, they stack vertically."
|
|
71
71
|
primaryAction={<Button>Primary Action</Button>}
|
|
72
|
-
secondaryAction={<Button variant="
|
|
72
|
+
secondaryAction={<Button variant="outline">Secondary</Button>}
|
|
73
73
|
media={<PlaceholderImage />}
|
|
74
74
|
/>
|
|
75
75
|
),
|
|
@@ -85,7 +85,7 @@ export const VariantB: Story = {
|
|
|
85
85
|
headline="Media Left, Text Right"
|
|
86
86
|
body="Variant B places the media on the left (15 columns) and text content on the right (9 columns) on desktop viewports. On mobile and tablet, they stack vertically with text first."
|
|
87
87
|
primaryAction={<Button>Primary Action</Button>}
|
|
88
|
-
secondaryAction={<Button variant="
|
|
88
|
+
secondaryAction={<Button variant="outline">Secondary</Button>}
|
|
89
89
|
media={<PlaceholderImage />}
|
|
90
90
|
/>
|
|
91
91
|
),
|
|
@@ -102,7 +102,7 @@ export const VariantADesktop: Story = {
|
|
|
102
102
|
headline="Desktop View"
|
|
103
103
|
body="On desktop (lg, 1440px), the content spans 9 columns and the media spans 15 columns in a horizontal layout."
|
|
104
104
|
primaryAction={<Button>Primary</Button>}
|
|
105
|
-
secondaryAction={<Button variant="
|
|
105
|
+
secondaryAction={<Button variant="outline">Secondary</Button>}
|
|
106
106
|
media={<PlaceholderImage />}
|
|
107
107
|
/>
|
|
108
108
|
),
|
|
@@ -118,7 +118,7 @@ export const VariantATablet: Story = {
|
|
|
118
118
|
headline="Tablet View"
|
|
119
119
|
body="On tablet (md, 768px), the content and media stack vertically with the text above the media."
|
|
120
120
|
primaryAction={<Button>Primary</Button>}
|
|
121
|
-
secondaryAction={<Button variant="
|
|
121
|
+
secondaryAction={<Button variant="outline">Secondary</Button>}
|
|
122
122
|
media={<PlaceholderImage />}
|
|
123
123
|
/>
|
|
124
124
|
),
|
|
@@ -135,7 +135,7 @@ export const VariantAMobile: Story = {
|
|
|
135
135
|
body="On mobile (sm, 320px), content is stacked with smaller button sizing."
|
|
136
136
|
primaryAction={<Button size="sm">Primary</Button>}
|
|
137
137
|
secondaryAction={
|
|
138
|
-
<Button size="sm" variant="
|
|
138
|
+
<Button size="sm" variant="outline">
|
|
139
139
|
Secondary
|
|
140
140
|
</Button>
|
|
141
141
|
}
|
|
@@ -154,7 +154,7 @@ export const VariantBDesktop: Story = {
|
|
|
154
154
|
headline="Desktop View - Reversed"
|
|
155
155
|
body="Variant B reverses the layout, placing media on the left and content on the right."
|
|
156
156
|
primaryAction={<Button>Primary</Button>}
|
|
157
|
-
secondaryAction={<Button variant="
|
|
157
|
+
secondaryAction={<Button variant="outline">Secondary</Button>}
|
|
158
158
|
media={<PlaceholderImage />}
|
|
159
159
|
/>
|
|
160
160
|
),
|
|
@@ -224,7 +224,7 @@ export const WithImage: Story = {
|
|
|
224
224
|
headline="Real World Example"
|
|
225
225
|
body="Rivers work great with actual images, videos, or any media content. The media column is designed to accommodate various aspect ratios."
|
|
226
226
|
primaryAction={<Button>Get Started</Button>}
|
|
227
|
-
secondaryAction={<Button variant="
|
|
227
|
+
secondaryAction={<Button variant="outline">Learn More</Button>}
|
|
228
228
|
media={
|
|
229
229
|
<img
|
|
230
230
|
src="https://images.unsplash.com/photo-1551434678-e076c223a692?w=800&h=600&fit=crop"
|
|
@@ -177,9 +177,9 @@ describe("River", () => {
|
|
|
177
177
|
|
|
178
178
|
const river = page.getByTestId("river");
|
|
179
179
|
// Mobile padding
|
|
180
|
-
await expect.element(river).toHaveClass(/px-
|
|
181
|
-
await expect.element(river).toHaveClass(/pt-
|
|
182
|
-
await expect.element(river).toHaveClass(/pb-
|
|
180
|
+
await expect.element(river).toHaveClass(/px-20/);
|
|
181
|
+
await expect.element(river).toHaveClass(/pt-72/);
|
|
182
|
+
await expect.element(river).toHaveClass(/pb-20/);
|
|
183
183
|
});
|
|
184
184
|
});
|
|
185
185
|
|
|
@@ -246,7 +246,7 @@ describe("River", () => {
|
|
|
246
246
|
);
|
|
247
247
|
|
|
248
248
|
const headline = page.getByRole("heading", { level: 2 });
|
|
249
|
-
await expect.element(headline).toHaveClass(/typography-
|
|
249
|
+
await expect.element(headline).toHaveClass(/typography-h4/);
|
|
250
250
|
await expect.element(headline).toHaveClass(/text-gray-900/);
|
|
251
251
|
});
|
|
252
252
|
|
|
@@ -16,11 +16,11 @@ const riverVariants = tv({
|
|
|
16
16
|
base: [
|
|
17
17
|
"col-full",
|
|
18
18
|
// Small (mobile): 20px x, 72px top, 20px bottom
|
|
19
|
-
"px-
|
|
19
|
+
"px-20 pt-72 pb-20",
|
|
20
20
|
// Medium (tablet): 56px x, 96px y
|
|
21
|
-
"md:px-
|
|
21
|
+
"md:px-56 md:py-96",
|
|
22
22
|
// Large (desktop): 72px x, 128px y
|
|
23
|
-
"lg:px-
|
|
23
|
+
"lg:px-72 lg:py-128",
|
|
24
24
|
],
|
|
25
25
|
variants: {
|
|
26
26
|
variant: {
|
|
@@ -77,7 +77,7 @@ export interface RiverProps
|
|
|
77
77
|
* headline="Feature Headline"
|
|
78
78
|
* body="Description of the feature..."
|
|
79
79
|
* primaryAction={<Button>Primary</Button>}
|
|
80
|
-
* secondaryAction={<Button variant="
|
|
80
|
+
* secondaryAction={<Button variant="outline">Secondary</Button>}
|
|
81
81
|
* media={<img src="..." alt="Feature" />}
|
|
82
82
|
* />
|
|
83
83
|
* </div>
|
|
@@ -106,19 +106,14 @@ const River = React.forwardRef<HTMLElement, RiverProps>(
|
|
|
106
106
|
)}
|
|
107
107
|
>
|
|
108
108
|
{/* Text content with 16px gap - uses primitive spacing tokens */}
|
|
109
|
-
<div className="flex flex-col gap-
|
|
110
|
-
<h2 className="typography-
|
|
111
|
-
{headline}
|
|
112
|
-
</h2>
|
|
109
|
+
<div className="flex flex-col gap-16">
|
|
110
|
+
<h2 className="typography-h4 text-gray-900">{headline}</h2>
|
|
113
111
|
<p className="typography-body-small text-gray-800">{body}</p>
|
|
114
112
|
</div>
|
|
115
113
|
|
|
116
114
|
{/* Buttons with 36px gap from text, responsive sizes - uses primitive spacing tokens */}
|
|
117
115
|
<div
|
|
118
|
-
className={cn(
|
|
119
|
-
"flex flex-row gap-spacing-16 mt-spacing-36",
|
|
120
|
-
"[&>*]:flex-shrink-0",
|
|
121
|
-
)}
|
|
116
|
+
className={cn("flex flex-row gap-16 mt-36", "[&>*]:flex-shrink-0")}
|
|
122
117
|
>
|
|
123
118
|
{primaryAction}
|
|
124
119
|
{secondaryAction}
|
|
@@ -147,10 +142,7 @@ const River = React.forwardRef<HTMLElement, RiverProps>(
|
|
|
147
142
|
>
|
|
148
143
|
{/* Inner grid container for 24-col layout - uses primitive spacing tokens */}
|
|
149
144
|
<div
|
|
150
|
-
className={cn(
|
|
151
|
-
"grid grid-cols-1 gap-spacing-36",
|
|
152
|
-
"lg:grid-cols-24 lg:gap-spacing-36",
|
|
153
|
-
)}
|
|
145
|
+
className={cn("grid grid-cols-1 gap-36", "lg:grid-cols-24 lg:gap-36")}
|
|
154
146
|
>
|
|
155
147
|
{variant === "B" ? (
|
|
156
148
|
<>
|