'use client' import * as React from 'react' import { ContextMenu as BaseContextMenu } from '@base-ui/react/context-menu' import { useReducedMotion } from '../../hooks/use-reduced-motion' import { cn } from '../../internal/utils' import { type FloatingContentProps, splitFloatingProps } from '../../internal/floating' import { navigationLinkVariants } from '../navigation/navigation-link-variants' type ContextMenuSize = 'sm' | 'md' | 'lg' interface ContextMenuContextValue { size: ContextMenuSize reducedMotion: boolean } const ContextMenuContext = React.createContext(null) function useContextMenuContext() { const ctx = React.useContext(ContextMenuContext) if (!ctx) { throw new Error('ContextMenu sub-components must be rendered inside ') } return ctx } type BaseRootProps = React.ComponentProps interface ContextMenuProps extends BaseRootProps { /** * Scales the popup radius, item padding, and icon size. * @default 'md' */ size?: ContextMenuSize } function ContextMenu({ size = 'md', children, ...rest }: ContextMenuProps) { const reducedMotion = useReducedMotion() const ctx = React.useMemo(() => ({ size, reducedMotion }), [size, reducedMotion]) return ( {children} ) } type ContextMenuTriggerProps = React.ComponentProps function ContextMenuTrigger({ className, ...props }: ContextMenuTriggerProps) { return } const POPUP_SIZE: Record = { sm: 'min-w-40 rounded-md', md: 'min-w-48 rounded-lg', lg: 'min-w-56 rounded-xl', } const ICON_SIZE: Record = { sm: 'size-4', md: 'size-4.5', lg: 'size-5', } function popupClassName(size: ContextMenuSize, className?: string) { return cn( 'max-h-(--available-height) bg-background border-border-overlay flex flex-col border shadow-2xl outline-none', POPUP_SIZE[size], 'origin-(--transform-origin)', 'motion-safe:transition-[opacity,scale] motion-safe:duration-200 motion-safe:ease-[cubic-bezier(0.175,0.885,0.32,1.5)]', 'data-starting-style:motion-safe:scale-90 data-starting-style:motion-safe:opacity-0', 'data-ending-style:motion-safe:scale-95 data-ending-style:motion-safe:opacity-0 data-ending-style:motion-safe:duration-100 data-ending-style:motion-safe:ease-out', className, ) } type ContextMenuFloatingProps = FloatingContentProps< React.ComponentProps, React.ComponentProps > type ContextMenuContentProps = Omit, 'className'> & ContextMenuFloatingProps & { /** Extra classes on the popup. */ className?: string } function ContextMenuContent({ className, children, ...props }: ContextMenuContentProps) { const { size } = useContextMenuContext() const { positioner, portal, popup } = splitFloatingProps(props) return (
{children}
) } const ITEM_BASE = 'w-full outline-hidden' const ITEM_TEXT: Record = { sm: 'gap-1', md: 'gap-1.5', lg: 'gap-1.5', } type ContextMenuItemProps = React.ComponentProps function ContextMenuItem({ className, ...props }: ContextMenuItemProps) { const { size } = useContextMenuContext() return ( ) } type ContextMenuLinkItemProps = React.ComponentProps function ContextMenuLinkItem({ className, ...props }: ContextMenuLinkItemProps) { const { size } = useContextMenuContext() return ( ) } type ContextMenuGroupProps = React.ComponentProps function ContextMenuGroup(props: ContextMenuGroupProps) { return } type ContextMenuGroupLabelProps = React.ComponentProps const GROUP_LABEL_SIZE: Record = { sm: 'px-2.5 pt-1.5 pb-1 text-xs', md: 'px-3 pt-2 pb-1.25 text-sm', lg: 'px-3.5 pt-2.5 pb-1.5 text-base', } function ContextMenuGroupLabel({ className, ...props }: ContextMenuGroupLabelProps) { const { size } = useContextMenuContext() return ( ) } type ContextMenuSeparatorProps = React.ComponentProps function ContextMenuSeparator({ className, ...props }: ContextMenuSeparatorProps) { return ( ) } type ContextMenuRadioGroupProps = React.ComponentProps function ContextMenuRadioGroup(props: ContextMenuRadioGroupProps) { return } type ContextMenuRadioItemProps = React.ComponentProps function ContextMenuRadioItem({ className, children, ...props }: ContextMenuRadioItemProps) { const { size, reducedMotion } = useContextMenuContext() return ( {children} ) } type ContextMenuCheckboxItemProps = React.ComponentProps function ContextMenuCheckboxItem({ className, children, ...props }: ContextMenuCheckboxItemProps) { const { size, reducedMotion } = useContextMenuContext() return ( {children} ) } type ContextMenuSubProps = React.ComponentProps function ContextMenuSub(props: ContextMenuSubProps) { return } type ContextMenuSubTriggerProps = React.ComponentProps function ContextMenuSubTrigger({ className, children, ...props }: ContextMenuSubTriggerProps) { const { size } = useContextMenuContext() return ( {children} ) } type ContextMenuSubContentProps = Omit, 'className'> & ContextMenuFloatingProps & { /** Extra classes on the submenu popup. */ className?: string } function ContextMenuSubContent({ className, children, ...props }: ContextMenuSubContentProps) { const { size } = useContextMenuContext() const { positioner, portal, popup } = splitFloatingProps(props) return (
{children}
) } interface IconProps extends React.SVGProps {} function CheckIcon({ className, ...props }: IconProps) { return ( ) } function ChevronEndIcon(props: IconProps) { return ( ) } export { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuGroup, ContextMenuGroupLabel, ContextMenuItem, ContextMenuLinkItem, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuCheckboxItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, } export type { ContextMenuProps, ContextMenuTriggerProps, ContextMenuContentProps, ContextMenuGroupProps, ContextMenuGroupLabelProps, ContextMenuItemProps, ContextMenuLinkItemProps, ContextMenuRadioGroupProps, ContextMenuRadioItemProps, ContextMenuCheckboxItemProps, ContextMenuSeparatorProps, ContextMenuSubProps, ContextMenuSubTriggerProps, ContextMenuSubContentProps, }