import type { Meta, StoryObj } from "@storybook/react-vite"; import { within, expect } from "storybook/test"; import "./_columns.scss"; const meta: Meta = { title: "FP.React Components/Utilities/Columns", tags: ["autodocs"], parameters: { docs: { description: { component: ` ## 12-Column Utility System Bootstrap/Foundation-compatible column utilities for Flexbox layouts. Provides \`.col-1\` through \`.col-12\` classes with mobile-first responsive behavior. ### Key Features - **12-column grid**: \`.col-1\` (8.333%) through \`.col-12\` (100%) - **Mobile-first**: 100% width on mobile (< 768px), percentage widths on desktop - **Flexbox-only**: Works with Flex component or \`.col-row\` utility (NOT with Grid component) - **Optional utilities**: Offsets, auto-width, and ordering ### Container Requirements Column utilities require a flex container with \`flex-wrap: wrap\`: **Option 1: Use \`.col-row\` utility (recommended for simple layouts)** \`\`\`jsx
Column
\`\`\` **Option 2: Use Flex component (recommended for complex layouts)** \`\`\`jsx
Column
\`\`\` `, }, }, }, }; export default meta; type Story = StoryObj; // Demo card styling const demoCardStyle = { padding: "1rem", backgroundColor: "#e0e7ff", border: "2px solid #6366f1", borderRadius: "0.5rem", textAlign: "center" as const, fontWeight: "600", }; /** * Demonstrates all 12 column sizes stacked vertically. * Shows the percentage width each column class represents. */ export const AllColumnSizes: Story = { render: () => (
.col-1
8.333%
.col-2
16.667%
.col-3
25%
.col-4
33.333%
.col-5
41.667%
.col-6
50%
.col-7
58.333%
.col-8
66.667%
.col-9
75%
.col-10
83.333%
.col-11
91.667%
.col-12
100%
), play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); await step("All column sizes render correctly", async () => { expect(canvas.getByText(".col-1")).toBeInTheDocument(); expect(canvas.getByText(".col-6")).toBeInTheDocument(); expect(canvas.getByText(".col-12")).toBeInTheDocument(); }); }, }; /** * Two-column layout (50/50 split). * Common pattern for side-by-side content. */ export const TwoColumns: Story = { render: () => (
Left Column
.col-6
Right Column
.col-6
), play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); await step("Two columns render side by side", async () => { expect(canvas.getByText("Left Column")).toBeInTheDocument(); expect(canvas.getByText("Right Column")).toBeInTheDocument(); }); }, }; /** * Three-column layout (equal widths). * Perfect for feature lists, card grids, etc. */ export const ThreeColumns: Story = { render: () => (
Column 1
.col-4
Column 2
.col-4
Column 3
.col-4
), }; /** * Four-column layout (equal widths). * Great for dashboard cards or product grids. */ export const FourColumns: Story = { render: () => (
Col 1
.col-3
Col 2
.col-3
Col 3
.col-3
Col 4
.col-3
), }; /** * Sidebar layout with asymmetric columns. * Common pattern: narrow sidebar + wide main content area. */ export const SidebarLayout: Story = { render: () => (
Sidebar
.col-3
Main Content
.col-9
), }; /** * Mixed column widths demonstrating flexible layouts. * Shows how columns automatically wrap to new rows. */ export const MixedWidths: Story = { render: () => (
Wide (.col-8)
Narrow (.col-4)
Half (.col-6)
Half (.col-6)
Full Width (.col-12)
), }; /** * Column offset utilities for centering or creating asymmetric layouts. * Offsets push columns to the right using margin-inline-start. */ export const ColumnOffsets: Story = { render: () => (
Centered
.col-6.col-offset-3
Centered
.col-4.col-offset-4
Offset Left
.col-3.col-offset-2
Offset Left
.col-4.col-offset-1
), }; /** * Auto-width column that sizes based on content. * Useful for buttons, labels, or dynamic content widths. */ export const AutoWidth: Story = { render: () => (
Auto Width (.col-auto)
Fixed Width (.col-6)
Auto (.col-auto)
), }; /** * Column ordering utilities for visual reordering without changing HTML. * Useful for responsive layouts where order changes at breakpoints. */ export const ColumnOrdering: Story = { render: () => (

Visual order: Second → First → Third (using .col-order-* classes)

HTML Order: 1
Visual Order: 2
.col-order-2
HTML Order: 2
Visual Order: 1
.col-order-first
HTML Order: 3
Visual Order: 3
.col-order-last
), }; /** * Custom gap spacing using gap utility classes. * Shows how to control spacing between columns. */ export const CustomGapSpacing: Story = { render: () => (

No Gap

Column 1
Column 2
Column 3

Small Gap (0.5rem)

Column 1
Column 2
Column 3

Large Gap (2rem)

Column 1
Column 2
Column 3
), }; /** * Responsive behavior demonstration with actual responsive classes. * Resize browser to see columns stack on mobile (< 768px) and spread on desktop. */ export const ResponsiveBehavior: Story = { render: () => (
💡 Try this: Resize your browser or use DevTools responsive mode.
Mobile (< 480px): 1 column (100% width)
Tablet (≥ 480px): 2 columns (50% width each)
Desktop (≥ 1024px): 3 columns (33.33% width each)
Column 1
.col-12 .col-sm-6 .col-lg-4
Column 2
.col-12 .col-sm-6 .col-lg-4
Column 3
.col-12 .col-sm-6 .col-lg-4
), parameters: { viewport: { defaultViewport: "md", }, }, }; /** * Demonstrates how a single element responds across breakpoints. * Resize browser to see width change at 480px, 768px, and 1024px. */ export const ResponsiveBreakpoints: Story = { render: () => (
💡 Resize to test:
Mobile (< 480px): 100% width (1 column)
Tablet (≥ 480px): 50% width (2 columns)
Desktop (≥ 1024px): 33.33% width (3 columns)
.col-12 .col-sm-6 .col-lg-4
Resize to see me change!
), parameters: { viewport: { defaultViewport: "mobile1", }, }, }; /** * Dashboard card grid that adapts across breakpoints. * 1 column mobile, 2 columns tablet, 4 columns desktop. */ export const ResponsiveDashboard: Story = { render: () => (

Responsive Dashboard

{[ { title: "Total Users", value: "1,234", color: "#dbeafe" }, { title: "Revenue", value: "$12,345", color: "#fef3c7" }, { title: "Conversions", value: "567", color: "#d1fae5" }, { title: "Growth", value: "+23%", color: "#fce7f3" }, ].map((card, i) => (

{card.title}

{card.value}

))}
Layout: 1 col mobile → 2 col tablet → 4 col desktop
), }; /** * Blog-style layout with sidebar that stacks on mobile. */ export const ResponsiveSidebarLayout: Story = { render: () => (

Blog Sidebar Layout

Main Content

.col-12 .col-md-8
Full-width on mobile, 66.67% (8/12) on tablet+

Sidebar

.col-12 .col-md-4
Full-width on mobile, 33.33% (4/12) on tablet+

), }; /** * Product grid with progressive column counts. * 1 column mobile, 2 columns tablet, 3 columns desktop. */ export const ResponsiveProductGrid: Story = { render: () => (

Product Grid

{Array.from({ length: 6 }, (_, i) => (
{i + 1}

Product {i + 1}

$29.99

))}
Layout: 1 col mobile → 2 col tablet → 3 col desktop
), }; /** * Demonstrates responsive offsets for progressive centering. */ export const ResponsiveOffsets: Story = { render: () => (

Progressive Centering with Offsets

Progressively Centered Content

Mobile (< 480px): 100% width, no offset
Small (≥ 480px): 83.33% width (10/12), 8.33% left margin
Tablet (≥ 768px): 66.67% width (8/12), 16.67% left margin
Desktop (≥ 1024px): 50% width (6/12), 25% left margin

), }; /** * Demonstrates visual reordering at different breakpoints. * WARNING: Visual order doesn't change DOM order (accessibility concern). */ export const ResponsiveOrdering: Story = { render: () => (
⚠️ Accessibility Note: Visual order changes but DOM order stays the same. Screen readers and keyboard navigation follow DOM order, not visual order.

Mobile: A → B → C (natural order)

Desktop: B → A → C (reordered visually)

A
DOM: 1st
Mobile: 1st
Desktop: 2nd (.col-md-order-2)
B
DOM: 2nd
Mobile: 2nd
Desktop: 1st (.col-md-order-first)
C
DOM: 3rd
Mobile: 3rd
Desktop: 3rd (.col-md-order-last)
), }; /** * Form with responsive multi-column layout. */ export const ResponsiveFormLayout: Story = { render: () => (

Responsive Form

Layout: Full-width mobile → 2-column tablet
), };