# Menu Layer

A global menu management system that allows you to open contextual menus from anywhere in your application, with support for nested submenus.

## Features

- ✅ Stack-based system – Menus can open nested submenus (infinite depth)
- ✅ Session-based – Prevents conflicts between multiple open/close calls
- ✅ Single API – `openMenu({ anchorEl, items, menuProps })` from any component
- ✅ Smooth animations – Built-in open/close transitions
- ✅ Uses design-system – Renders with design-system Menu, MenuItem, and ListItem components
- ✅ Optional `closeImmediate` – Close without animation when navigating or unmounting the anchor

## File Structure

```
src/components/layers/Menus/
├── index.tsx      # MenuLayerProvider and useMenuLayer
├── types.ts       # MenuItemSchema, OpenMenuArgs, MenuLayerContextValue
├── stories.tsx    # Storybook stories
└── README.md      # This file
```

## Setup

Wrap your application with the `MenuLayerProvider`:

```tsx
import { MenuLayerProvider } from '@material-hu/components/layers/Menus';

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

## Usage

Use the `useMenuLayer` hook to open a menu from any component. Pass the anchor element (usually the button that was clicked) and an array of items.

```tsx
import { useMenuLayer } from '@material-hu/components/layers/Menus';

function MyComponent() {
  const { openMenu, closeMenu } = useMenuLayer();

  const handleOpenOptions = (e: React.MouseEvent<HTMLButtonElement>) => {
    openMenu({
      anchorEl: e.currentTarget,
      items: [
        {
          id: 'edit',
          title: 'Edit',
          icon: IconPencil,
          onSelect: () => handleEdit(),
        },
        {
          id: 'delete',
          title: 'Delete',
          icon: IconTrash,
          onSelect: () => handleDelete(),
        },
      ],
      menuProps: {
        position: 'left',
        sx: { minWidth: '200px' },
      },
    });
  };

  return <IconButton onClick={handleOpenOptions}><IconDotsVertical /></IconButton>;
}
```

### openMenu args

| Prop       | Type                        | Description                                      |
| ---------- | --------------------------- | ------------------------------------------------ |
| `anchorEl` | `HTMLElement`               | **Required.** Element the menu is anchored to.   |
| `items`    | `MenuItemSchema[]`          | **Required.** Menu items (and optional submenus).|
| `menuProps`| `Omit<MenuProps, 'open'>`   | Optional. Props for the Menu wrapper (position, sx, etc.). |

### MenuItemSchema

| Prop            | Type            | Description                                                                 |
| --------------- | --------------- | --------------------------------------------------------------------------- |
| `id`            | `string`        | **Required.** Unique identifier for the item.                               |
| `title`         | `string`        | **Required.** Main text displayed for the item.                              |
| `description`   | `string`        | Optional. Secondary text below the title.                                    |
| `icon`          | `TablerIcon`    | Optional. Icon displayed to the left of the title.                            |
| `disabled`      | `boolean`      | Optional. If true, the item is not clickable.                                |
| `onSelect`      | `() => void`    | Optional. Callback when the item is clicked (no submenu).                    |
| `items`         | `MenuItemSchema[]` | Optional. Nested items; renders a submenu with a chevron.                |
| `closeImmediate`| `boolean`       | Optional. If true, closes the menu immediately without animation. Use when `onSelect` navigates or unmounts the anchor. |

### useMenuLayer return value

| Method      | Type                        | Description                                           |
| ----------- | --------------------------- | ----------------------------------------------------- |
| `openMenu`  | `(args: OpenMenuArgs) => void` | Opens a menu at the given anchor with the given items. |
| `closeMenu` | `(immediate?: boolean) => void` | Closes the current menu. Pass `true` to skip animation. |

## Examples

### Simple menu

```tsx
openMenu({
  anchorEl: e.currentTarget,
  items: [
    { id: 'copy', title: 'Copy', onSelect: () => copyToClipboard() },
    { id: 'paste', title: 'Paste', onSelect: () => paste() },
  ],
});
```

### Menu with icons and descriptions

```tsx
openMenu({
  anchorEl: e.currentTarget,
  items: [
    {
      id: 'edit',
      title: 'Edit',
      description: 'Edit this item',
      icon: IconPencil,
      onSelect: () => onEdit(),
    },
    {
      id: 'delete',
      title: 'Delete',
      description: 'Remove permanently',
      icon: IconTrash,
      onSelect: () => onDelete(),
    },
  ],
  menuProps: { position: 'left', sx: { minWidth: 240 } },
});
```

### Nested submenus

```tsx
openMenu({
  anchorEl: e.currentTarget,
  items: [
    { id: 'edit', title: 'Edit', onSelect: () => onEdit() },
    {
      id: 'more',
      title: 'More options',
      icon: IconDotsVertical,
      items: [
        { id: 'archive', title: 'Archive', onSelect: () => onArchive() },
        {
          id: 'move',
          title: 'Move to...',
          items: [
            { id: 'folder1', title: 'Folder 1', onSelect: () => moveTo('folder1') },
            { id: 'folder2', title: 'Folder 2', onSelect: () => moveTo('folder2') },
          ],
        },
      ],
    },
  ],
});
```

### Item that navigates (close immediately)

When an item triggers navigation or unmounts the anchor, use `closeImmediate: true` so the menu closes without animation and avoids stale state:

```tsx
{
  id: 'view-details',
  title: 'View details',
  closeImmediate: true,
  onSelect: () => navigate(`/items/${id}`),
}
```

### Disabled item

```tsx
{
  id: 'paste',
  title: 'Paste',
  icon: IconClipboard,
  disabled: true,
}
```

## Behavior Notes

- **Nested submenus**: Items with an `items` array open a submenu; a chevron is shown and clicking opens the nested list.
- **Session management**: Each menu session has a unique `sessionId`. Only the current session can close the menu, which avoids conflicts during transitions.
- **Close behavior**: Only the top-level menu (backdrop) handles close; closing runs the exit animation then clears the stack.
- **closeMenu(immediate)**: Call `closeMenu(true)` to close without animation (e.g. before navigation).

## TypeScript Support

Types are exported from the layer:

```tsx
import type {
  MenuItemSchema,
  OpenMenuArgs,
  MenuLevel,
  MenuLayerContextValue,
} from '@material-hu/components/layers/Menus/types';
```

### Available exports

```tsx
import {
  MenuLayerProvider,
  useMenuLayer,
} from '@material-hu/components/layers/Menus';

import type { MenuItemSchema, OpenMenuArgs } from '@material-hu/components/layers/Menus/types';
```
