# Drawer Layer

A global drawer management system that allows you to open drawers from anywhere in your application without mounting multiple instances.

## Features

- ✅ Stack-based system - Drawers can open other drawers
- ✅ Reactive config updates - Drawer config stays in sync with component state
- ✅ Two usage patterns - Simple API and Composition Components
- ✅ Smooth animations - Built-in open/close transitions
- ✅ Flexible - Use simple props or build custom layouts
- ✅ Uses design-system components - All content uses Drawer composition components from design-system

## File Structure

```
src/components/layers/Drawers/
├── constants.ts   # Drawer constants (z-index, border radius)
├── hooks.ts       # useDrawerLayer, useDrawerLayerItem hooks
├── utils.ts       # Type guards and helper functions
├── types.ts       # TypeScript type definitions
├── index.tsx      # DrawerLayerProvider and Drawer exports
├── stories.tsx    # Storybook stories
└── README.md      # This file
```

## Setup

Wrap your application with the `DrawerLayerProvider`:

```tsx
import { DrawerLayerProvider } from '@material-hu/layers/Drawers';

function App() {
  return (
    <DrawerLayerProvider>
      <YourApp />
    </DrawerLayerProvider>
  );
}
```

## Usage

**Props:** Use `wrapperProps` for the MUI Drawer wrapper (e.g. `PaperProps`, `SlideProps`, `anchor`). Content config (title, children, or content) stays at top level.

### 1. Simple API

Use the simple API for common drawer patterns. This uses the design-system Drawer component internally.

```tsx
import { useDrawerLayer } from '@material-hu/layers/Drawers';

function MyComponent() {
  const { openDrawer, closeDrawer } = useDrawerLayer();

  const handleEdit = () => {
    openDrawer({
      title: 'Edit Item',
      size: 'medium',
      children: <EditForm />,
      primaryButtonProps: {
        children: 'Save',
        onClick: () => {
          saveChanges();
          closeDrawer();
        },
      },
      secondaryButtonProps: {
        children: 'Cancel',
        onClick: closeDrawer,
      },
      footer: <InfoMessage />,
      wrapperProps: {
        anchor: 'right',
        PaperProps: { sx: { maxWidth: 480 } },
      },
    });
  };

  return <button onClick={handleEdit}>Edit</button>;
}
```

#### Simple API Props

| Prop | Type | Description |
|------|------|-------------|
| `title` | `string` | Drawer title |
| `size` | `'medium' \| 'large'` | Drawer width |
| `children` | `ReactNode` | Main content |
| `onClose` | `(reason?: DrawerCloseReason) => void` | Close handler (handled by layer) |
| `onBack` | `() => void` | Back button handler |
| `hasBackButton` | `boolean` | Show back button |
| `primaryButtonProps` | `LoadingButtonProps` | Primary action button |
| `secondaryButtonProps` | `LoadingButtonProps` | Secondary action button |
| `footer` | `ReactNode` | Extra footer content |
| `primaryContent` | `ReactNode` | Left side content (double layout) |
| `secondaryContent` | `ReactNode` | Right side content (double layout) |
| `slotProps` | `object` | Styling props for internal sections |
| `wrapperProps` | `DrawerWrapperProps` | Optional. Props for the MUI Drawer wrapper (`PaperProps`, `SlideProps`, `anchor`, `sx`, etc.). |

### 2. useDrawerLayerItem Hook

Use this hook when you need a drawer with **reactive config updates**. The drawer configuration automatically stays in sync with your component's state.

```tsx
import { useDrawerLayerItem } from '@material-hu/layers/Drawers';

function MyComponent() {
  const [isLoading, setIsLoading] = useState(false);
  const [formData, setFormData] = useState({ name: '' });

  const drawer = useDrawerLayerItem('edit-profile', {
    title: 'Edit Profile',
    children: (
      <TextField
        value={formData.name}
        onChange={(e) => setFormData({ name: e.target.value })}
      />
    ),
    primaryButtonProps: {
      children: 'Save',
      loading: isLoading, // Auto-updates when isLoading changes
      onClick: async () => {
        setIsLoading(true);
        await saveProfile(formData);
        setIsLoading(false);
        drawer.closeDrawer();
      },
    },
    secondaryButtonProps: {
      children: 'Cancel',
      onClick: () => drawer.closeDrawer(),
    },
  });

  return <Button onClick={() => drawer.openDrawer()}>Edit Profile</Button>;
}
```

#### useDrawerLayerItem API

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | `string` | Unique identifier for the drawer |
| `config` | `OpenDrawerArgs` | Drawer configuration (same props as `openDrawer`) |

**Returns:**

| Method | Type | Description |
|--------|------|-------------|
| `openDrawer` | `(config?: OpenDrawerArgs) => void` | Opens the drawer (optionally with different config) |
| `closeDrawer` | `(immediate?: boolean) => void` | Closes the drawer |
| `updateDrawerConfig` | `(setter: (current) => new) => void` | Manually update drawer config |

#### When to use each hook

| Use case | Hook |
|----------|------|
| Simple one-off drawers | `useDrawerLayer` |
| Drawers with reactive state (loading, form data) | `useDrawerLayerItem` |
| Programmatic config updates | `useDrawerLayerItem` |

### 3. Composition Components API

Use composition components for complete flexibility in layout and content. Pass **`content`** (your composed JSX) and optionally **`wrapperProps`** for the MUI Drawer wrapper.

```tsx
import { useDrawerLayer, Drawer } from '@material-hu/layers/Drawers';

function MyComponent() {
  const { openDrawer, closeDrawer } = useDrawerLayer();

  const handleCustomDrawer = () => {
    openDrawer({
      content: (
        <>
          <Drawer.Header
            title="Custom Layout"
            onClose={closeDrawer}
            hasBackButton
            onBack={handleBack}
          />
          <Drawer.Body>
            <YourCustomForm />
          </Drawer.Body>
          <Drawer.Footer>
            <InfoPanel />
          </Drawer.Footer>
          <Drawer.Actions>
            <Button variant="tertiary" onClick={closeDrawer}>
              Cancel
            </Button>
            <Button variant="primary" onClick={handleSave}>
              Save
            </Button>
          </Drawer.Actions>
        </>
      ),
      wrapperProps: {
        anchor: 'right',
        PaperProps: { sx: { maxWidth: 480 } },
      },
    });
  };

  return <button onClick={handleCustomDrawer}>Open Drawer</button>;
}
```

#### Composition API props

| Prop | Type | Description |
|------|------|-------------|
| `content` | `ReactNode` | **Required.** Your composed layout (e.g. `Drawer.Header` + `Drawer.Body` + …). |
| `onClose` | `(reason?: DrawerCloseReason) => void` | Close handler (handled by layer). |
| `wrapperProps` | `DrawerWrapperProps` | Optional. Props for the MUI Drawer wrapper (`PaperProps`, `SlideProps`, `anchor`, `sx`, etc.). |

#### Available Composition Components

##### `Drawer.Header`

Header section with title, optional back button, and close button.

```tsx
<Drawer.Header
  title="Drawer Title"
  onClose={closeDrawer}
  onBack={handleBack}      // Optional
  hasBackButton={true}      // Optional
>
  {/* Optional custom content */}
</Drawer.Header>
```

##### `Drawer.Body`

Content section with automatic scroll support.

```tsx
<Drawer.Body
  slotProps={{              // Optional styling
    sx: { /* custom styles */ }
  }}
>
  <YourContent />
</Drawer.Body>
```

##### `Drawer.DoubleLayout`

Two-column layout for side-by-side content.

```tsx
<Drawer.DoubleLayout
  primaryContent={<LeftContent />}
  secondaryContent={<RightContent />}
  slotProps={{              // Optional styling
    layout?: StackProps;
    primaryContent?: StackProps;
    secondaryContent?: StackProps;
  }}
/>
```

##### `Drawer.Footer`

Extra footer section for additional content.

```tsx
<Drawer.Footer>
  <InfoPanel />
</Drawer.Footer>
```

##### `Drawer.Actions`

Action buttons section.

```tsx
<Drawer.Actions
  primaryButtonProps={{     // Optional - auto-renders button
    children: 'Save',
    onClick: handleSave
  }}
  secondaryButtonProps={{   // Optional - auto-renders button
    children: 'Cancel',
    onClick: closeDrawer
  }}
  size="medium"             // Optional - affects layout
>
  {/* Or provide custom children */}
  <Button>Custom Button</Button>
</Drawer.Actions>
```

## Examples

### Simple Form Drawer

```tsx
const handleEdit = () => {
  openDrawer({
    title: 'Edit Profile',
    size: 'medium',
    children: <ProfileForm />,
    primaryButtonProps: {
      children: 'Save',
      onClick: () => {
        saveProfile();
        closeDrawer();
      }
    },
    secondaryButtonProps: {
      children: 'Cancel',
      onClick: closeDrawer
    }
  });
};
```

### Drawer with Custom Layout

```tsx
const handleCustom = () => {
  openDrawer({
    content: (
      <>
        <Drawer.Header title="Custom" onClose={closeDrawer} hasBackButton />
        <Drawer.Body>
          <CustomComponent />
        </Drawer.Body>
        <Drawer.Actions>
          <Button onClick={closeDrawer}>Done</Button>
        </Drawer.Actions>
      </>
    )
  });
};
```

### Double Layout Drawer

```tsx
const handleDoubleLayout = () => {
  openDrawer({
    title: 'Compare',
    size: 'large',
    primaryContent: <LeftPanel />,
    secondaryContent: <RightPanel />,
    primaryButtonProps: {
      children: 'Apply',
      onClick: closeDrawer
    }
  });
};
```

## Behavior Notes

- **Multiple Instances**: Multiple instances of Drawers can be used and stacked on top of the other one.
- **Session Management**: Each drawer has a unique session ID to prevent conflicts during transitions.
- **Immediate Close**: Pass `true` to `closeDrawer(true)` to close without animation (useful before navigation).
- **Auto Cleanup**: Drawer state is automatically cleaned up after close animations complete.
- **Size**: Automatically adjusts to `large` when using double layout (`primaryContent` + `secondaryContent`).

## TypeScript Support

Full TypeScript support with exported types:

```tsx
import type {
  OpenDrawerArgs,
  SimpleDrawerProps,
  CompositionDrawerProps,
  DrawerWrapperProps,
  DrawerLayerContextValue,
  DrawerLevel,
  DrawerCloseReason,
} from '@material-hu/layers/Drawers/types';
```

- **`OpenDrawerArgs`** – Argument for `openDrawer` / `useDrawerLayerItem` config. Simple (design-system props) or Composition (`content`). Optional `wrapperProps` for the MUI Drawer wrapper.
- **`DrawerWrapperProps`** – MUI Drawer props (excluding `open`, `onClose`). Pass via `wrapperProps` in `OpenDrawerArgs`.
- **`DrawerCloseReason`** – `'backdropClick' | 'escapeKeyDown' | 'dismissButton' | 'cancelButton' | 'backButton' | 'submitButton'`.

### Available Exports

```tsx
// Main exports
import {
  DrawerLayerProvider,  // Context provider
  useDrawerLayer,       // Basic drawer hook
  useDrawerLayerItem,   // Reactive drawer hook
  Drawer,               // Composition components
} from '@material-hu/layers/Drawers';

// Composition components
Drawer.Header
Drawer.Body
Drawer.DoubleLayout
Drawer.Footer
Drawer.Actions
Drawer.Content
```
