import React, { useMemo, useRef, useState } from 'react'; import { Menu, MenuList, MenuItem, Box, useOutsideClick, MenuButton, MenuItemProps, PlacementWithLogical } from '@chakra-ui/react'; import MyDivider from '../MyDivider'; import type { IconNameType } from '../Icon/type'; import { useSystem } from '../../../hooks/useSystem'; import Avatar from '../Avatar'; export type MenuItemType = 'primary' | 'danger'; export type Props = { width?: number | string; offset?: [number, number]; Button: React.ReactNode; trigger?: 'hover' | 'click'; iconSize?: string; iconRadius?: string; menuItemStyles?: MenuItemProps; placement?: PlacementWithLogical; menuList: { label?: string; children: { isActive?: boolean; type?: MenuItemType; icon?: IconNameType | string; label: string | React.ReactNode; description?: string; onClick: () => any; }[]; }[]; }; const MyMenu = ({ width = 'auto', trigger = 'hover', offset, iconSize = '1rem', Button, menuList, iconRadius, placement = 'bottom-start', menuItemStyles = { borderRadius: 'sm', py: 2, px: 3, display: 'flex', alignItems: 'center', fontSize: 'sm' } }: Props) => { const typeMapStyle: Record = { primary: { _hover: { backgroundColor: 'primary.50', color: 'primary.600' }, _focus: { backgroundColor: 'primary.50', color: 'primary.600' }, _active: { backgroundColor: 'primary.50', color: 'primary.600' } }, danger: { color: 'red.600', _hover: { background: 'red.1' }, _focus: { background: 'red.1' }, _active: { background: 'red.1' } } }; const { isPc } = useSystem(); const ref = useRef(null); const closeTimer = useRef(); const [isOpen, setIsOpen] = useState(false); const formatTrigger = !isPc ? 'click' : trigger; useOutsideClick({ ref: ref, handler: () => { setIsOpen(false); } }); const computeOffset = useMemo<[number, number]>(() => { if (offset) return offset; if (typeof width === 'number') return [-width / 2, 5]; return [0, 5]; }, [offset]); return ( { if (formatTrigger === 'hover') { setIsOpen(true); } clearTimeout(closeTimer.current); }} onMouseLeave={() => { if (formatTrigger === 'hover') { closeTimer.current = setTimeout(() => { setIsOpen(false); }, 100); } }} > { e.stopPropagation(); if (formatTrigger === 'click') { setIsOpen(!isOpen); } }} > {Button} {menuList.map((item, i) => { return ( {item.label && {item.label}} {i !== 0 && } {item.children.map((child, index) => ( { e.stopPropagation(); setIsOpen(false); child.onClick && child.onClick(); }} color={child.isActive ? 'primary.700' : 'myGray.600'} whiteSpace={'pre-wrap'} _notLast={{ mb: 0.5 }} {...typeMapStyle[child.type || 'primary']} > {!!child.icon && ( )} {child.label} {child.description && ( {child.description} )} ))} ); })} ); }; export default React.memo(MyMenu);