소스 검색

docs: Add stories for CrossfadeTabPanels component

Aaron Bassett 5 달 전
부모
커밋
2ebe59ede9

+ 115 - 0
packages/component-library/src/CrossfadeTabPanels/index.stories.module.scss

@@ -0,0 +1,115 @@
+@use "../theme";
+
+.tabContent {
+  padding: theme.spacing(8);
+}
+
+.heading {
+  margin-bottom: theme.spacing(4);
+}
+
+.list {
+  margin-top: theme.spacing(4);
+  padding-left: theme.spacing(6);
+}
+
+// Custom styling story
+.homePanel {
+  padding: theme.spacing(8);
+  background-color: #f0f9ff;
+  border-radius: theme.border-radius("lg");
+
+  .heading {
+    color: #0369a1;
+  }
+}
+
+.aboutPanel {
+  padding: theme.spacing(8);
+  background-color: #f0fdf4;
+  border-radius: theme.border-radius("lg");
+
+  .heading {
+    color: #166534;
+  }
+}
+
+.contactPanel {
+  padding: theme.spacing(8);
+  background-color: #fef3c7;
+  border-radius: theme.border-radius("lg");
+
+  .heading {
+    color: #92400e;
+  }
+}
+
+// Complex content story
+.section {
+  margin-top: theme.spacing(4);
+}
+
+.grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: theme.spacing(4);
+  margin-top: theme.spacing(4);
+}
+
+.widget {
+  padding: theme.spacing(4);
+  border: 1px solid theme.color("border");
+  border-radius: theme.border-radius("base");
+}
+
+.chartPlaceholder {
+  padding: theme.spacing(4);
+  background-color: theme.color("background", "secondary");
+  border-radius: theme.border-radius("base");
+  margin-bottom: theme.spacing(4);
+}
+
+.chart {
+  height: 200px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: theme.color("border");
+}
+
+// Settings form
+.form {
+  margin-top: theme.spacing(4);
+}
+
+.formField {
+  margin-bottom: theme.spacing(4);
+}
+
+.label {
+  display: block;
+  margin-bottom: theme.spacing(2);
+}
+
+.input,
+.select {
+  padding: theme.spacing(2);
+  width: 100%;
+  max-width: 300px;
+  border: 1px solid theme.color("border");
+  border-radius: theme.border-radius("base");
+}
+
+.button {
+  padding: theme.spacing(2) theme.spacing(4);
+  margin-top: theme.spacing(4);
+  background-color: theme.color("button", "primary", "background", "normal");
+  color: theme.color("button", "primary", "foreground");
+  border: none;
+  border-radius: theme.border-radius("base");
+  cursor: pointer;
+
+  &:hover {
+    background-color: theme.color("button", "primary", "background", "hover");
+  }
+}

+ 260 - 0
packages/component-library/src/CrossfadeTabPanels/index.stories.tsx

@@ -0,0 +1,260 @@
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { CrossfadeTabPanels as CrossfadeTabPanelsComponent } from "./index.jsx";
+import { TabList } from "../TabList/index.jsx";
+import { Tabs } from "../unstyled/Tabs/index.jsx";
+import styles from "./index.stories.module.scss";
+
+const meta = {
+  component: CrossfadeTabPanelsComponent,
+  parameters: {
+    docs: {
+      description: {
+        component:
+          "CrossfadeTabPanels provides animated transitions between tab panels using a crossfade effect. It must be used within a Tabs context.",
+      },
+    },
+  },
+  argTypes: {
+    items: {
+      description: "Array of tab panel items with id, optional className, and children",
+      table: {
+        category: "Props",
+      },
+    },
+  },
+  tags: ["autodocs"],
+} satisfies Meta<typeof CrossfadeTabPanelsComponent>;
+export default meta;
+
+type Story = StoryObj<typeof CrossfadeTabPanelsComponent>;
+
+export const Default: Story = {
+  render: () => (
+    <Tabs defaultSelectedKey="tab1">
+      <TabList
+        label="Example tabs"
+        items={[
+          { id: "tab1", children: "Tab 1" },
+          { id: "tab2", children: "Tab 2" },
+          { id: "tab3", children: "Tab 3" },
+        ]}
+      />
+      <CrossfadeTabPanelsComponent
+        items={[
+          {
+            id: "tab1",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Tab 1 Content</h2>
+                <p>This is the content for the first tab.</p>
+              </div>
+            ),
+          },
+          {
+            id: "tab2",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Tab 2 Content</h2>
+                <p>This is the content for the second tab.</p>
+                <p>Notice how it crossfades when switching tabs.</p>
+              </div>
+            ),
+          },
+          {
+            id: "tab3",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Tab 3 Content</h2>
+                <p>This is the content for the third tab.</p>
+                <ul className={styles.list}>
+                  <li>Item 1</li>
+                  <li>Item 2</li>
+                  <li>Item 3</li>
+                </ul>
+              </div>
+            ),
+          },
+        ]}
+      />
+    </Tabs>
+  ),
+};
+
+export const WithCustomStyling: Story = {
+  render: () => (
+    <Tabs defaultSelectedKey="home">
+      <TabList
+        label="Navigation tabs"
+        items={[
+          { id: "home", children: "Home" },
+          { id: "about", children: "About" },
+          { id: "contact", children: "Contact" },
+        ]}
+      />
+      <CrossfadeTabPanelsComponent
+        items={[
+          {
+            id: "home",
+            children: (
+              <div className={styles.homePanel}>
+                <h2 className={styles.heading}>Welcome Home</h2>
+                <p>This panel has custom styling with a blue theme.</p>
+              </div>
+            ),
+          },
+          {
+            id: "about",
+            children: (
+              <div className={styles.aboutPanel}>
+                <h2 className={styles.heading}>About Us</h2>
+                <p>This panel has custom styling with a green theme.</p>
+              </div>
+            ),
+          },
+          {
+            id: "contact",
+            children: (
+              <div className={styles.contactPanel}>
+                <h2 className={styles.heading}>Contact Us</h2>
+                <p>This panel has custom styling with a yellow theme.</p>
+              </div>
+            ),
+          },
+        ]}
+      />
+    </Tabs>
+  ),
+};
+
+export const DifferentHeights: Story = {
+  render: () => (
+    <Tabs defaultSelectedKey="short">
+      <TabList
+        label="Content tabs"
+        items={[
+          { id: "short", children: "Short Content" },
+          { id: "medium", children: "Medium Content" },
+          { id: "long", children: "Long Content" },
+        ]}
+      />
+      <CrossfadeTabPanelsComponent
+        items={[
+          {
+            id: "short",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Short Content</h2>
+                <p>Just a single paragraph here.</p>
+              </div>
+            ),
+          },
+          {
+            id: "medium",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Medium Content</h2>
+                <p>This tab has more content than the first one.</p>
+                <p>It includes multiple paragraphs to show how the crossfade handles different heights.</p>
+                <p>The animation should smoothly transition between different content sizes.</p>
+              </div>
+            ),
+          },
+          {
+            id: "long",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Long Content</h2>
+                <p>This tab contains the most content to demonstrate height transitions.</p>
+                <h3>Section 1</h3>
+                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
+                <h3>Section 2</h3>
+                <p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
+                <h3>Section 3</h3>
+                <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p>
+              </div>
+            ),
+          },
+        ]}
+      />
+    </Tabs>
+  ),
+};
+
+export const ComplexContent: Story = {
+  render: () => (
+    <Tabs defaultSelectedKey="dashboard">
+      <TabList
+        label="Application sections"
+        items={[
+          { id: "dashboard", children: "Dashboard" },
+          { id: "analytics", children: "Analytics" },
+          { id: "settings", children: "Settings" },
+        ]}
+      />
+      <CrossfadeTabPanelsComponent
+        items={[
+          {
+            id: "dashboard",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Dashboard</h2>
+                <div className={styles.grid}>
+                  <div className={styles.widget}>
+                    <h3>Widget 1</h3>
+                    <p>Some dashboard content</p>
+                  </div>
+                  <div className={styles.widget}>
+                    <h3>Widget 2</h3>
+                    <p>More dashboard content</p>
+                  </div>
+                </div>
+              </div>
+            ),
+          },
+          {
+            id: "analytics",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Analytics</h2>
+                <div className={styles.section}>
+                  <div className={styles.chartPlaceholder}>
+                    <h3>Chart Placeholder</h3>
+                    <div className={styles.chart}>
+                      Chart would go here
+                    </div>
+                  </div>
+                  <p>Analytics data and insights would be displayed in this panel.</p>
+                </div>
+              </div>
+            ),
+          },
+          {
+            id: "settings",
+            children: (
+              <div className={styles.tabContent}>
+                <h2 className={styles.heading}>Settings</h2>
+                <form className={styles.form}>
+                  <div className={styles.formField}>
+                    <label className={styles.label}>Setting 1</label>
+                    <input type="text" className={styles.input} />
+                  </div>
+                  <div className={styles.formField}>
+                    <label className={styles.label}>Setting 2</label>
+                    <select className={styles.select}>
+                      <option>Option 1</option>
+                      <option>Option 2</option>
+                    </select>
+                  </div>
+                  <button type="button" className={styles.button}>
+                    Save Settings
+                  </button>
+                </form>
+              </div>
+            ),
+          },
+        ]}
+      />
+    </Tabs>
+  ),
+};