import type { ReactNode } from 'react' import * as React from 'react' const DropdownMenuContext = React.createContext({ open: false, onOpenChange: (_open: boolean) => {}, }) type DropdownMenuProps = { children?: ReactNode open?: boolean onOpenChange?: (open: boolean) => void } type DropdownMenuTriggerProps = React.HTMLAttributes & { children?: ReactNode nativeButton?: boolean render?: React.ReactElement } type DropdownMenuContentProps = React.HTMLAttributes & { children?: ReactNode placement?: string sideOffset?: number alignOffset?: number popupClassName?: string } export const DropdownMenu = ({ children, open, onOpenChange, }: DropdownMenuProps) => { const [localOpen, setLocalOpen] = React.useState(false) const resolvedOpen = open ?? localOpen const handleOpenChange = React.useCallback((nextOpen: boolean) => { setLocalOpen(nextOpen) onOpenChange?.(nextOpen) }, [onOpenChange]) return (
{children}
) } export const DropdownMenuTrigger = ({ children, render, nativeButton: _nativeButton, onClick, ...props }: DropdownMenuTriggerProps) => { const { open, onOpenChange } = React.useContext(DropdownMenuContext) const node = render ?? children const isNativeButton = React.isValidElement(node) && node.type === 'button' const handleClick = (event: React.MouseEvent) => { onClick?.(event) if (!event.defaultPrevented) onOpenChange(!open) } if (React.isValidElement(node)) { const triggerElement = node as React.ReactElement> const childProps = (triggerElement.props ?? {}) as React.HTMLAttributes & { 'data-testid'?: string } const triggerProps = props as React.HTMLAttributes & { 'data-testid'?: string } const role = childProps.role ?? triggerProps.role ?? (!isNativeButton && (childProps['aria-label'] || triggerProps['aria-label']) ? 'button' : undefined) return React.cloneElement(triggerElement, { ...props, ...childProps, 'data-testid': childProps['data-testid'] ?? triggerProps['data-testid'] ?? 'dropdown-menu-trigger', role, 'tabIndex': childProps.tabIndex ?? triggerProps.tabIndex ?? (role === 'button' ? 0 : undefined), 'onClick': (event: React.MouseEvent) => { childProps.onClick?.(event) handleClick(event) }, }, render ? (children ?? childProps.children) : childProps.children) } return (
{node}
) } export const DropdownMenuContent = ({ children, className, popupClassName, placement, sideOffset, alignOffset, ...props }: DropdownMenuContentProps) => { const { open } = React.useContext(DropdownMenuContext) if (!open) return null return (
{children}
) } export const DropdownMenuItem = ({ children, onClick, ...props }: React.HTMLAttributes & { children?: ReactNode }) => (
{children}
) export const DropdownMenuRadioGroup = ({ children, onValueChange, ...props }: React.HTMLAttributes & { children?: ReactNode, value?: unknown, onValueChange?: (value: unknown) => void }) => (
{React.Children.map(children, (child) => { if (!React.isValidElement(child)) return child return React.cloneElement(child as React.ReactElement<{ __onValueChange?: (value: unknown) => void }>, { __onValueChange: onValueChange }) })}
) export const DropdownMenuRadioItem = ({ children, value, onClick, __onValueChange, ...props }: React.HTMLAttributes & { children?: ReactNode, value?: unknown, __onValueChange?: (value: unknown) => void }) => (
{ onClick?.(event) __onValueChange?.(value) }} {...props} > {children}
) export const DropdownMenuRadioItemIndicator = ({ children }: { children?: ReactNode }) => <>{children} export const DropdownMenuCheckboxItem = DropdownMenuItem export const DropdownMenuCheckboxItemIndicator = ({ children }: { children?: ReactNode }) => <>{children} export const DropdownMenuLabel = ({ children }: { children?: ReactNode }) => <>{children} export const DropdownMenuSeparator = (props: React.HTMLAttributes) =>
export const DropdownMenuSub = ({ children }: { children?: ReactNode }) => <>{children} export const DropdownMenuSubTrigger = DropdownMenuItem export const DropdownMenuSubContent = ({ children }: { children?: ReactNode }) => <>{children}