import type { Meta, StoryObj } from "@storybook/react-vite"; import { within, expect } from "storybook/test"; import { Grid, GridItem } from "./grid"; import "./grid.scss"; const meta: Meta = { title: "FP.React Components/Layout/Grid", component: Grid, tags: ["autodocs", "beta", "layout"], parameters: { docs: { description: { component: ` # Grid - Layout Primitive A CSS Grid-based layout primitive for responsive multi-column layouts with Grid.Item sub-component. ## Features - **CSS Grid**: True 2D layout with rows and columns - **Responsive Columns**: 1-12 column layouts or auto-fit/auto-fill - **Grid.Item**: Sub-component with column/row span control - **Fluid Spacing**: Responsive gap using CSS clamp() - **Polymorphic**: Render as any semantic HTML element - **Type-Safe**: Full TypeScript support ## When to Use - **Grid**: Multi-column card grids, dashboard layouts, responsive layouts - **Stack**: Simple vertical/horizontal layouts without explicit columns - **Cluster**: Inline groups that wrap (tags, buttons) - **Box**: Padding/margin on containers (no layout) [View Full Documentation →](https://github.com/anthropics/fpkit/blob/main/packages/fpkit/src/components/grid/README.mdx) `, }, }, }, }; export default meta; type Story = StoryObj; /** * Default 3-column grid with medium gap. * Perfect for card layouts and content grids. */ export const Default: Story = { args: { columns: 3, gap: "md", children: ( <> {[...Array(6)].map((_, i) => (
Card {i + 1}
))} ), }, play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); await step("Grid renders correctly", async () => { expect(canvas.getByText("Card 1")).toBeInTheDocument(); }); await step("Grid has correct classes", async () => { const grid = canvas.getByText("Card 1").parentElement; expect(grid).toHaveClass("grid"); expect(grid).toHaveClass("grid-cols-3"); expect(grid).toHaveClass("grid-gap-md"); }); }, }; /** * 2-column layout (main content + sidebar). * Using Grid.Item for column span control. */ export const TwoColumn: Story = { render: () => (

Main Content

Spans 8 of 12 columns (66%)

Sidebar

Spans 4 of 12 columns (33%)

), }; /** * Auto-fit grid with minimum column width. * Columns adjust automatically based on container width. */ export const AutoFit: Story = { args: { auto: "fit", minColumnWidth: "15rem", gap: "md", children: ( <> {[...Array(9)].map((_, i) => (
Item {i + 1}
))} ), }, }; /** * 4-column image gallery. * Perfect for photo grids and media galleries. */ export const ImageGallery: Story = { render: () => ( {[...Array(12)].map((_, i) => (
{i + 1}
))}
), }; /** * Dashboard layout with mixed column spans. * Demonstrates Grid.Item with various span values. */ export const Dashboard: Story = { render: () => (
Header (Full Width)
Sidebar (4 cols)
Main Content (8 cols)
Card 1
Card 2
Card 3
), }; /** * Gap size variations. * Demonstrates all gap scale values. */ export const GapSizes: Story = { render: () => (
{["xs", "sm", "md", "lg", "xl"].map((size) => (

Gap {size.toUpperCase()}

{[...Array(4)].map((_, i) => (
Item {i + 1}
))}
))}
), }; /** * Asymmetric column gaps (gapX and gapY). * Different horizontal and vertical spacing. */ export const AsymmetricGaps: Story = { args: { columns: 3, gapX: "lg", gapY: "xs", children: ( <> {[...Array(6)].map((_, i) => (
Item {i + 1}
))} ), }, }; /** * Row span example. * Grid.Item spanning multiple rows. */ export const RowSpan: Story = { render: () => (
Tall Item (2 rows)
Item 2
Item 3
Item 4
Item 5
), }; /** * Alignment options (justifyItems and alignItems). * Controls how items align within their grid cells. */ export const Alignment: Story = { render: () => (

Justify Items: Center

{[...Array(3)].map((_, i) => (
Centered
))}

Align Items: Center

{[...Array(3)].map((_, i) => (
Centered
))}
), }; /** * Column count variations. * Demonstrates different column counts from 1 to 6. */ export const ColumnCounts: Story = { render: () => (
{[1, 2, 3, 4, 5, 6].map((cols) => (

{cols} Column{cols > 1 ? "s" : ""}

{[...Array(cols)].map((_, i) => (
Col {i + 1}
))}
))}
), }; /** * Form layout with 2 columns. * Label + input pairs in a grid. */ export const FormLayout: Story = { render: () => (