Skip to content

Commit 2ebe59e

Browse files
committed
docs: Add stories for CrossfadeTabPanels component
1 parent 5d242f1 commit 2ebe59e

File tree

2 files changed

+375
-0
lines changed

2 files changed

+375
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
@use "../theme";
2+
3+
.tabContent {
4+
padding: theme.spacing(8);
5+
}
6+
7+
.heading {
8+
margin-bottom: theme.spacing(4);
9+
}
10+
11+
.list {
12+
margin-top: theme.spacing(4);
13+
padding-left: theme.spacing(6);
14+
}
15+
16+
// Custom styling story
17+
.homePanel {
18+
padding: theme.spacing(8);
19+
background-color: #f0f9ff;
20+
border-radius: theme.border-radius("lg");
21+
22+
.heading {
23+
color: #0369a1;
24+
}
25+
}
26+
27+
.aboutPanel {
28+
padding: theme.spacing(8);
29+
background-color: #f0fdf4;
30+
border-radius: theme.border-radius("lg");
31+
32+
.heading {
33+
color: #166534;
34+
}
35+
}
36+
37+
.contactPanel {
38+
padding: theme.spacing(8);
39+
background-color: #fef3c7;
40+
border-radius: theme.border-radius("lg");
41+
42+
.heading {
43+
color: #92400e;
44+
}
45+
}
46+
47+
// Complex content story
48+
.section {
49+
margin-top: theme.spacing(4);
50+
}
51+
52+
.grid {
53+
display: grid;
54+
grid-template-columns: 1fr 1fr;
55+
gap: theme.spacing(4);
56+
margin-top: theme.spacing(4);
57+
}
58+
59+
.widget {
60+
padding: theme.spacing(4);
61+
border: 1px solid theme.color("border");
62+
border-radius: theme.border-radius("base");
63+
}
64+
65+
.chartPlaceholder {
66+
padding: theme.spacing(4);
67+
background-color: theme.color("background", "secondary");
68+
border-radius: theme.border-radius("base");
69+
margin-bottom: theme.spacing(4);
70+
}
71+
72+
.chart {
73+
height: 200px;
74+
display: flex;
75+
align-items: center;
76+
justify-content: center;
77+
background-color: theme.color("border");
78+
}
79+
80+
// Settings form
81+
.form {
82+
margin-top: theme.spacing(4);
83+
}
84+
85+
.formField {
86+
margin-bottom: theme.spacing(4);
87+
}
88+
89+
.label {
90+
display: block;
91+
margin-bottom: theme.spacing(2);
92+
}
93+
94+
.input,
95+
.select {
96+
padding: theme.spacing(2);
97+
width: 100%;
98+
max-width: 300px;
99+
border: 1px solid theme.color("border");
100+
border-radius: theme.border-radius("base");
101+
}
102+
103+
.button {
104+
padding: theme.spacing(2) theme.spacing(4);
105+
margin-top: theme.spacing(4);
106+
background-color: theme.color("button", "primary", "background", "normal");
107+
color: theme.color("button", "primary", "foreground");
108+
border: none;
109+
border-radius: theme.border-radius("base");
110+
cursor: pointer;
111+
112+
&:hover {
113+
background-color: theme.color("button", "primary", "background", "hover");
114+
}
115+
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
3+
import { CrossfadeTabPanels as CrossfadeTabPanelsComponent } from "./index.jsx";
4+
import { TabList } from "../TabList/index.jsx";
5+
import { Tabs } from "../unstyled/Tabs/index.jsx";
6+
import styles from "./index.stories.module.scss";
7+
8+
const meta = {
9+
component: CrossfadeTabPanelsComponent,
10+
parameters: {
11+
docs: {
12+
description: {
13+
component:
14+
"CrossfadeTabPanels provides animated transitions between tab panels using a crossfade effect. It must be used within a Tabs context.",
15+
},
16+
},
17+
},
18+
argTypes: {
19+
items: {
20+
description: "Array of tab panel items with id, optional className, and children",
21+
table: {
22+
category: "Props",
23+
},
24+
},
25+
},
26+
tags: ["autodocs"],
27+
} satisfies Meta<typeof CrossfadeTabPanelsComponent>;
28+
export default meta;
29+
30+
type Story = StoryObj<typeof CrossfadeTabPanelsComponent>;
31+
32+
export const Default: Story = {
33+
render: () => (
34+
<Tabs defaultSelectedKey="tab1">
35+
<TabList
36+
label="Example tabs"
37+
items={[
38+
{ id: "tab1", children: "Tab 1" },
39+
{ id: "tab2", children: "Tab 2" },
40+
{ id: "tab3", children: "Tab 3" },
41+
]}
42+
/>
43+
<CrossfadeTabPanelsComponent
44+
items={[
45+
{
46+
id: "tab1",
47+
children: (
48+
<div className={styles.tabContent}>
49+
<h2 className={styles.heading}>Tab 1 Content</h2>
50+
<p>This is the content for the first tab.</p>
51+
</div>
52+
),
53+
},
54+
{
55+
id: "tab2",
56+
children: (
57+
<div className={styles.tabContent}>
58+
<h2 className={styles.heading}>Tab 2 Content</h2>
59+
<p>This is the content for the second tab.</p>
60+
<p>Notice how it crossfades when switching tabs.</p>
61+
</div>
62+
),
63+
},
64+
{
65+
id: "tab3",
66+
children: (
67+
<div className={styles.tabContent}>
68+
<h2 className={styles.heading}>Tab 3 Content</h2>
69+
<p>This is the content for the third tab.</p>
70+
<ul className={styles.list}>
71+
<li>Item 1</li>
72+
<li>Item 2</li>
73+
<li>Item 3</li>
74+
</ul>
75+
</div>
76+
),
77+
},
78+
]}
79+
/>
80+
</Tabs>
81+
),
82+
};
83+
84+
export const WithCustomStyling: Story = {
85+
render: () => (
86+
<Tabs defaultSelectedKey="home">
87+
<TabList
88+
label="Navigation tabs"
89+
items={[
90+
{ id: "home", children: "Home" },
91+
{ id: "about", children: "About" },
92+
{ id: "contact", children: "Contact" },
93+
]}
94+
/>
95+
<CrossfadeTabPanelsComponent
96+
items={[
97+
{
98+
id: "home",
99+
children: (
100+
<div className={styles.homePanel}>
101+
<h2 className={styles.heading}>Welcome Home</h2>
102+
<p>This panel has custom styling with a blue theme.</p>
103+
</div>
104+
),
105+
},
106+
{
107+
id: "about",
108+
children: (
109+
<div className={styles.aboutPanel}>
110+
<h2 className={styles.heading}>About Us</h2>
111+
<p>This panel has custom styling with a green theme.</p>
112+
</div>
113+
),
114+
},
115+
{
116+
id: "contact",
117+
children: (
118+
<div className={styles.contactPanel}>
119+
<h2 className={styles.heading}>Contact Us</h2>
120+
<p>This panel has custom styling with a yellow theme.</p>
121+
</div>
122+
),
123+
},
124+
]}
125+
/>
126+
</Tabs>
127+
),
128+
};
129+
130+
export const DifferentHeights: Story = {
131+
render: () => (
132+
<Tabs defaultSelectedKey="short">
133+
<TabList
134+
label="Content tabs"
135+
items={[
136+
{ id: "short", children: "Short Content" },
137+
{ id: "medium", children: "Medium Content" },
138+
{ id: "long", children: "Long Content" },
139+
]}
140+
/>
141+
<CrossfadeTabPanelsComponent
142+
items={[
143+
{
144+
id: "short",
145+
children: (
146+
<div className={styles.tabContent}>
147+
<h2 className={styles.heading}>Short Content</h2>
148+
<p>Just a single paragraph here.</p>
149+
</div>
150+
),
151+
},
152+
{
153+
id: "medium",
154+
children: (
155+
<div className={styles.tabContent}>
156+
<h2 className={styles.heading}>Medium Content</h2>
157+
<p>This tab has more content than the first one.</p>
158+
<p>It includes multiple paragraphs to show how the crossfade handles different heights.</p>
159+
<p>The animation should smoothly transition between different content sizes.</p>
160+
</div>
161+
),
162+
},
163+
{
164+
id: "long",
165+
children: (
166+
<div className={styles.tabContent}>
167+
<h2 className={styles.heading}>Long Content</h2>
168+
<p>This tab contains the most content to demonstrate height transitions.</p>
169+
<h3>Section 1</h3>
170+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
171+
<h3>Section 2</h3>
172+
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
173+
<h3>Section 3</h3>
174+
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p>
175+
</div>
176+
),
177+
},
178+
]}
179+
/>
180+
</Tabs>
181+
),
182+
};
183+
184+
export const ComplexContent: Story = {
185+
render: () => (
186+
<Tabs defaultSelectedKey="dashboard">
187+
<TabList
188+
label="Application sections"
189+
items={[
190+
{ id: "dashboard", children: "Dashboard" },
191+
{ id: "analytics", children: "Analytics" },
192+
{ id: "settings", children: "Settings" },
193+
]}
194+
/>
195+
<CrossfadeTabPanelsComponent
196+
items={[
197+
{
198+
id: "dashboard",
199+
children: (
200+
<div className={styles.tabContent}>
201+
<h2 className={styles.heading}>Dashboard</h2>
202+
<div className={styles.grid}>
203+
<div className={styles.widget}>
204+
<h3>Widget 1</h3>
205+
<p>Some dashboard content</p>
206+
</div>
207+
<div className={styles.widget}>
208+
<h3>Widget 2</h3>
209+
<p>More dashboard content</p>
210+
</div>
211+
</div>
212+
</div>
213+
),
214+
},
215+
{
216+
id: "analytics",
217+
children: (
218+
<div className={styles.tabContent}>
219+
<h2 className={styles.heading}>Analytics</h2>
220+
<div className={styles.section}>
221+
<div className={styles.chartPlaceholder}>
222+
<h3>Chart Placeholder</h3>
223+
<div className={styles.chart}>
224+
Chart would go here
225+
</div>
226+
</div>
227+
<p>Analytics data and insights would be displayed in this panel.</p>
228+
</div>
229+
</div>
230+
),
231+
},
232+
{
233+
id: "settings",
234+
children: (
235+
<div className={styles.tabContent}>
236+
<h2 className={styles.heading}>Settings</h2>
237+
<form className={styles.form}>
238+
<div className={styles.formField}>
239+
<label className={styles.label}>Setting 1</label>
240+
<input type="text" className={styles.input} />
241+
</div>
242+
<div className={styles.formField}>
243+
<label className={styles.label}>Setting 2</label>
244+
<select className={styles.select}>
245+
<option>Option 1</option>
246+
<option>Option 2</option>
247+
</select>
248+
</div>
249+
<button type="button" className={styles.button}>
250+
Save Settings
251+
</button>
252+
</form>
253+
</div>
254+
),
255+
},
256+
]}
257+
/>
258+
</Tabs>
259+
),
260+
};

0 commit comments

Comments
 (0)