import { Meta } from "@storybook/addon-docs/blocks";

<Meta title="FP.REACT Components/Layout/Flex/Readme" />

# Flex Component

A powerful, type-safe flexbox layout component with compound pattern, responsive
props, and semantic element restrictions. Built for modern React applications
with accessibility-first design and full TypeScript support.

## Summary

The `Flex` component provides a declarative React API for flexbox layouts,
converting props to utility classes for optimal performance. Features responsive
breakpoint props, preset layout variants, and enforced semantic HTML structure.

**Latest Version:** v3.0.0+ (Enhanced with type-safe semantic elements)

## Features

- 🧩 **Compound component pattern** - Flex.Item and Flex.Spacer sub-components
- 📱 **Responsive props** - Different layouts at sm/md/lg/xl breakpoints
- 🎯 **Preset variants** - Common patterns like 'center', 'between', 'stack'
- 🔒 **Type-safe semantic elements** - Restricts `as` prop to valid container
  elements
- ⚡ **Performance optimized** - Generates utility classes, not inline styles
- 🎨 **CSS custom properties** - Full theming via CSS variables
- 📦 **TypeScript support** - Comprehensive type definitions with autocomplete
- ♿ **Accessibility-first** - Semantic HTML by default
- 🧪 **100% test coverage** - 62 comprehensive tests

## Accessibility

This component has been designed for WCAG 2.1 AA compliance:

- ✅ Uses semantic HTML container elements (section, article, nav, etc.)
- ✅ Type system enforces proper element usage (no inline/interactive elements)
- ✅ Forwards all ARIA attributes to rendered elements
- ✅ No interactive behavior by default (purely layout)
- ✅ Supports semantic list structures (ul/ol with li elements)
- ✅ Maintains logical tab order based on DOM structure
- ✅ Flexbox respects text spacing and zoom requirements

### Semantic Element Restrictions

The `as` prop is restricted to semantic container elements to ensure proper HTML
structure:

**✅ Allowed Elements:**

- **Block containers**: `div` (default), `section`, `article`, `aside`, `main`,
  `header`, `footer`
- **List containers**: `ul`, `ol`, `dl`, `nav`
- **Form containers**: `form`, `fieldset`
- **List items** (Flex.Item only): `li`, `dt`, `dd`

**❌ Not Allowed:**

- Inline elements: `span`, `a`, `strong`, `em`
- Interactive elements: `button`, `input`, `select`
- Void elements: `img`, `hr`, `br`

This restriction prevents common accessibility mistakes and ensures semantic
HTML structure.

## Props

### Flex (Main Component)

```ts
interface FlexProps extends ResponsiveFlexProps {
  /** Preset layout variant */
  variant?: "center" | "between" | "around" | "stack" | "spread";

  /** Use inline-flex instead of flex */
  inline?: boolean;

  /** Element type to render as (restricted to container elements) */
  as?: FlexContainerElement;

  /** Additional CSS class names */
  className?: string;

  /** Inline styles and CSS custom properties */
  styles?: React.CSSProperties;

  /** Children elements */
  children?: React.ReactNode;

  /** Responsive props for small screens (≥30rem / 480px) */
  sm?: ResponsiveFlexProps;

  /** Responsive props for medium screens (≥48rem / 768px) */
  md?: ResponsiveFlexProps;

  /** Responsive props for large screens (≥62rem / 992px) */
  lg?: ResponsiveFlexProps;

  /** Responsive props for extra large screens (≥80rem / 1280px) */
  xl?: ResponsiveFlexProps;

  /** Flex direction */
  direction?: "row" | "row-reverse" | "column" | "column-reverse";

  /** Flex wrap behavior */
  wrap?: "wrap" | "nowrap" | "wrap-reverse";

  /** Gap between flex items */
  gap?: "0" | "xs" | "sm" | "md" | "lg" | "xl";

  /** Row gap (vertical spacing) */
  rowGap?: "0" | "xs" | "sm" | "md" | "lg" | "xl";

  /** Column gap (horizontal spacing) */
  colGap?: "0" | "xs" | "sm" | "md" | "lg" | "xl";

  /** Justify content (main axis alignment) */
  justify?: "start" | "end" | "center" | "between" | "around" | "evenly";

  /** Align items (cross axis alignment) */
  align?: "start" | "end" | "center" | "baseline" | "stretch";

  /** Align content (multi-line alignment) */
  alignContent?:
    | "start"
    | "end"
    | "center"
    | "between"
    | "around"
    | "evenly"
    | "stretch";
}
```

### Flex.Item

```ts
interface FlexItemProps {
  /** Element type to render as (includes list items) */
  as?: FlexItemElement;

  /** Flex grow factor */
  grow?: 0 | 1;

  /** Flex shrink factor */
  shrink?: 0 | 1;

  /** Flex basis */
  basis?: "auto" | "0" | "full";

  /** Flex shorthand */
  flex?: "1" | "auto" | "initial" | "none";

  /** Align self (overrides parent align-items) */
  alignSelf?: "auto" | "start" | "end" | "center" | "baseline" | "stretch";

  /** Order of the flex item */
  order?: "first" | "last" | "none";

  /** Additional CSS class names */
  className?: string;

  /** Inline styles and CSS custom properties */
  styles?: React.CSSProperties;

  /** Children elements */
  children?: React.ReactNode;

  /** Responsive props for different breakpoints */
  sm?: { flex?: "1" | "auto" | "none" };
  md?: { flex?: "1" | "auto" | "none" };
  lg?: { flex?: "1" | "auto" | "none" };
  xl?: { flex?: "1" | "auto" | "none" };
}
```

### Flex.Spacer

```ts
interface FlexSpacerProps {
  /** Element type to render as (container elements only) */
  as?: FlexContainerElement;

  /** Additional CSS class names */
  className?: string;

  /** Inline styles and CSS custom properties */
  styles?: React.CSSProperties;
}
```

### Default Values

| Prop        | Default | Description                               |
| ----------- | ------- | ----------------------------------------- |
| `as`        | `"div"` | Container element type                    |
| `inline`    | `false` | Display mode (flex vs inline-flex)        |
| `direction` | -       | No default (uses CSS default: row)        |
| `wrap`      | -       | No default (uses CSS default: nowrap)     |
| `gap`       | -       | No gap by default                         |
| `justify`   | -       | No default (uses CSS default: flex-start) |
| `align`     | -       | No default (uses CSS default: stretch)    |

## Usage Examples

### Basic Flex Container

```tsx
import { Flex } from "@fpkit/acss";

function BasicLayout() {
  return (
    <Flex direction="row" gap="md" justify="between" align="center">
      <div>Item 1</div>
      <div>Item 2</div>
      <div>Item 3</div>
    </Flex>
  );
}
```

### Responsive Layout

Column on mobile, row on medium+ screens:

```tsx
import { Flex } from "@fpkit/acss";

function ResponsiveLayout() {
  return (
    <Flex direction="column" gap="sm" md={{ direction: "row", gap: "lg" }}>
      <Flex.Item flex="none" md={{ flex: "1" }}>
        <h2>Sidebar</h2>
        <p>Navigation content</p>
      </Flex.Item>

      <Flex.Item flex="none" md={{ flex: "1" }}>
        <h2>Main Content</h2>
        <p>Primary content area</p>
      </Flex.Item>
    </Flex>
  );
}
```

### Using Preset Variants

Quick layouts with common patterns:

```tsx
import { Flex } from "@fpkit/acss";

function PresetVariants() {
  return (
    <>
      {/* Center everything */}
      <Flex variant="center">
        <div>Centered content</div>
      </Flex>

      {/* Space between items */}
      <Flex variant="between">
        <div>Left</div>
        <div>Right</div>
      </Flex>

      {/* Vertical stack */}
      <Flex variant="stack" gap="md">
        <div>Item 1</div>
        <div>Item 2</div>
      </Flex>
    </>
  );
}
```

### Flex.Spacer for Pushing Items Apart

```tsx
import { Flex } from "@fpkit/acss";

function Header() {
  return (
    <Flex as="header" align="center" gap="md">
      <div>Logo</div>
      <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
      </nav>
      <Flex.Spacer />
      <button>Sign In</button>
      <button>Sign Up</button>
    </Flex>
  );
}
```

### Semantic Navigation with Flex

```tsx
import { Flex } from "@fpkit/acss";

function Navigation() {
  return (
    <Flex as="nav" role="navigation" aria-label="Main navigation" gap="md">
      <a href="/">Home</a>
      <a href="/products">Products</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </Flex>
  );
}
```

### Semantic List Structure

```tsx
import { Flex } from "@fpkit/acss";

function ProductList({ products }) {
  return (
    <Flex as="ul" direction="column" gap="md">
      {products.map((product) => (
        <Flex.Item as="li" key={product.id}>
          <h3>{product.name}</h3>
          <p>{product.description}</p>
          <span>${product.price}</span>
        </Flex.Item>
      ))}
    </Flex>
  );
}
```

### Complex Responsive Grid

```tsx
import { Flex } from "@fpkit/acss";

function ProductGrid({ products }) {
  return (
    <Flex
      direction="column"
      gap="sm"
      sm={{ direction: "row", wrap: "wrap", gap: "md" }}
    >
      {products.map((product) => (
        <Flex.Item
          key={product.id}
          flex="none"
          sm={{ flex: "1" }}
          styles={{ minWidth: "300px" }}
        >
          <article>
            <img src={product.image} alt={product.name} />
            <h3>{product.name}</h3>
            <p>{product.description}</p>
            <button>Add to Cart</button>
          </article>
        </Flex.Item>
      ))}
    </Flex>
  );
}
```

### Form Layout with Flexbox

```tsx
import { Flex } from "@fpkit/acss";

function LoginForm() {
  return (
    <Flex as="form" direction="column" gap="md">
      <Flex direction="column" gap="xs">
        <label htmlFor="email">Email</label>
        <input id="email" type="email" />
      </Flex>

      <Flex direction="column" gap="xs">
        <label htmlFor="password">Password</label>
        <input id="password" type="password" />
      </Flex>

      <Flex gap="md" justify="between" align="center">
        <label>
          <input type="checkbox" /> Remember me
        </label>
        <button type="submit">Sign In</button>
      </Flex>
    </Flex>
  );
}
```

### Flex.Item with Alignment

```tsx
import { Flex } from "@fpkit/acss";

function AlignmentExample() {
  return (
    <Flex direction="row" gap="md" styles={{ minHeight: "200px" }}>
      <Flex.Item alignSelf="start">
        <div>Aligned to start</div>
      </Flex.Item>

      <Flex.Item alignSelf="center">
        <div>Centered vertically</div>
      </Flex.Item>

      <Flex.Item alignSelf="end">
        <div>Aligned to end</div>
      </Flex.Item>

      <Flex.Item alignSelf="stretch">
        <div>Stretched to full height</div>
      </Flex.Item>
    </Flex>
  );
}
```

### Visual Order Control

```tsx
import { Flex } from "@fpkit/acss";

function OrderExample() {
  return (
    <Flex direction="row" gap="md">
      <Flex.Item order="last">
        <div>Renders first in HTML, displays last visually</div>
      </Flex.Item>

      <Flex.Item>
        <div>Normal order (middle)</div>
      </Flex.Item>

      <Flex.Item order="first">
        <div>Renders last in HTML, displays first visually</div>
      </Flex.Item>
    </Flex>
  );
}
```

### Dashboard Layout

```tsx
import { Flex } from "@fpkit/acss";

function Dashboard() {
  return (
    <Flex direction="column" gap="lg" styles={{ minHeight: "100vh" }}>
      {/* Header */}
      <Flex as="header" justify="between" align="center" gap="md">
        <h1>Dashboard</h1>
        <nav>
          <Flex gap="md">
            <a href="/profile">Profile</a>
            <a href="/settings">Settings</a>
            <button>Logout</button>
          </Flex>
        </nav>
      </Flex>

      {/* Main content area */}
      <Flex as="main" flex="1" gap="lg">
        {/* Sidebar */}
        <Flex
          as="aside"
          direction="column"
          gap="md"
          styles={{ width: "250px" }}
        >
          <nav>
            <Flex direction="column" gap="sm">
              <a href="/dashboard">Overview</a>
              <a href="/analytics">Analytics</a>
              <a href="/reports">Reports</a>
            </Flex>
          </nav>
        </Flex>

        {/* Content */}
        <Flex as="section" direction="column" gap="md" flex="1">
          <h2>Overview</h2>
          <Flex wrap="wrap" gap="md">
            <Flex.Item flex="1" styles={{ minWidth: "300px" }}>
              <article>Metric 1</article>
            </Flex.Item>
            <Flex.Item flex="1" styles={{ minWidth: "300px" }}>
              <article>Metric 2</article>
            </Flex.Item>
            <Flex.Item flex="1" styles={{ minWidth: "300px" }}>
              <article>Metric 3</article>
            </Flex.Item>
          </Flex>
        </Flex>
      </Flex>

      {/* Footer */}
      <Flex as="footer" justify="center" gap="md">
        <a href="/privacy">Privacy</a>
        <a href="/terms">Terms</a>
        <a href="/contact">Contact</a>
      </Flex>
    </Flex>
  );
}
```

## Styling

The Flex component uses CSS utility classes and custom properties for styling.

### CSS Utility Classes Generated

The component automatically generates utility class names from props:

```tsx
// These props:
<Flex direction="row" gap="md" justify="between" align="center">

// Generate these classes:
// "flex flex-row gap-md justify-between items-center"
```

### Responsive Classes

Responsive props generate breakpoint-prefixed classes:

```tsx
// These props:
<Flex
  direction="column"
  md={{ direction: "row", gap: "lg" }}
>

// Generate these classes:
// "flex flex-col md:flex-row md:gap-lg"
```

### CSS Custom Properties

Override default spacing via CSS variables:

```css
:root {
  /* Gap sizes (in rem) */
  --flex-gap-0: 0;
  --flex-gap-xs: 0.25rem;
  --flex-gap-sm: 0.5rem;
  --flex-gap-md: 1rem;
  --flex-gap-lg: 1.5rem;
  --flex-gap-xl: 2rem;
}
```

### Custom Styling Examples

**Inline Styles:**

```tsx
<Flex styles={{ backgroundColor: "#f5f5f5", padding: "2rem" }}>
  <div>Custom styled flex</div>
</Flex>
```

**CSS Classes:**

```tsx
<Flex className="custom-layout shadow-lg">
  <div>With custom classes</div>
</Flex>
```

**CSS Variables:**

```tsx
<Flex
  gap="md"
  styles={
    {
      "--flex-gap-md": "2rem",
    } as React.CSSProperties
  }
>
  <div>Custom gap size</div>
</Flex>
```

## Breakpoints

The component supports four responsive breakpoints:

| Breakpoint | Minimum Width  | Example Usage                 |
| ---------- | -------------- | ----------------------------- |
| `sm`       | 30rem (480px)  | `sm={{ direction: "row" }}`   |
| `md`       | 48rem (768px)  | `md={{ gap: "lg" }}`          |
| `lg`       | 62rem (992px)  | `lg={{ wrap: "wrap" }}`       |
| `xl`       | 80rem (1280px) | `xl={{ justify: "between" }}` |

### Responsive Design Patterns

**Mobile-First Approach:**

```tsx
<Flex
  direction="column" // Default: column on mobile
  sm={{ direction: "row" }} // Row on small+
  lg={{ gap: "xl" }} // Larger gap on large+
>
  {/* Content */}
</Flex>
```

**Desktop-First Approach:**

```tsx
<Flex
  direction="row" // Default: row on desktop
  lg={{ direction: "column" }} // Column on large screens only
>
  {/* Content */}
</Flex>
```

## Type Safety

### Semantic Element Enforcement

TypeScript prevents invalid element usage at compile-time:

```tsx
// ✅ Valid - div is a container element
<Flex as="div">...</Flex>

// ✅ Valid - section is semantic
<Flex as="section">...</Flex>

// ✅ Valid - nav is a list container
<Flex as="nav">...</Flex>

// ❌ TypeScript Error - span is not a container element
<Flex as="span">...</Flex>

// ❌ TypeScript Error - button is interactive
<Flex as="button">...</Flex>

// ✅ Valid - li is allowed for Flex.Item
<Flex as="ul">
  <Flex.Item as="li">List item</Flex.Item>
</Flex>

// ❌ TypeScript Error - li not allowed on main Flex
<Flex as="li">...</Flex>
```

### Type Exports

```tsx
import type {
  FlexProps,
  FlexItemProps,
  FlexSpacerProps,
  FlexContainerElement,
  FlexItemElement,
  FlexDirection,
  FlexWrap,
  FlexJustify,
  FlexAlign,
  FlexGap,
  FlexVariant,
  ResponsiveFlexProps,
} from "@fpkit/acss";
```

## Performance

### Utility Class Generation

The component generates utility class names instead of inline styles for better
performance:

**✅ Good (Utility Classes):**

```tsx
// Generates: "flex flex-row gap-md"
<Flex direction="row" gap="md">
```

**❌ Slower (Inline Styles):**

```tsx
// Less efficient
<div style={{ display: 'flex', flexDirection: 'row', gap: '1rem' }}>
```

**Benefits:**

- CSS caching by browser
- Smaller React updates
- Better performance in lists
- Easier to override with CSS

### Responsive Performance

Responsive props use CSS media queries (not JavaScript):

```tsx
// Generates: "flex flex-col md:flex-row"
// Media query handled by CSS, not JS
<Flex direction="column" md={{ direction: "row" }}>
```

## Best Practices

### 1. Choose the Right Semantic Element

```tsx
// ✅ Good - semantic header
<Flex as="header" justify="between">
  <Logo />
  <Nav />
</Flex>

// ✅ Good - semantic navigation
<Flex as="nav" gap="md">
  <a href="/">Home</a>
  <a href="/about">About</a>
</Flex>

// ❌ Bad - using div for everything
<Flex as="div">...</Flex>
```

### 2. Use Preset Variants for Common Patterns

```tsx
// ✅ Good - use preset
<Flex variant="center">
  <Logo />
</Flex>

// ❌ Unnecessary - manual props
<Flex justify="center" align="center" direction="column">
  <Logo />
</Flex>
```

### 3. Leverage Responsive Props

```tsx
// ✅ Good - mobile-first responsive
<Flex
  direction="column"
  gap="sm"
  md={{ direction: "row", gap: "lg" }}
>
```

### 4. Use Flex.Item for Fine Control

```tsx
// ✅ Good - explicit flex behavior
<Flex.Item flex="1">Grows to fill space</Flex.Item>
<Flex.Item flex="none">Fixed size</Flex.Item>

// ❌ Less clear - manual styles
<div style={{ flex: 1 }}>...</div>
```

### 5. Use Flex.Spacer to Push Items

```tsx
// ✅ Good - semantic spacer
<Flex>
  <div>Left</div>
  <Flex.Spacer />
  <div>Right</div>
</Flex>

// ❌ Less semantic
<Flex justify="between">
  <div>Left</div>
  <div>Right</div>
</Flex>
```

### 6. Maintain Semantic List Structures

```tsx
// ✅ Good - proper list semantics
<Flex as="ul">
  <Flex.Item as="li">Item 1</Flex.Item>
  <Flex.Item as="li">Item 2</Flex.Item>
</Flex>

// ❌ Bad - invalid HTML (ul > div)
<Flex as="ul">
  <div>Item 1</div>
  <div>Item 2</div>
</Flex>
```

## Technical Implementation

### Architecture

- **Hybrid Approach** - CSS utilities + React component API
- **Class Generation** - Props convert to utility class names
- **Responsive Design** - Breakpoint-prefixed classes for media queries
- **Type Safety** - Literal union types restrict valid options
- **Compound Pattern** - Sub-components attached as properties

### Class Name Generation

```tsx
// From flex.tsx
const generateFlexClasses = (
  props: ResponsiveFlexProps,
  prefix = ""
): string[] => {
  const classes: string[] = [];

  if (props.direction) {
    const dirMap = {
      row: "flex-row",
      "row-reverse": "flex-row-reverse",
      column: "flex-col",
      "column-reverse": "flex-col-reverse",
    };
    classes.push(`${prefix}${dirMap[props.direction]}`);
  }

  // ... more mappings

  return classes;
};
```

### Responsive Class Generation

```tsx
// Responsive breakpoint classes
if (sm) classes.push(...generateFlexClasses(sm, "sm:"));
if (md) classes.push(...generateFlexClasses(md, "md:"));
if (lg) classes.push(...generateFlexClasses(lg, "lg:"));
if (xl) classes.push(...generateFlexClasses(xl, "xl:"));
```

### Testing

The component has 100% test coverage with 62 tests:

- ✅ Basic rendering and props
- ✅ Direction, wrap, gap, justify, align props
- ✅ Preset variants
- ✅ Responsive breakpoint props
- ✅ Compound components (Flex.Item, Flex.Spacer)
- ✅ Flex.Item sizing and alignment
- ✅ Polymorphic rendering (`as` prop)
- ✅ Custom className and styles
- ✅ Display names

Run tests:

```bash
cd packages/fpkit && npm test flex.test.tsx
```

## Comparison: Flex Component vs Direct Utility Classes

### Using Flex Component (Recommended)

```tsx
<Flex direction="row" gap="md" md={{ direction: "column" }}>
  <Flex.Item flex="1">Content</Flex.Item>
</Flex>
```

**Benefits:**

- ✅ TypeScript autocomplete and type safety
- ✅ Semantic element enforcement
- ✅ Cleaner JSX
- ✅ Easy responsive props
- ✅ Better refactoring

### Using Direct Utility Classes

```tsx
<div className="flex flex-row gap-md md:flex-col">
  <div className="flex-1">Content</div>
</div>
```

**Benefits:**

- ✅ Slightly less JavaScript
- ✅ Direct CSS control
- ✅ Familiar to Tailwind users

**Both approaches are valid** - the Flex component provides a React-friendly API
on top of the same utility classes.

## Browser Support

- ✅ Modern browsers (Chrome, Firefox, Safari, Edge)
- ✅ Requires CSS flexbox support
- ✅ Requires React 18+
- ✅ TypeScript 5.0+ recommended for full type safety
- ✅ CSS custom properties support

## API Reference

### Exported Components

- `Flex` - Main flexbox container component
- `Flex.Item` - Individual flex item with sizing controls
- `Flex.Spacer` - Auto-expanding spacer element

### Exported Types

- `FlexProps` - Main Flex component props
- `FlexItemProps` - Flex.Item component props
- `FlexSpacerProps` - Flex.Spacer component props
- `FlexContainerElement` - Valid container elements
- `FlexItemElement` - Valid item elements (includes list items)
- `FlexDirection` - Direction values
- `FlexWrap` - Wrap values
- `FlexJustify` - Justify content values
- `FlexAlign` - Align items values
- `FlexAlignContent` - Align content values
- `FlexAlignSelf` - Align self values
- `FlexGap` - Gap size values
- `FlexVariant` - Preset variant values
- `ResponsiveFlexProps` - Props for responsive breakpoints

## Migration Guide

### From Previous Versions

If migrating from direct utility classes or other flex systems:

**Before:**

```tsx
<div className="flex flex-row gap-md">
  <div className="flex-1">Content</div>
</div>
```

**After:**

```tsx
<Flex direction="row" gap="md">
  <Flex.Item flex="1">Content</Flex.Item>
</Flex>
```

### Type Safety Updates (v3.0.0+)

Version 3.0.0 introduces semantic element restrictions:

```tsx
// ✅ Valid in v3.0.0+
<Flex as="section">...</Flex>

// ❌ TypeScript error in v3.0.0+ (was allowed before)
<Flex as="span">...</Flex>
```

Update code to use valid container elements only.

## Resources

- [Storybook Documentation](http://localhost:6006/?path=/docs/fp-react-components-flex--docs)
- [GitHub Repository](https://github.com/yourusername/acss)
- [CSS Flexbox Guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
- [MDN Flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout)

## Support

For issues, questions, or contributions:

- Open an issue on [GitHub](https://github.com/yourusername/acss/issues)
- Check existing [Storybook stories](http://localhost:6006) for examples
- Review the comprehensive test suite for usage patterns

---

**Version:** v3.0.0+ **Last Updated:** December 2025 **Test Coverage:** 100% (62
tests) **Maintained by:** fpkit Team
