import type { Dispatch, SetStateAction } from 'react'; import * as RadixContextMenu from '@radix-ui/react-context-menu'; import clsx from 'clsx'; import { AnimatePresence, motion } from 'motion/react'; import { createContext, Fragment, type ReactNode, useContext, useMemo, useState } from 'react'; import styles from './context-menu.module.css'; import { animationVariants } from '/@/shared/components/animations/animation-variants'; import { AppIcon, Icon } from '/@/shared/components/icon/icon'; import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; interface ContextMenuContext { open: boolean; setOpen: Dispatch>; } export const ContextMenuContext = createContext(null); interface ContentProps { bottomStickyContent?: ReactNode; children: ReactNode; onCloseAutoFocus?: (event: FocusEvent) => void; onEscapeKeyDown?: (event: KeyboardEvent) => void; onFocusOutside?: (event: FocusEvent) => void; onPointerDownOutside?: (event: PointerEvent) => void; stickyContent?: ReactNode; } interface ContextMenuProps { children: ReactNode; } interface DividerProps {} interface ItemProps { children: ReactNode; className?: string; disabled?: boolean; isSelected?: boolean; leftIcon?: keyof typeof AppIcon; onSelect?: (event: Event) => void; rightIcon?: keyof typeof AppIcon; } interface LabelProps extends React.ComponentPropsWithoutRef<'div'> { children: ReactNode; } interface SubmenuContext { disabled?: boolean; isCloseDisabled?: boolean; open: boolean; setOpen: Dispatch>; } interface TargetProps { children: ReactNode; } export function ContextMenu(props: ContextMenuProps) { const { children } = props; const [open, setOpen] = useState(false); const context = useMemo(() => ({ open, setOpen }), [open]); return ( {children} ); } function Content(props: ContentProps) { const { bottomStickyContent, children, stickyContent } = props; const { open } = useContext(ContextMenuContext) as ContextMenuContext; return ( {open && ( {stickyContent} {children} {bottomStickyContent} )} ); } function Divider(props: DividerProps) { return ; } function Item(props: ItemProps) { const { children, className, disabled, isSelected, leftIcon, onSelect, rightIcon } = props; return ( {leftIcon && } {children} {rightIcon && } ); } function Label(props: LabelProps) { const { children, className, ...htmlProps } = props; return ( {children} ); } function Target(props: TargetProps) { const { children } = props; return ( {children} ); } const SubmenuContext = createContext(null); interface SubmenuContentProps { children: ReactNode; stickyContent?: ReactNode; } interface SubmenuProps { children: ReactNode; disabled?: boolean; isCloseDisabled?: boolean; open?: boolean; } interface SubmenuTargetProps { children: ReactNode; } function Submenu(props: SubmenuProps) { const { children, disabled, isCloseDisabled, open: isManuallyOpen } = props; const [open, setOpen] = useState(isManuallyOpen ?? false); const context = useMemo( () => ({ disabled, isCloseDisabled, open, setOpen }), [disabled, isCloseDisabled, open], ); return ( {children} ); } function SubmenuContent(props: SubmenuContentProps) { const { children, stickyContent } = props; const { isCloseDisabled, open, setOpen } = useContext(SubmenuContext) as SubmenuContext; return ( {open && ( setOpen(true)} onMouseLeave={() => { if (!isCloseDisabled) { setOpen(false); } }} > {stickyContent} {children} )} ); } function SubmenuTarget(props: SubmenuTargetProps) { const { children } = props; const { disabled, setOpen } = useContext(SubmenuContext) as SubmenuContext; return ( setOpen(true)} onMouseLeave={() => setOpen(false)} > {children} ); } ContextMenu.Target = Target; ContextMenu.Content = Content; ContextMenu.Item = Item; ContextMenu.Label = Label; ContextMenu.Group = RadixContextMenu.Group; ContextMenu.Submenu = Submenu; ContextMenu.SubmenuTarget = SubmenuTarget; ContextMenu.SubmenuContent = SubmenuContent; ContextMenu.Divider = Divider; ContextMenu.Arrow = RadixContextMenu.Arrow;