'use client'; import { View } from 'react-native'; import { useMenuRootContext } from '../root/MenuRootContext'; import { useMenuPositionerContext } from '../positioner/MenuPositionerContext'; import { useMenuTransitionContext } from '../root/MenuTransitionContext'; import { useRenderElement } from '../../use-render/useRenderElement'; import { CompositeList } from '../../internals/composite/list/CompositeList'; import type { Align, PhysicalSide } from '../../utils/useAnchorPositioning'; import type { TransitionStatus } from '../../internals/useTransitionStatus'; import type { ZestUIComponentProps } from '../../types'; import { useStoreState } from '../../store/ReactStore'; /** * A container for the menu items. * Renders a ``. */ export function MenuPopup(componentProps: MenuPopup.Props) { const { render, className, style, ref, ...elementProps } = componentProps; const store = useMenuRootContext(); const { side, align } = useMenuPositionerContext(); const { transitionStatus } = useMenuTransitionContext() ?? { transitionStatus: undefined }; const open = useStoreState(store, 'open'); const triggerWidth = useStoreState(store, 'triggerWidth'); const triggerHeight = useStoreState(store, 'triggerHeight'); const state: MenuPopupState = { open, transitionStatus, side, align, triggerWidth, triggerHeight, }; const element = useRenderElement(View, componentProps, { state, ref, props: [ { accessibilityRole: 'menu' as const, // Claim the touch responder so presses inside the popup never reach the // backdrop's outside-press handler. onStartShouldSetResponder: () => true, }, elementProps, ], }); // Items register here so they can be indexed in visual order. return {element}; } export interface MenuPopupState { /** * Whether the menu is currently open. */ open: boolean; /** * The transition status of the menu: `'starting'` as it opens (auto-clears * to `undefined` after one frame), `'ending'` once it is closing. */ transitionStatus: TransitionStatus; /** * The side the popup was actually placed on, after collision handling. */ side: PhysicalSide; /** * The alignment the popup was actually placed with. */ align: Align; /** * The trigger's measured width, available for consumers to size the popup * against its anchor. This is the React Native equivalent of the web's * `--anchor-width` CSS variable. */ triggerWidth: number | undefined; /** * The trigger's measured height. */ triggerHeight: number | undefined; } export interface MenuPopupProps extends ZestUIComponentProps {} export namespace MenuPopup { export type State = MenuPopupState; export type Props = MenuPopupProps; }