dify/web/__mocks__/base-ui-dropdown-menu.tsx
Coding On Star 9331024d91
refactor(web): portal to follow elem migration (#35892)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
2026-05-07 13:02:11 +00:00

173 lines
5.2 KiB
TypeScript

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<HTMLElement> & {
children?: ReactNode
nativeButton?: boolean
render?: React.ReactElement
}
type DropdownMenuContentProps = React.HTMLAttributes<HTMLDivElement> & {
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 (
<DropdownMenuContext.Provider value={{ open: resolvedOpen, onOpenChange: handleOpenChange }}>
<div data-testid="dropdown-menu" data-open={String(resolvedOpen)}>
{children}
</div>
</DropdownMenuContext.Provider>
)
}
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<HTMLElement>) => {
onClick?.(event)
if (!event.defaultPrevented)
onOpenChange(!open)
}
if (React.isValidElement(node)) {
const triggerElement = node as React.ReactElement<Record<string, unknown>>
const childProps = (triggerElement.props ?? {}) as React.HTMLAttributes<HTMLElement> & { 'data-testid'?: string }
const triggerProps = props as React.HTMLAttributes<HTMLElement> & { '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<HTMLElement>) => {
childProps.onClick?.(event)
handleClick(event)
},
}, render ? (children ?? childProps.children) : childProps.children)
}
return (
<div data-testid="dropdown-menu-trigger" role="button" tabIndex={0} onClick={handleClick} {...props}>
{node}
</div>
)
}
export const DropdownMenuContent = ({
children,
className,
popupClassName,
placement,
sideOffset,
alignOffset,
...props
}: DropdownMenuContentProps) => {
const { open } = React.useContext(DropdownMenuContext)
if (!open)
return null
return (
<div
data-testid="dropdown-menu-content"
data-placement={placement}
data-side-offset={sideOffset}
data-align-offset={alignOffset}
className={className || popupClassName}
{...props}
>
{children}
</div>
)
}
export const DropdownMenuItem = ({
children,
onClick,
...props
}: React.HTMLAttributes<HTMLDivElement> & { children?: ReactNode }) => (
<div role="menuitem" onClick={onClick} {...props}>
{children}
</div>
)
export const DropdownMenuRadioGroup = ({
children,
onValueChange,
...props
}: React.HTMLAttributes<HTMLDivElement> & { children?: ReactNode, value?: unknown, onValueChange?: (value: unknown) => void }) => (
<div
role="radiogroup"
{...props}
data-on-value-change={onValueChange ? 'true' : undefined}
>
{React.Children.map(children, (child) => {
if (!React.isValidElement(child))
return child
return React.cloneElement(child as React.ReactElement<{ __onValueChange?: (value: unknown) => void }>, { __onValueChange: onValueChange })
})}
</div>
)
export const DropdownMenuRadioItem = ({
children,
value,
onClick,
__onValueChange,
...props
}: React.HTMLAttributes<HTMLDivElement> & { children?: ReactNode, value?: unknown, __onValueChange?: (value: unknown) => void }) => (
<div
role="radio"
onClick={(event) => {
onClick?.(event)
__onValueChange?.(value)
}}
{...props}
>
{children}
</div>
)
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<HTMLDivElement>) => <div role="separator" {...props} />
export const DropdownMenuSub = ({ children }: { children?: ReactNode }) => <>{children}</>
export const DropdownMenuSubTrigger = DropdownMenuItem
export const DropdownMenuSubContent = ({ children }: { children?: ReactNode }) => <>{children}</>