import React from 'react' import {View, Pressable} from 'react-native' import * as DropdownMenu from '@radix-ui/react-dropdown-menu' import * as Dialog from '#/components/Dialog' import {useInteractionState} from '#/components/hooks/useInteractionState' import {atoms as a, useTheme, flatten, web} from '#/alf' import {Text} from '#/components/Typography' import { ContextType, TriggerProps, ItemProps, GroupProps, ItemTextProps, ItemIconProps, } from '#/components/Menu/types' import {Context} from '#/components/Menu/context' export function useMenuControl(): Dialog.DialogControlProps { const id = React.useId() const [isOpen, setIsOpen] = React.useState(false) return React.useMemo( () => ({ id, ref: {current: null}, isOpen, open() { setIsOpen(true) }, close() { setIsOpen(false) }, }), [id, isOpen, setIsOpen], ) } export function useMemoControlContext() { return React.useContext(Context) } export function Root({ children, control, }: React.PropsWithChildren<{ control?: Dialog.DialogOuterProps['control'] }>) { const defaultControl = useMenuControl() const context = React.useMemo( () => ({ control: control || defaultControl, }), [control, defaultControl], ) const onOpenChange = React.useCallback( (open: boolean) => { if (context.control.isOpen && !open) { context.control.close() } else if (!context.control.isOpen && open) { context.control.open() } }, [context.control], ) return ( {children} ) } export function Trigger({children, label, style}: TriggerProps) { const {control} = React.useContext(Context) const { state: hovered, onIn: onMouseEnter, onOut: onMouseLeave, } = useInteractionState() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() return ( { control.open() }} {...web({ onMouseEnter, onMouseLeave, })}> {children({ isNative: false, control, state: { hovered, focused, pressed: false, }, props: {}, })} ) } export function Outer({children}: React.PropsWithChildren<{}>) { const t = useTheme() return ( {children} ) } export function Item({children, label, onPress, ...rest}: ItemProps) { const t = useTheme() const {control} = React.useContext(Context) const { state: hovered, onIn: onMouseEnter, onOut: onMouseLeave, } = useInteractionState() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() return ( { onPress(e) /** * Ported forward from Radix * @see https://www.radix-ui.com/primitives/docs/components/dropdown-menu#item */ if (!e.defaultPrevented) { control.close() } }} onFocus={onFocus} onBlur={onBlur} // need `flatten` here for Radix compat style={flatten([ a.flex_row, a.align_center, a.gap_sm, a.py_sm, a.rounded_xs, {minHeight: 32, paddingHorizontal: 10}, web({outline: 0}), (hovered || focused) && [ web({outline: '0 !important'}), t.name === 'light' ? t.atoms.bg_contrast_25 : t.atoms.bg_contrast_50, ], ])} {...web({ onMouseEnter, onMouseLeave, })}> {children} ) } export function ItemText({children, style}: ItemTextProps) { const t = useTheme() return ( {children} ) } export function ItemIcon({icon: Comp, position = 'left'}: ItemIconProps) { const t = useTheme() return ( ) } export function Group({children}: GroupProps) { return children } export function Divider() { const t = useTheme() return ( ) }