import type { Meta, StoryObj } from "@storybook/react-vite"; import { within, expect } from "storybook/test"; import { Cluster } from "./cluster"; import "./cluster.scss"; const meta: Meta = { title: "FP.React Components/Layout/Cluster", component: Cluster, tags: ["autodocs", "beta", "layout"], parameters: { docs: { description: { component: ` # Cluster - Layout Primitive A wrapping flex layout for inline groups that need to flow and wrap naturally. ## Features - **Auto-Wrapping**: Items wrap to next line when container is full - **Fluid Spacing**: Responsive gap using CSS clamp() - **Semantic**: Clear intent for inline grouped content - **Polymorphic**: Render as any semantic HTML element - **Type-Safe**: Full TypeScript support ## When to Use - **Cluster**: Inline content that wraps (tags, badges, buttons) - **Stack**: Vertical/horizontal layouts without wrapping - **Box**: Padding/margin on containers (no gap) [View Full Documentation →](https://github.com/anthropics/fpkit/blob/main/packages/fpkit/src/components/cluster/README.mdx) `, }, }, }, }; export default meta; type Story = StoryObj; /** * Default Cluster with small gap. * Perfect for tag clouds and inline groups. */ export const Default: Story = { args: { gap: "sm", children: ( <> {["React", "TypeScript", "CSS", "Accessibility", "Performance"].map((tag) => ( {tag} ))} ), }, play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); await step("Cluster renders correctly", async () => { expect(canvas.getByText("React")).toBeInTheDocument(); }); await step("Cluster has correct classes", async () => { const cluster = canvas.getByText("React").parentElement; expect(cluster).toHaveClass("cluster"); expect(cluster).toHaveClass("cluster-gap-sm"); }); }, }; /** * Button group with wrapping. * Buttons wrap to next line when they exceed container width. */ export const ButtonGroup: Story = { args: { gap: "md", styles: { maxWidth: "400px" }, children: ( <> {[...Array(8)].map((_, i) => ( ))} ), }, }; /** * Centered tag cloud. * Tags centered horizontally with wrapping. */ export const CenteredTags: Story = { args: { gap: "sm", justify: "center", children: ( <> {["HTML", "CSS", "JavaScript", "React", "Vue", "Angular", "Svelte", "TypeScript"].map( (tech) => ( {tech} ) )} ), }, }; /** * Badge cluster. * Multiple badges with different colors and sizes. */ export const Badges: Story = { render: () => ( Active New Beta Deprecated ), }; /** * Navigation links with baseline alignment. * Links aligned by baseline for consistent text alignment. */ export const Navigation: Story = { args: { as: "nav", gap: "lg", align: "baseline", justify: "center", styles: { padding: "1rem", backgroundColor: "#f8f9fa", border: "1px solid #e0e0e0", }, children: ( <> Home Products About Contact ), }, }; /** * Different gap sizes. * Demonstrates the unified spacing scale from xs to xl. */ export const GapSizes: Story = { render: () => (
{["xs", "sm", "md", "lg", "xl"].map((size) => (

Gap {size.toUpperCase()}

{[...Array(6)].map((_, i) => ( Item {i + 1} ))}
))}
), }; /** * Alignment variations. * Demonstrates different vertical alignment options. */ export const Alignments: Story = { render: () => (
{["start", "center", "end", "baseline"].map((alignment) => (

Align {alignment}

Small Medium Large
))}
), }; /** * Justification variations. * Demonstrates different horizontal alignment options. */ export const Justifications: Story = { render: () => (
{["start", "center", "end", "between"].map((justification) => (

Justify {justification}

{[...Array(4)].map((_, i) => ( Item {i + 1} ))}
))}
), }; /** * Filter pills. * Interactive filter tags that wrap naturally. */ export const FilterPills: Story = { render: () => ( {["All", "Active", "Completed", "In Progress", "Pending", "Cancelled"].map((filter) => ( ))} ), }; /** * Semantic list. * Using ul element for semantic list of items. */ export const SemanticList: Story = { args: { as: "ul", gap: "md", styles: { listStyle: "none", padding: 0 }, children: ( <> {["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"].map((item) => (
  • {item}
  • ))} ), }, };