npm package: @mukhindev/mui-folding-menu
Description: React folding menu MUI-based
Author: Sergey Mukhin
Latest version: 1.0.2

# @mukhindev/mui-folding-menu

Складываемое меню для React c использованием MUI

## Пример использования

```tsx
import { useEffect, useMemo, useRef } from "react";
import FoldingMenu, {
  FoldingMenuItem,
  FoldingMenuProvider,
  FoldingMenuRef,
} from "@mukhindev/mui-folding-menu";
import { Button, Container } from "@mui/material";
import {
  CategoryOutlined,
  FavoriteOutlined,
  PersonOutlined,
} from "@mui/icons-material";

export default function App() {
  const ref = useRef<FoldingMenuRef>(null);

  // Управление состоянием меню снаружи
  useEffect(() => {
    // Окрыть полный путь до элемента (раскрыв все children по пути)
    ref.current?.openPathToMenuItem("2.1");
    // Пометь элемент как активный
    ref.current?.setActiveMenuItemId("2.1");

    setTimeout(() => {
      ref.current?.setActiveMenuItemId("4");
    }, 7500);
  }, [ref]);

  // Составляем меню
  const menu = useMemo<FoldingMenuItem[][]>(() => {
    return [
      [
        // Ссылка (id будем использовать как ссылку)
        {
          id: "https://mukhin.dev",
          icon: <FavoriteOutlined />,
          label: "Первый пункт ссылка",
        },
        // Папка
        {
          id: "2",
          label: "Папка",
          children: [
            // По onClick в extendButton понимаем, что не надо превращать в ссылку
            {
              id: "2.1",
              icon: <PersonOutlined />,
              label: "Сын",
              onClick: () => console.log("Я сын"),
            },
            {
              id: "2.2",
              icon: <PersonOutlined />,
              label: "Дочь",
              onClick: () => console.log("Я дочь"),
            },
          ],
        },
        // Асинхронно получаем папку (также можно получать элемент и даже элементы)
        {
          id: "3",
          label: "Загрузка папки...",
          loader: () =>
            new Promise((resolve) => {
              setTimeout(() => {
                resolve({
                  id: "3...",
                  label: "Папка получена асинхронно",
                  children: [
                    {
                      id: "3.1",
                      icon: <PersonOutlined />,
                      label: "Вложено в папку 1",
                      onClick: () => console.log("3.1"),
                    },
                    {
                      id: "3.2",
                      icon: <PersonOutlined />,
                      label: "Вложено в папку 2",
                      onClick: () => console.log("3.2"),
                    },
                  ],
                });
              }, 5000);
            }),
        },
      ],
      // Тут сам создастся разделитель
      [
        // Проверяем, что длинный текст подрежается с помощью ...
        {
          id: "4",
          icon: <CategoryOutlined />,
          color: "success",
          label:
            "Пункт с каким-то ну нереально длинным названием в меню зачем-то",
          onClick: () => console.log("Я id: 3, по мне кликнули"),
        },
      ],
      // Тут сам создастся разделитель
      [
        // Выводим полностью произвольный пункт (не будет даже <li> обёртки)
        {
          id: "5",
          render: ({ item }) => <div>Что-то произвольное (id: {item.id})</div>,
        },
      ],
    ];
  }, []);

  return (
    <Container
      sx={{
        display: "flex",
        flexDirection: "column",
        p: 4,
        gap: 3,
        maxWidth: 400,
      }}
    >
      {/** Провайдер нужен для старых проектов, где не получится стабилизировать состояние меню */}
      <FoldingMenuProvider>
        <FoldingMenu
          ref={ref}
          menu={menu}
          extendButton={(item) =>
            // Если элемент не содержит children и onClick ...
            !("children" in item || "onClick" in item) && (
              // То расширять кнопку до ссылки
              <Button component="a" href={item.id} target="_blank" />
            )
          }
        />
      </FoldingMenuProvider>
    </Container>
  );
}

```

## TODO

- [ ] Поддержка `openPathToMenuItem` для асинхронных элементов меню
- [ ] Сделать возможным работу без FoldingMenuProvider (нельзя его просто убрать просто так, он нужен для старых проектов, где не получится стабилизировать состояние меню)