import React, { useState, type FC, type HTMLProps, type ReactElement, type ReactNode } from 'react';
import { HiChevronDown, HiChevronRight } from 'react-icons/hi2';
import { PiCaretDoubleLeftThin, PiCaretDoubleRightThin } from 'react-icons/pi';
import { flexRender, useControllable, type FlexRenderable } from '@wener/reaction';
import { clsx } from 'clsx';
import { HeaderContentFooterLayout, LeftContentRightLayout, OverlayScrollbar } from '../../components';
import { Tooltip } from '../../floating';
import { NavLink } from '../links';
import type { BaseNavLink } from './BaseNavLink';
interface ExpandableSideMenuTitle {
type: 'title';
label: string;
icon?: ReactElement;
iconActive?: ReactElement;
}
interface ExpandableSideMenuItem {
type?: 'item';
label?: string;
icon?: FlexRenderable;
iconActive?: FlexRenderable;
href: string;
end?: boolean;
}
interface ExpandableSideMenuGroup {
type?: 'group';
label: string;
icon?: ReactElement;
iconActive?: ReactElement;
end?: boolean;
children: ExpandableSideMenuItem[];
}
export type ExpandableSideMenuItemProps = ExpandableSideMenuItem | ExpandableSideMenuGroup | ExpandableSideMenuTitle;
export interface ExpandableSideMenuLayoutProps extends Omit, 'title'> {
header?: FlexRenderable<{ expanded: boolean }>;
title?: ReactNode;
icon?: ReactElement;
children?: ReactNode;
items: Array;
expanded?: boolean;
initialExpanded?: boolean;
onExpandedChange?: (v: boolean) => void;
NavLink?: BaseNavLink;
}
const SideMenuItem: FC<{ item: ExpandableSideMenuItemProps; expanded?: boolean; NavLink?: BaseNavLink }> = ({
item,
expanded,
}) => {
const [collapse, setCollapse] = useState(true);
if ('children' in item) {
const { label, icon, children } = item;
if (!expanded) {
return (
{icon}
);
}
return (
<>
{
setCollapse(!collapse);
}}
>
{icon}
{label}
{collapse ? : }
{!collapse &&
children.map((item, i) => {
return (
,
iconActive: undefined,
}}
key={`${label}/${i}`}
/>
);
})}
>
);
// fixme collapse not works
// return (
//
//
// {icon}
// {label}
//
//
// {children.map((item, i) => {
// return -
// {item.label}
//
// })}
//
//
}
if (item.type === 'title') {
if (!expanded) {
return (
{item.label}
);
}
return (
{item.label}
);
}
const { href, icon, end, iconActive, label } = item;
// data-tooltip 由于 overflow 实际无法显示
return (
clsx(expanded ? '' : 'justify-center p-2', isActive ? 'active' : 'inactive')}
>
{({ isActive: active }) => {
let ico = flexRender(
active ? iconActive || icon : icon,
{
active,
className: 'w-6 h-6',
},
true,
);
return (
<>
{ico}
{expanded && label}
>
);
}}
);
};
export const ExpandableMenu: FC = ({
expanded,
title,
header: _header,
icon,
items,
onExpandedChange,
children,
}) => {
return (
{icon}
{expanded && title && {title}}
{flexRender(_header, { expanded })}
}
footer={
}
>
{items.map((item, i) => {
return ;
})}
{children}
);
};
export const ExpandableSideMenuLayout: FC = ({
children,
header: _header,
title,
icon,
items,
expanded: _expanded,
onExpandedChange: _onExpandedChange,
initialExpanded: _initialExpanded,
...props
}) => {
const [expanded, setExpanded] = useControllable(
_expanded,
_onExpandedChange,
() => _initialExpanded ?? (typeof window === 'undefined' ? true : window.matchMedia('(min-width: 768px)').matches),
);
return (
}
{...props}
>
{children}
);
};
ExpandableSideMenuLayout.displayName = 'ExpandableSideMenuLayout';