Menubar Primitive
A menu that stays visible on the screen, often seen in desktop apps, offering easy access to a standard set of commands.
Installation
Section titled “Installation”Install the component via your command line.
npx expo install @rn-primitives/menubarInstall @radix-ui/react-menubar
npx expo install @radix-ui/react-menubarCopy/paste the following code for web to  ~/components/primitives/menubar/menubar.web.tsx
import * as Menubar from '@radix-ui/react-menubar';import {  useAugmentedRef,  useControllableState,  useIsomorphicLayoutEffect,} from '~/components/primitives/hooks';import * as Slot from '~/components/primitives/slot';import { EmptyGestureResponderEvent } from '~/components/primitives/utils';import * as React from 'react';import { GestureResponderEvent, Pressable, Text, View } from 'react-native';import type {  CheckboxItemProps,  CheckboxItemRef,  ContentProps,  ContentRef,  GroupProps,  GroupRef,  ItemIndicatorProps,  ItemIndicatorRef,  ItemProps,  ItemRef,  LabelProps,  LabelRef,  MenuProps,  MenuRef,  OverlayProps,  OverlayRef,  PortalProps,  RadioGroupProps,  RadioGroupRef,  RadioItemProps,  RadioItemRef,  RootProps,  RootRef,  SeparatorProps,  SeparatorRef,  SubContentProps,  SubContentRef,  SubProps,  SubRef,  SubTriggerProps,  SubTriggerRef,  TriggerProps,  TriggerRef,} from './types';
const RootContext = React.createContext<RootProps | null>(null);
const Root = React.forwardRef<RootRef, RootProps>(  ({ asChild, value, onValueChange, ...viewProps }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <RootContext.Provider value={{ value, onValueChange }}>        <Menubar.Root value={value} onValueChange={onValueChange}>          <Component ref={ref} {...viewProps} />        </Menubar.Root>      </RootContext.Provider>    );  });
Root.displayName = 'RootWebMenubar';
function useRootContext() {  const context = React.useContext(RootContext);  if (!context) {    throw new Error('Menubar compound components cannot be rendered outside the Menubar component');  }  return context;}
const MenuContext = React.createContext<MenuProps | null>(null);
const Menu = React.forwardRef<MenuRef, MenuProps>(({ asChild, value, ...viewProps }, ref) => {  const Component = asChild ? Slot.View : View;  return (    <MenuContext.Provider value={{ value }}>      <Menubar.Menu value={value}>        <Component ref={ref} {...viewProps} />      </Menubar.Menu>    </MenuContext.Provider>  );});
Menu.displayName = 'MenuWebMenubar';
function useMenuContext() {  const context = React.useContext(MenuContext);  if (!context) {    throw new Error('Menubar compound components cannot be rendered outside the Menubar component');  }  return context;}
const Trigger = React.forwardRef<TriggerRef, TriggerProps>(  ({ asChild, disabled = false, ...props }, ref) => {    const augmentedRef = useAugmentedRef({ ref });    const { value: menuValue } = useMenuContext();    const { value } = useRootContext();
    useIsomorphicLayoutEffect(() => {      if (augmentedRef.current) {        const augRef = augmentedRef.current as unknown as HTMLDivElement;        augRef.dataset.state = value && menuValue === value ? 'open' : 'closed';      }    }, [value && menuValue]);
    useIsomorphicLayoutEffect(() => {      if (augmentedRef.current) {        const augRef = augmentedRef.current as unknown as HTMLDivElement;        if (disabled) {          augRef.dataset.disabled = 'true';        } else {          augRef.dataset.disabled = undefined;        }      }    }, [disabled]);
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Menubar.Trigger disabled={disabled ?? undefined} asChild>        <Component ref={augmentedRef} disabled={disabled} {...props} />      </Menubar.Trigger>    );  });
Trigger.displayName = 'TriggerWebMenubar';
function Portal({ forceMount, container, children }: PortalProps) {  return <Menubar.Portal forceMount={forceMount} container={container} children={children} />;}
const Overlay = React.forwardRef<OverlayRef, OverlayProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.Pressable : Pressable;  return <Component ref={ref} {...props} />;});
Overlay.displayName = 'OverlayWebMenubar';
const MenubarContentContext = React.createContext<{  close: () => void;} | null>(null);
const Content = React.forwardRef<ContentRef, ContentProps>(  (    {      asChild = false,      forceMount,      align,      side,      sideOffset,      alignOffset = 0,      avoidCollisions = true,      insets,      loop,      onCloseAutoFocus,      onEscapeKeyDown,      onPointerDownOutside,      onFocusOutside,      onInteractOutside,      collisionBoundary,      sticky,      hideWhenDetached,      ...props    },    ref  ) => {    const itemRef = React.useRef<HTMLDivElement>(null);
    function close() {      itemRef.current?.click();    }
    const Component = asChild ? Slot.View : View;    return (      <MenubarContentContext.Provider value={{ close }}>        <Menubar.Content          forceMount={forceMount}          alignOffset={alignOffset}          avoidCollisions={avoidCollisions}          collisionPadding={insets}          loop={loop}          onCloseAutoFocus={onCloseAutoFocus}          onEscapeKeyDown={onEscapeKeyDown}          onPointerDownOutside={onPointerDownOutside}          onFocusOutside={onFocusOutside}          onInteractOutside={onInteractOutside}          collisionBoundary={collisionBoundary}          sticky={sticky}          hideWhenDetached={hideWhenDetached}          align={align}          side={side}          sideOffset={sideOffset}        >          <Component ref={ref} {...props} />          <Menubar.Item            ref={itemRef}            aria-hidden            style={{ position: 'fixed', top: 0, left: 0, zIndex: -999999999 }}            aria-disabled            tabIndex={-1}            hidden          />        </Menubar.Content>      </MenubarContentContext.Provider>    );  });
Content.displayName = 'ContentWebMenubar';
function useMenubarContentContext() {  const context = React.useContext(MenubarContentContext);  if (!context) {    throw new Error(      'MenubarContent compound components cannot be rendered outside the MenubarContent component'    );  }  return context;}
const Item = React.forwardRef<ItemRef, ItemProps>(  (    {      asChild,      textValue,      closeOnPress = true,      onPress: onPressProp,      onKeyDown: onKeyDownProp,      ...props    },    ref  ) => {    const { close } = useMenubarContentContext();
    function onKeyDown(ev: React.KeyboardEvent) {      onKeyDownProp?.(ev);      if (ev.key === 'Enter' || ev.key === ' ') {        onPressProp?.(EmptyGestureResponderEvent);        if (closeOnPress) {          close();        }      }    }
    function onPress(ev: GestureResponderEvent) {      onPressProp?.(ev);      if (closeOnPress) {        close();      }    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Menubar.Item        textValue={textValue}        disabled={props.disabled ?? undefined}        onSelect={closeOnPress ? undefined : onSelected}        asChild      >        <Component          ref={ref}          // @ts-expect-error web only          onKeyDown={onKeyDown}          onPress={onPress}          {...props}        />      </Menubar.Item>    );  });
Item.displayName = 'ItemWebMenubar';
const Group = React.forwardRef<GroupRef, GroupProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.View : View;  return (    <Menubar.Group asChild>      <Component ref={ref} {...props} />    </Menubar.Group>  );});
Group.displayName = 'GroupWebMenubar';
const Label = React.forwardRef<LabelRef, LabelProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.Text : Text;  return (    <Menubar.Label asChild>      <Component ref={ref} {...props} />    </Menubar.Label>  );});
Label.displayName = 'LabelWebMenubar';
const CheckboxItem = React.forwardRef<CheckboxItemRef, CheckboxItemProps>(  (    {      asChild,      checked,      onCheckedChange,      textValue,      disabled = false,      closeOnPress = true,      onPress: onPressProp,      onKeyDown: onKeyDownProp,      ...props    },    ref  ) => {    function onKeyDown(ev: React.KeyboardEvent) {      onKeyDownProp?.(ev);      if (ev.key === 'Enter' || ev.key === ' ') {        onPressProp?.(EmptyGestureResponderEvent);        onCheckedChange?.(!checked);        if (closeOnPress) {          close();        }      }    }
    function onPress(ev: GestureResponderEvent) {      onPressProp?.(ev);      onCheckedChange?.(!checked);      if (closeOnPress) {        close();      }    }    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Menubar.CheckboxItem        textValue={textValue}        checked={checked}        onCheckedChange={onCheckedChange}        onSelect={closeOnPress ? undefined : onSelected}        disabled={disabled ?? undefined}        asChild      >        <Component          ref={ref}          // @ts-expect-error web only          onKeyDown={onKeyDown}          onPress={onPress}          role='button'          {...props}        />      </Menubar.CheckboxItem>    );  });
CheckboxItem.displayName = 'CheckboxItemWebMenubar';
const MenubarRadioGroupContext = React.createContext<{  value?: string;  onValueChange?: (value: string) => void;} | null>(null);
const RadioGroup = React.forwardRef<RadioGroupRef, RadioGroupProps>(  ({ asChild, value, onValueChange, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <MenubarRadioGroupContext.Provider value={{ value, onValueChange }}>        <Menubar.RadioGroup value={value} onValueChange={onValueChange} asChild>          <Component ref={ref} {...props} />        </Menubar.RadioGroup>      </MenubarRadioGroupContext.Provider>    );  });
RadioGroup.displayName = 'RadioGroupWebMenubar';
function useMenubarRadioGroupContext() {  const context = React.useContext(MenubarRadioGroupContext);  if (!context) {    throw new Error(      'MenubarRadioGroup compound components cannot be rendered outside the MenubarRadioGroup component'    );  }  return context;}
const RadioItem = React.forwardRef<RadioItemRef, RadioItemProps>(  (    {      asChild,      value,      textValue,      closeOnPress = true,      onPress: onPressProp,      onKeyDown: onKeyDownProp,      ...props    },    ref  ) => {    const { onValueChange } = useMenubarRadioGroupContext();    const { close } = useMenubarContentContext();
    function onKeyDown(ev: React.KeyboardEvent) {      onKeyDownProp?.(ev);      if (ev.key === 'Enter' || ev.key === ' ') {        onValueChange?.(value);        onPressProp?.(EmptyGestureResponderEvent);        if (closeOnPress) {          close();        }      }    }
    function onPress(ev: GestureResponderEvent) {      onValueChange?.(value);      onPressProp?.(ev);      if (closeOnPress) {        close();      }    }    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Menubar.RadioItem        value={value}        textValue={textValue}        disabled={props.disabled ?? undefined}        onSelect={closeOnPress ? undefined : onSelected}        asChild      >        <Component          ref={ref}          // @ts-expect-error web only          onKeyDown={onKeyDown}          onPress={onPress}          {...props}        />      </Menubar.RadioItem>    );  });
RadioItem.displayName = 'RadioItemWebMenubar';
const ItemIndicator = React.forwardRef<ItemIndicatorRef, ItemIndicatorProps>(  ({ asChild, forceMount, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <Menubar.ItemIndicator forceMount={forceMount} asChild>        <Component ref={ref} {...props} />      </Menubar.ItemIndicator>    );  });
ItemIndicator.displayName = 'ItemIndicatorWebMenubar';
const Separator = React.forwardRef<SeparatorRef, SeparatorProps>(  ({ asChild, decorative, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <Menubar.Separator asChild>        <Component ref={ref} {...props} />      </Menubar.Separator>    );  });
Separator.displayName = 'SeparatorWebMenubar';
const MenubarSubContext = React.createContext<{  open: boolean;  onOpenChange: (open: boolean) => void;} | null>(null);
const Sub = React.forwardRef<SubRef, SubProps>(  ({ asChild, defaultOpen, open: openProp, onOpenChange: onOpenChangeProp, ...props }, ref) => {    const [open = false, onOpenChange] = useControllableState({      prop: openProp,      defaultProp: defaultOpen,      onChange: onOpenChangeProp,    });    const Component = asChild ? Slot.View : View;    return (      <MenubarSubContext.Provider value={{ open, onOpenChange }}>        <Menubar.Sub open={open} onOpenChange={onOpenChange}>          <Component ref={ref} {...props} />        </Menubar.Sub>      </MenubarSubContext.Provider>    );  });
Sub.displayName = 'SubWebMenubar';
function useSubContext() {  const context = React.useContext(MenubarSubContext);  if (!context) {    throw new Error(      'MenubarSub compound components cannot be rendered outside the MenubarSub component'    );  }  return context;}
const SubTrigger = React.forwardRef<SubTriggerRef, SubTriggerProps>(  ({ asChild, textValue, disabled = false, onPress: onPressProp, ...props }, ref) => {    const { onOpenChange } = useSubContext();
    function onPress(ev: GestureResponderEvent) {      onOpenChange(true);      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Menubar.SubTrigger disabled={disabled ?? undefined} textValue={textValue} asChild>        <Component ref={ref} onPress={onPress} {...props} />      </Menubar.SubTrigger>    );  });
SubTrigger.displayName = 'SubTriggerWebMenubar';
const SubContent = React.forwardRef<SubContentRef, SubContentProps>(  ({ asChild = false, forceMount, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <Menubar.Portal>        <Menubar.SubContent forceMount={forceMount}>          <Component ref={ref} {...props} />        </Menubar.SubContent>      </Menubar.Portal>    );  });
Content.displayName = 'ContentWebMenubar';
export {  CheckboxItem,  Content,  Group,  Item,  ItemIndicator,  Label,  Menu,  Overlay,  Portal,  RadioGroup,  RadioItem,  Root,  Separator,  Sub,  SubContent,  SubTrigger,  Trigger,  useMenuContext,  useRootContext,  useSubContext,};
function onSelected(ev: Event) {  ev.preventDefault();}Copy/paste the following code for native to  ~/components/primitives/menubar/menubar.tsx
import {  useAugmentedRef,  useControllableState,  useRelativePosition,  type LayoutPosition,} from '~/components/primitives/hooks';import { Portal as RNPPortal } from '~/components/primitives/portal';import * as Slot from '~/components/primitives/slot';import * as React from 'react';import {  BackHandler,  Pressable,  Text,  View,  type GestureResponderEvent,  type LayoutChangeEvent,  type LayoutRectangle,} from 'react-native';import type {  CheckboxItemProps,  CheckboxItemRef,  ContentProps,  ContentRef,  GroupProps,  GroupRef,  ItemIndicatorProps,  ItemIndicatorRef,  ItemProps,  ItemRef,  LabelProps,  LabelRef,  MenuProps,  MenuRef,  OverlayProps,  OverlayRef,  PortalProps,  RadioGroupProps,  RadioGroupRef,  RadioItemProps,  RadioItemRef,  RootProps,  RootRef,  SeparatorProps,  SeparatorRef,  SubContentProps,  SubContentRef,  SubProps,  SubRef,  SubTriggerProps,  SubTriggerRef,  TriggerProps,  TriggerRef,} from './types';
interface IMenuContext extends RootProps {  triggerPosition: LayoutPosition | null;  setTriggerPosition: (triggerPosition: LayoutPosition | null) => void;  contentLayout: LayoutRectangle | null;  setContentLayout: (contentLayout: LayoutRectangle | null) => void;  nativeID: string;}
const RootContext = React.createContext<IMenuContext | null>(null);
const Root = React.forwardRef<RootRef, RootProps>(  ({ asChild, value, onValueChange, ...viewProps }, ref) => {    const nativeID = React.useId();    const [triggerPosition, setTriggerPosition] = React.useState<LayoutPosition | null>(null);    const [contentLayout, setContentLayout] = React.useState<LayoutRectangle | null>(null);
    const Component = asChild ? Slot.View : View;    return (      <RootContext.Provider        value={{          value,          onValueChange,          nativeID,          contentLayout,          setContentLayout,          setTriggerPosition,          triggerPosition,        }}      >        <Component ref={ref} {...viewProps} />      </RootContext.Provider>    );  });
Root.displayName = 'RootMenubar';
function useRootContext() {  const context = React.useContext(RootContext);  if (!context) {    throw new Error('Menubar compound components cannot be rendered outside the Menubar component');  }  return context;}
const MenuContext = React.createContext<MenuProps | null>(null);
const Menu = React.forwardRef<MenuRef, MenuProps>(({ asChild, value, ...viewProps }, ref) => {  const Component = asChild ? Slot.View : View;  return (    <MenuContext.Provider      value={{        value,      }}    >      <Component ref={ref} role='menubar' {...viewProps} />    </MenuContext.Provider>  );});
Menu.displayName = 'MenuMenubar';
function useMenuContext() {  const context = React.useContext(MenuContext);  if (!context) {    throw new Error('Menubar compound components cannot be rendered outside the Menubar component');  }  return context;}
const Trigger = React.forwardRef<TriggerRef, TriggerProps>(  ({ asChild, onPress: onPressProp, disabled = false, ...props }, ref) => {    const triggerRef = useAugmentedRef({ ref });    const { value, onValueChange, setTriggerPosition } = useRootContext();    const { value: menuValue } = useMenuContext();
    function onPress(ev: GestureResponderEvent) {      if (disabled) return;      triggerRef.current?.measure((_x, _y, width, height, pageX, pageY) => {        setTriggerPosition({ width, pageX, pageY, height });      });
      onValueChange(menuValue === value ? undefined : menuValue);      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Component        ref={triggerRef}        aria-disabled={disabled ?? undefined}        role='button'        onPress={onPress}        disabled={disabled ?? undefined}        aria-expanded={value === menuValue}        {...props}      />    );  });
Trigger.displayName = 'TriggerMenubar';
/** * @warning when using a custom `<PortalHost />`, you will have to adjust the Content's sideOffset to account for nav elements like headers. */function Portal({ forceMount, hostName, children }: PortalProps) {  const menubar = useRootContext();  const menu = useMenuContext();
  if (!menubar.triggerPosition) {    return null;  }
  if (!forceMount) {    if (menubar.value !== menu.value) {      return null;    }  }
  return (    <RNPPortal hostName={hostName} name={`${menubar.nativeID}_portal`}>      <RootContext.Provider value={menubar} key={`RootContext_${menubar.nativeID}_portal_provider`}>        <MenuContext.Provider value={menu} key={`MenuContext_${menubar.nativeID}_portal_provider`}>          {children}        </MenuContext.Provider>      </RootContext.Provider>    </RNPPortal>  );}
const Overlay = React.forwardRef<OverlayRef, OverlayProps>(  ({ asChild, forceMount, onPress: OnPressProp, closeOnPress = true, ...props }, ref) => {    const { value, onValueChange, setContentLayout, setTriggerPosition } = useRootContext();
    function onPress(ev: GestureResponderEvent) {      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);      }      OnPressProp?.(ev);    }
    if (!forceMount) {      if (!value) {        return null;      }    }
    const Component = asChild ? Slot.Pressable : Pressable;    return <Component ref={ref} onPress={onPress} {...props} />;  });
Overlay.displayName = 'OverlayMenubar';
/** * @info `position`, `top`, `left`, and `maxWidth` style properties are controlled internally. Opt out of this behavior by setting `disablePositioningStyle` to `true`. */const Content = React.forwardRef<ContentRef, ContentProps>(  (    {      asChild = false,      forceMount,      align = 'start',      side = 'bottom',      sideOffset = 0,      alignOffset = 0,      avoidCollisions = true,      onLayout: onLayoutProp,      insets,      style,      disablePositioningStyle,      ...props    },    ref  ) => {    const {      value,      onValueChange,      triggerPosition,      contentLayout,      setContentLayout,      nativeID,      setTriggerPosition,    } = useRootContext();    const { value: menuValue } = useMenuContext();
    React.useEffect(() => {      const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);        return true;      });
      return () => {        setContentLayout(null);        backHandler.remove();      };    }, []);
    const positionStyle = useRelativePosition({      align,      avoidCollisions,      triggerPosition,      contentLayout,      alignOffset,      insets,      sideOffset,      side,      disablePositioningStyle,    });
    function onLayout(event: LayoutChangeEvent) {      setContentLayout(event.nativeEvent.layout);      onLayoutProp?.(event);    }
    if (!forceMount) {      if (value !== menuValue) {        return null;      }    }
    const Component = asChild ? Slot.View : View;    return (      <Component        ref={ref}        role='menu'        nativeID={nativeID}        aria-modal={true}        style={[positionStyle, style]}        onLayout={onLayout}        onStartShouldSetResponder={onStartShouldSetResponder}        {...props}      />    );  });
Content.displayName = 'ContentMenubar';
const Item = React.forwardRef<ItemRef, ItemProps>(  (    { asChild, textValue, onPress: onPressProp, disabled = false, closeOnPress = true, ...props },    ref  ) => {    const { onValueChange, setContentLayout, setTriggerPosition } = useRootContext();
    function onPress(ev: GestureResponderEvent) {      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);      }      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Component        ref={ref}        role='menuitem'        onPress={onPress}        disabled={disabled}        aria-valuetext={textValue}        aria-disabled={!!disabled}        accessibilityState={{ disabled: !!disabled }}        {...props}      />    );  });
Item.displayName = 'ItemMenubar';
const Group = React.forwardRef<GroupRef, GroupProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.View : View;  return <Component ref={ref} role='group' {...props} />;});
Group.displayName = 'GroupMenubar';
const Label = React.forwardRef<LabelRef, LabelProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.Text : Text;  return <Component ref={ref} {...props} />;});
Label.displayName = 'LabelMenubar';
type FormItemContext =  | { checked: boolean }  | {      value: string | undefined;      onValueChange: (value: string) => void;    };
const FormItemContext = React.createContext<FormItemContext | null>(null);
const CheckboxItem = React.forwardRef<CheckboxItemRef, CheckboxItemProps>(  (    {      asChild,      checked,      onCheckedChange,      textValue,      onPress: onPressProp,      closeOnPress = true,      disabled = false,      ...props    },    ref  ) => {    const { onValueChange, setTriggerPosition, setContentLayout, nativeID } = useRootContext();
    function onPress(ev: GestureResponderEvent) {      onCheckedChange(!checked);      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);      }      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <FormItemContext.Provider value={{ checked }}>        <Component          ref={ref}          role='checkbox'          aria-checked={checked}          onPress={onPress}          disabled={disabled}          aria-disabled={!!disabled}          aria-valuetext={textValue}          accessibilityState={{ disabled: !!disabled }}          {...props}        />      </FormItemContext.Provider>    );  });
CheckboxItem.displayName = 'CheckboxItemMenubar';
function useFormItemContext() {  const context = React.useContext(FormItemContext);  if (!context) {    throw new Error(      'CheckboxItem or RadioItem compound components cannot be rendered outside of a CheckboxItem or RadioItem component'    );  }  return context;}
const RadioGroup = React.forwardRef<RadioGroupRef, RadioGroupProps>(  ({ asChild, value, onValueChange, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <FormItemContext.Provider value={{ value, onValueChange }}>        <Component ref={ref} role='radiogroup' {...props} />      </FormItemContext.Provider>    );  });
RadioGroup.displayName = 'RadioGroupMenubar';
type BothFormItemContext = Exclude<FormItemContext, { checked: boolean }> & {  checked: boolean;};
const RadioItemContext = React.createContext({} as { itemValue: string });
const RadioItem = React.forwardRef<RadioItemRef, RadioItemProps>(  (    {      asChild,      value: itemValue,      textValue,      onPress: onPressProp,      disabled = false,      closeOnPress = true,      ...props    },    ref  ) => {    const {      onValueChange: onRootValueChange,      setTriggerPosition,      setContentLayout,    } = useRootContext();
    const { value, onValueChange } = useFormItemContext() as BothFormItemContext;    function onPress(ev: GestureResponderEvent) {      onValueChange(itemValue);      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onRootValueChange(undefined);      }      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <RadioItemContext.Provider value={{ itemValue }}>        <Component          ref={ref}          onPress={onPress}          role='radio'          aria-checked={value === itemValue}          disabled={disabled ?? false}          accessibilityState={{            disabled: disabled ?? false,            checked: value === itemValue,          }}          aria-valuetext={textValue}          {...props}        />      </RadioItemContext.Provider>    );  });
RadioItem.displayName = 'RadioItemMenubar';
function useItemIndicatorContext() {  return React.useContext(RadioItemContext);}
const ItemIndicator = React.forwardRef<ItemIndicatorRef, ItemIndicatorProps>(  ({ asChild, forceMount, ...props }, ref) => {    const { itemValue } = useItemIndicatorContext();    const { checked, value } = useFormItemContext() as BothFormItemContext;
    if (!forceMount) {      if (itemValue == null && !checked) {        return null;      }      if (value !== itemValue) {        return null;      }    }    const Component = asChild ? Slot.View : View;    return <Component ref={ref} role='presentation' {...props} />;  });
ItemIndicator.displayName = 'ItemIndicatorMenubar';
const Separator = React.forwardRef<SeparatorRef, SeparatorProps>(  ({ asChild, decorative, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return <Component role={decorative ? 'presentation' : 'separator'} ref={ref} {...props} />;  });
Separator.displayName = 'SeparatorMenubar';
const SubContext = React.createContext<{  nativeID: string;  open: boolean;  onOpenChange: (value: boolean) => void;} | null>(null);
const Sub = React.forwardRef<SubRef, SubProps>(  ({ asChild, defaultOpen, open: openProp, onOpenChange: onOpenChangeProp, ...props }, ref) => {    const nativeID = React.useId();    const [open = false, onOpenChange] = useControllableState({      prop: openProp,      defaultProp: defaultOpen,      onChange: onOpenChangeProp,    });
    const Component = asChild ? Slot.View : View;    return (      <SubContext.Provider        value={{          nativeID,          open,          onOpenChange,        }}      >        <Component ref={ref} {...props} />      </SubContext.Provider>    );  });
Sub.displayName = 'SubMenubar';
function useSubContext() {  const context = React.useContext(SubContext);  if (!context) {    throw new Error('Sub compound components cannot be rendered outside of a Sub component');  }  return context;}
const SubTrigger = React.forwardRef<SubTriggerRef, SubTriggerProps>(  ({ asChild, textValue, onPress: onPressProp, disabled = false, ...props }, ref) => {    const { nativeID, open, onOpenChange } = useSubContext();
    function onPress(ev: GestureResponderEvent) {      onOpenChange(!open);      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Component        ref={ref}        aria-valuetext={textValue}        role='menuitem'        aria-expanded={open}        accessibilityState={{ expanded: open, disabled: !!disabled }}        nativeID={nativeID}        onPress={onPress}        disabled={disabled}        aria-disabled={!!disabled}        {...props}      />    );  });
SubTrigger.displayName = 'SubTriggerMenubar';
const SubContent = React.forwardRef<SubContentRef, SubContentProps>(  ({ asChild = false, forceMount, ...props }, ref) => {    const { open, nativeID } = useSubContext();
    if (!forceMount) {      if (!open) {        return null;      }    }
    const Component = asChild ? Slot.View : View;    return <Component ref={ref} role='group' aria-labelledby={nativeID} {...props} />;  });
SubContent.displayName = 'SubContentMenubar';
export {  CheckboxItem,  Content,  Group,  Item,  ItemIndicator,  Label,  Menu,  Overlay,  Portal,  RadioGroup,  RadioItem,  Root,  Separator,  Sub,  SubContent,  SubTrigger,  Trigger,  useMenuContext,  useRootContext,  useSubContext,};
function onStartShouldSetResponder() {  return true;}Copy/paste the following code for types to  ~/components/primitives/menubar/types.ts
import {  ForceMountable,  PositionedContentProps,  PressableRef,  SlottablePressableProps,  SlottableTextProps,  SlottableViewProps,  TextRef,  ViewRef,} from '~/components/primitives/types';
type RootProps = SlottableViewProps & {  value: string | undefined;  onValueChange: (value: string | undefined) => void;};
type MenuProps = SlottableViewProps & {  value: string | undefined;};
interface PortalProps extends ForceMountable {  children: React.ReactNode;  /**   * Platform: NATIVE ONLY   */  hostName?: string;  /**   * Platform: WEB ONLY   */  container?: HTMLElement | null | undefined;}
type OverlayProps = ForceMountable &  SlottablePressableProps & {    closeOnPress?: boolean;  };
type ItemProps = SlottablePressableProps & {  textValue?: string;  closeOnPress?: boolean;};
type CheckboxItemProps = SlottablePressableProps & {  checked: boolean;  onCheckedChange: (checked: boolean) => void;  closeOnPress?: boolean;  textValue?: string;};
type RadioGroupProps = SlottableViewProps & {  value: string | undefined;  onValueChange: (value: string) => void;};
type RadioItemProps = SlottablePressableProps & {  value: string;  textValue?: string;  closeOnPress?: boolean;};
type SeparatorProps = SlottableViewProps & {  decorative?: boolean;};
type SubProps = SlottableViewProps & {  defaultOpen?: boolean;  open?: boolean;  onOpenChange?: (value: boolean) => void;};
type SubTriggerProps = SlottablePressableProps & {  textValue?: string;};
type TriggerProps = SlottablePressableProps;type ContentProps = SlottableViewProps & PositionedContentProps;type SubContentProps = SlottableViewProps & ForceMountable;type ItemIndicatorProps = SlottableViewProps & ForceMountable;type GroupProps = SlottableViewProps;type LabelProps = SlottableTextProps;
type CheckboxItemRef = PressableRef;type ContentRef = ViewRef;type GroupRef = ViewRef;type ItemIndicatorRef = ViewRef;type ItemRef = PressableRef;type LabelRef = TextRef;type MenuRef = ViewRef;type OverlayRef = PressableRef;type RadioGroupRef = ViewRef;type RadioItemRef = PressableRef;type RootRef = ViewRef;type SeparatorRef = ViewRef;type SubContentRef = ViewRef;type SubRef = ViewRef;type SubTriggerRef = PressableRef;type TriggerRef = PressableRef;
export type {  CheckboxItemProps,  CheckboxItemRef,  ContentProps,  ContentRef,  GroupProps,  GroupRef,  ItemIndicatorProps,  ItemIndicatorRef,  ItemProps,  ItemRef,  LabelProps,  LabelRef,  MenuProps,  MenuRef,  OverlayProps,  OverlayRef,  PortalProps,  RadioGroupProps,  RadioGroupRef,  RadioItemProps,  RadioItemRef,  RootProps,  RootRef,  SeparatorProps,  SeparatorRef,  SubContentProps,  SubContentRef,  SubProps,  SubRef,  SubTriggerProps,  SubTriggerRef,  TriggerProps,  TriggerRef,};Copy/paste the following code for exporting to  ~/components/primitives/menubar/index.ts
export * from './menubar';export * from './types';Copy/paste the following code for native to  ~/components/primitives/menubar/index.tsx
import {  useAugmentedRef,  useControllableState,  useRelativePosition,  type LayoutPosition,} from '~/components/primitives/hooks';import { Portal as RNPPortal } from '~/components/primitives/portal';import * as Slot from '~/components/primitives/slot';import * as React from 'react';import {  BackHandler,  Pressable,  Text,  View,  type GestureResponderEvent,  type LayoutChangeEvent,  type LayoutRectangle,} from 'react-native';import type {  CheckboxItemProps,  CheckboxItemRef,  ContentProps,  ContentRef,  GroupProps,  GroupRef,  ItemIndicatorProps,  ItemIndicatorRef,  ItemProps,  ItemRef,  LabelProps,  LabelRef,  MenuProps,  MenuRef,  OverlayProps,  OverlayRef,  PortalProps,  RadioGroupProps,  RadioGroupRef,  RadioItemProps,  RadioItemRef,  RootProps,  RootRef,  SeparatorProps,  SeparatorRef,  SubContentProps,  SubContentRef,  SubProps,  SubRef,  SubTriggerProps,  SubTriggerRef,  TriggerProps,  TriggerRef,} from './types';
interface IMenuContext extends RootProps {  triggerPosition: LayoutPosition | null;  setTriggerPosition: (triggerPosition: LayoutPosition | null) => void;  contentLayout: LayoutRectangle | null;  setContentLayout: (contentLayout: LayoutRectangle | null) => void;  nativeID: string;}
const RootContext = React.createContext<IMenuContext | null>(null);
const Root = React.forwardRef<RootRef, RootProps>(  ({ asChild, value, onValueChange, ...viewProps }, ref) => {    const nativeID = React.useId();    const [triggerPosition, setTriggerPosition] = React.useState<LayoutPosition | null>(null);    const [contentLayout, setContentLayout] = React.useState<LayoutRectangle | null>(null);
    const Component = asChild ? Slot.View : View;    return (      <RootContext.Provider        value={{          value,          onValueChange,          nativeID,          contentLayout,          setContentLayout,          setTriggerPosition,          triggerPosition,        }}      >        <Component ref={ref} {...viewProps} />      </RootContext.Provider>    );  });
Root.displayName = 'RootMenubar';
function useRootContext() {  const context = React.useContext(RootContext);  if (!context) {    throw new Error('Menubar compound components cannot be rendered outside the Menubar component');  }  return context;}
const MenuContext = React.createContext<MenuProps | null>(null);
const Menu = React.forwardRef<MenuRef, MenuProps>(({ asChild, value, ...viewProps }, ref) => {  const Component = asChild ? Slot.View : View;  return (    <MenuContext.Provider      value={{        value,      }}    >      <Component ref={ref} role='menubar' {...viewProps} />    </MenuContext.Provider>  );});
Menu.displayName = 'MenuMenubar';
function useMenuContext() {  const context = React.useContext(MenuContext);  if (!context) {    throw new Error('Menubar compound components cannot be rendered outside the Menubar component');  }  return context;}
const Trigger = React.forwardRef<TriggerRef, TriggerProps>(  ({ asChild, onPress: onPressProp, disabled = false, ...props }, ref) => {    const triggerRef = useAugmentedRef({ ref });    const { value, onValueChange, setTriggerPosition } = useRootContext();    const { value: menuValue } = useMenuContext();
    function onPress(ev: GestureResponderEvent) {      if (disabled) return;      triggerRef.current?.measure((_x, _y, width, height, pageX, pageY) => {        setTriggerPosition({ width, pageX, pageY, height });      });
      onValueChange(menuValue === value ? undefined : menuValue);      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Component        ref={triggerRef}        aria-disabled={disabled ?? undefined}        role='button'        onPress={onPress}        disabled={disabled ?? undefined}        aria-expanded={value === menuValue}        {...props}      />    );  });
Trigger.displayName = 'TriggerMenubar';
/** * @warning when using a custom `<PortalHost />`, you will have to adjust the Content's sideOffset to account for nav elements like headers. */function Portal({ forceMount, hostName, children }: PortalProps) {  const menubar = useRootContext();  const menu = useMenuContext();
  if (!menubar.triggerPosition) {    return null;  }
  if (!forceMount) {    if (menubar.value !== menu.value) {      return null;    }  }
  return (    <RNPPortal hostName={hostName} name={`${menubar.nativeID}_portal`}>      <RootContext.Provider value={menubar} key={`RootContext_${menubar.nativeID}_portal_provider`}>        <MenuContext.Provider value={menu} key={`MenuContext_${menubar.nativeID}_portal_provider`}>          {children}        </MenuContext.Provider>      </RootContext.Provider>    </RNPPortal>  );}
const Overlay = React.forwardRef<OverlayRef, OverlayProps>(  ({ asChild, forceMount, onPress: OnPressProp, closeOnPress = true, ...props }, ref) => {    const { value, onValueChange, setContentLayout, setTriggerPosition } = useRootContext();
    function onPress(ev: GestureResponderEvent) {      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);      }      OnPressProp?.(ev);    }
    if (!forceMount) {      if (!value) {        return null;      }    }
    const Component = asChild ? Slot.Pressable : Pressable;    return <Component ref={ref} onPress={onPress} {...props} />;  });
Overlay.displayName = 'OverlayMenubar';
/** * @info `position`, `top`, `left`, and `maxWidth` style properties are controlled internally. Opt out of this behavior by setting `disablePositioningStyle` to `true`. */const Content = React.forwardRef<ContentRef, ContentProps>(  (    {      asChild = false,      forceMount,      align = 'start',      side = 'bottom',      sideOffset = 0,      alignOffset = 0,      avoidCollisions = true,      onLayout: onLayoutProp,      insets,      style,      disablePositioningStyle,      ...props    },    ref  ) => {    const {      value,      onValueChange,      triggerPosition,      contentLayout,      setContentLayout,      nativeID,      setTriggerPosition,    } = useRootContext();    const { value: menuValue } = useMenuContext();
    React.useEffect(() => {      const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);        return true;      });
      return () => {        setContentLayout(null);        backHandler.remove();      };    }, []);
    const positionStyle = useRelativePosition({      align,      avoidCollisions,      triggerPosition,      contentLayout,      alignOffset,      insets,      sideOffset,      side,      disablePositioningStyle,    });
    function onLayout(event: LayoutChangeEvent) {      setContentLayout(event.nativeEvent.layout);      onLayoutProp?.(event);    }
    if (!forceMount) {      if (value !== menuValue) {        return null;      }    }
    const Component = asChild ? Slot.View : View;    return (      <Component        ref={ref}        role='menu'        nativeID={nativeID}        aria-modal={true}        style={[positionStyle, style]}        onLayout={onLayout}        onStartShouldSetResponder={onStartShouldSetResponder}        {...props}      />    );  });
Content.displayName = 'ContentMenubar';
const Item = React.forwardRef<ItemRef, ItemProps>(  (    { asChild, textValue, onPress: onPressProp, disabled = false, closeOnPress = true, ...props },    ref  ) => {    const { onValueChange, setContentLayout, setTriggerPosition } = useRootContext();
    function onPress(ev: GestureResponderEvent) {      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);      }      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Component        ref={ref}        role='menuitem'        onPress={onPress}        disabled={disabled}        aria-valuetext={textValue}        aria-disabled={!!disabled}        accessibilityState={{ disabled: !!disabled }}        {...props}      />    );  });
Item.displayName = 'ItemMenubar';
const Group = React.forwardRef<GroupRef, GroupProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.View : View;  return <Component ref={ref} role='group' {...props} />;});
Group.displayName = 'GroupMenubar';
const Label = React.forwardRef<LabelRef, LabelProps>(({ asChild, ...props }, ref) => {  const Component = asChild ? Slot.Text : Text;  return <Component ref={ref} {...props} />;});
Label.displayName = 'LabelMenubar';
type FormItemContext =  | { checked: boolean }  | {      value: string | undefined;      onValueChange: (value: string) => void;    };
const FormItemContext = React.createContext<FormItemContext | null>(null);
const CheckboxItem = React.forwardRef<CheckboxItemRef, CheckboxItemProps>(  (    {      asChild,      checked,      onCheckedChange,      textValue,      onPress: onPressProp,      closeOnPress = true,      disabled = false,      ...props    },    ref  ) => {    const { onValueChange, setTriggerPosition, setContentLayout, nativeID } = useRootContext();
    function onPress(ev: GestureResponderEvent) {      onCheckedChange(!checked);      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onValueChange(undefined);      }      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <FormItemContext.Provider value={{ checked }}>        <Component          ref={ref}          role='checkbox'          aria-checked={checked}          onPress={onPress}          disabled={disabled}          aria-disabled={!!disabled}          aria-valuetext={textValue}          accessibilityState={{ disabled: !!disabled }}          {...props}        />      </FormItemContext.Provider>    );  });
CheckboxItem.displayName = 'CheckboxItemMenubar';
function useFormItemContext() {  const context = React.useContext(FormItemContext);  if (!context) {    throw new Error(      'CheckboxItem or RadioItem compound components cannot be rendered outside of a CheckboxItem or RadioItem component'    );  }  return context;}
const RadioGroup = React.forwardRef<RadioGroupRef, RadioGroupProps>(  ({ asChild, value, onValueChange, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return (      <FormItemContext.Provider value={{ value, onValueChange }}>        <Component ref={ref} role='radiogroup' {...props} />      </FormItemContext.Provider>    );  });
RadioGroup.displayName = 'RadioGroupMenubar';
type BothFormItemContext = Exclude<FormItemContext, { checked: boolean }> & {  checked: boolean;};
const RadioItemContext = React.createContext({} as { itemValue: string });
const RadioItem = React.forwardRef<RadioItemRef, RadioItemProps>(  (    {      asChild,      value: itemValue,      textValue,      onPress: onPressProp,      disabled = false,      closeOnPress = true,      ...props    },    ref  ) => {    const {      onValueChange: onRootValueChange,      setTriggerPosition,      setContentLayout,    } = useRootContext();
    const { value, onValueChange } = useFormItemContext() as BothFormItemContext;    function onPress(ev: GestureResponderEvent) {      onValueChange(itemValue);      if (closeOnPress) {        setTriggerPosition(null);        setContentLayout(null);        onRootValueChange(undefined);      }      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <RadioItemContext.Provider value={{ itemValue }}>        <Component          ref={ref}          onPress={onPress}          role='radio'          aria-checked={value === itemValue}          disabled={disabled ?? false}          accessibilityState={{            disabled: disabled ?? false,            checked: value === itemValue,          }}          aria-valuetext={textValue}          {...props}        />      </RadioItemContext.Provider>    );  });
RadioItem.displayName = 'RadioItemMenubar';
function useItemIndicatorContext() {  return React.useContext(RadioItemContext);}
const ItemIndicator = React.forwardRef<ItemIndicatorRef, ItemIndicatorProps>(  ({ asChild, forceMount, ...props }, ref) => {    const { itemValue } = useItemIndicatorContext();    const { checked, value } = useFormItemContext() as BothFormItemContext;
    if (!forceMount) {      if (itemValue == null && !checked) {        return null;      }      if (value !== itemValue) {        return null;      }    }    const Component = asChild ? Slot.View : View;    return <Component ref={ref} role='presentation' {...props} />;  });
ItemIndicator.displayName = 'ItemIndicatorMenubar';
const Separator = React.forwardRef<SeparatorRef, SeparatorProps>(  ({ asChild, decorative, ...props }, ref) => {    const Component = asChild ? Slot.View : View;    return <Component role={decorative ? 'presentation' : 'separator'} ref={ref} {...props} />;  });
Separator.displayName = 'SeparatorMenubar';
const SubContext = React.createContext<{  nativeID: string;  open: boolean;  onOpenChange: (value: boolean) => void;} | null>(null);
const Sub = React.forwardRef<SubRef, SubProps>(  ({ asChild, defaultOpen, open: openProp, onOpenChange: onOpenChangeProp, ...props }, ref) => {    const nativeID = React.useId();    const [open = false, onOpenChange] = useControllableState({      prop: openProp,      defaultProp: defaultOpen,      onChange: onOpenChangeProp,    });
    const Component = asChild ? Slot.View : View;    return (      <SubContext.Provider        value={{          nativeID,          open,          onOpenChange,        }}      >        <Component ref={ref} {...props} />      </SubContext.Provider>    );  });
Sub.displayName = 'SubMenubar';
function useSubContext() {  const context = React.useContext(SubContext);  if (!context) {    throw new Error('Sub compound components cannot be rendered outside of a Sub component');  }  return context;}
const SubTrigger = React.forwardRef<SubTriggerRef, SubTriggerProps>(  ({ asChild, textValue, onPress: onPressProp, disabled = false, ...props }, ref) => {    const { nativeID, open, onOpenChange } = useSubContext();
    function onPress(ev: GestureResponderEvent) {      onOpenChange(!open);      onPressProp?.(ev);    }
    const Component = asChild ? Slot.Pressable : Pressable;    return (      <Component        ref={ref}        aria-valuetext={textValue}        role='menuitem'        aria-expanded={open}        accessibilityState={{ expanded: open, disabled: !!disabled }}        nativeID={nativeID}        onPress={onPress}        disabled={disabled}        aria-disabled={!!disabled}        {...props}      />    );  });
SubTrigger.displayName = 'SubTriggerMenubar';
const SubContent = React.forwardRef<SubContentRef, SubContentProps>(  ({ asChild = false, forceMount, ...props }, ref) => {    const { open, nativeID } = useSubContext();
    if (!forceMount) {      if (!open) {        return null;      }    }
    const Component = asChild ? Slot.View : View;    return <Component ref={ref} role='group' aria-labelledby={nativeID} {...props} />;  });
SubContent.displayName = 'SubContentMenubar';
export {  CheckboxItem,  Content,  Group,  Item,  ItemIndicator,  Label,  Menu,  Overlay,  Portal,  RadioGroup,  RadioItem,  Root,  Separator,  Sub,  SubContent,  SubTrigger,  Trigger,  useMenuContext,  useRootContext,  useSubContext,};
function onStartShouldSetResponder() {  return true;}Copy/paste the following code for types to  ~/components/primitives/menubar/types.ts
import {  ForceMountable,  PositionedContentProps,  PressableRef,  SlottablePressableProps,  SlottableTextProps,  SlottableViewProps,  TextRef,  ViewRef,} from '~/components/primitives/types';
type RootProps = SlottableViewProps & {  value: string | undefined;  onValueChange: (value: string | undefined) => void;};
type MenuProps = SlottableViewProps & {  value: string | undefined;};
interface PortalProps extends ForceMountable {  children: React.ReactNode;  /**   * Platform: NATIVE ONLY   */  hostName?: string;  /**   * Platform: WEB ONLY   */  container?: HTMLElement | null | undefined;}
type OverlayProps = ForceMountable &  SlottablePressableProps & {    closeOnPress?: boolean;  };
type ItemProps = SlottablePressableProps & {  textValue?: string;  closeOnPress?: boolean;};
type CheckboxItemProps = SlottablePressableProps & {  checked: boolean;  onCheckedChange: (checked: boolean) => void;  closeOnPress?: boolean;  textValue?: string;};
type RadioGroupProps = SlottableViewProps & {  value: string | undefined;  onValueChange: (value: string) => void;};
type RadioItemProps = SlottablePressableProps & {  value: string;  textValue?: string;  closeOnPress?: boolean;};
type SeparatorProps = SlottableViewProps & {  decorative?: boolean;};
type SubProps = SlottableViewProps & {  defaultOpen?: boolean;  open?: boolean;  onOpenChange?: (value: boolean) => void;};
type SubTriggerProps = SlottablePressableProps & {  textValue?: string;};
type TriggerProps = SlottablePressableProps;type ContentProps = SlottableViewProps & PositionedContentProps;type SubContentProps = SlottableViewProps & ForceMountable;type ItemIndicatorProps = SlottableViewProps & ForceMountable;type GroupProps = SlottableViewProps;type LabelProps = SlottableTextProps;
type CheckboxItemRef = PressableRef;type ContentRef = ViewRef;type GroupRef = ViewRef;type ItemIndicatorRef = ViewRef;type ItemRef = PressableRef;type LabelRef = TextRef;type MenuRef = ViewRef;type OverlayRef = PressableRef;type RadioGroupRef = ViewRef;type RadioItemRef = PressableRef;type RootRef = ViewRef;type SeparatorRef = ViewRef;type SubContentRef = ViewRef;type SubRef = ViewRef;type SubTriggerRef = PressableRef;type TriggerRef = PressableRef;
export type {  CheckboxItemProps,  CheckboxItemRef,  ContentProps,  ContentRef,  GroupProps,  GroupRef,  ItemIndicatorProps,  ItemIndicatorRef,  ItemProps,  ItemRef,  LabelProps,  LabelRef,  MenuProps,  MenuRef,  OverlayProps,  OverlayRef,  PortalProps,  RadioGroupProps,  RadioGroupRef,  RadioItemProps,  RadioItemRef,  RootProps,  RootRef,  SeparatorProps,  SeparatorRef,  SubContentProps,  SubContentRef,  SubProps,  SubRef,  SubTriggerProps,  SubTriggerRef,  TriggerProps,  TriggerRef,};import * as React from 'react';import { StyleSheet, View, Text } from 'react-native';import Animated, { FadeIn } from 'react-native-reanimated';import * as MenubarPrimitive from '@rn-primitives/menubar';
function Example() {  const [value, setValue] = React.useState<string | undefined>();  const [isSubOpen, setIsSubOpen] = React.useState(false);  const [isChecked, setIsChecked] = React.useState(false);  const [radio, setRadio] = React.useState('michael');
  // TODO: handle closing menus when pressing/clicking outside of this Example component. Ex: when navigating to another screen
  function closeSubs() {    setIsSubOpen(false);  }
  function onValueChange(val: string | undefined) {    if (typeof val === 'string') {      setValue(val);      return;    }    closeSubs();    setValue(undefined);  }
  return (    <>      {!!value && (        <MenubarPrimitive.Overlay          style={StyleSheet.absoluteFillObject}        />      )}      <MenubarPrimitive.Root value={value} onValueChange={onValueChange}>        <MenubarPrimitive.Menu value='file'>          <MenubarPrimitive.Trigger onPress={closeSubs}>            <Text>File</Text>          </MenubarPrimitive.Trigger>          <MenubarPrimitive.Portal>            <MenubarPrimitive.Content>              <MenubarPrimitive.Item>                <Text>New Tab</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Item>                <Text>New Window</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Item disabled>                <Text>New Incognito Window</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Separator />              <MenubarPrimitive.Sub open={isSubOpen} onOpenChange={setIsSubOpen}>                <MenubarPrimitive.SubTrigger>                  <Text>Share</Text>                </MenubarPrimitive.SubTrigger>                <MenubarPrimitive.SubContent>                  <Animated.View entering={FadeIn.duration(200)}>                    <MenubarPrimitive.Item>                      <Text>Email link</Text>                    </MenubarPrimitive.Item>                    <MenubarPrimitive.Item>                      <Text>Messages</Text>                    </MenubarPrimitive.Item>                    <MenubarPrimitive.Item>                      <Text>Notes</Text>                    </MenubarPrimitive.Item>                  </Animated.View>                </MenubarPrimitive.SubContent>              </MenubarPrimitive.Sub>              <MenubarPrimitive.Separator />              <MenubarPrimitive.Item>                <Text>Print...</Text>              </MenubarPrimitive.Item>            </MenubarPrimitive.Content>          </MenubarPrimitive.Portal>        </MenubarPrimitive.Menu>        <MenubarPrimitive.Menu value='edit'>          <MenubarPrimitive.Trigger onPress={closeSubs}>            <Text>Edit</Text>          </MenubarPrimitive.Trigger>          <MenubarPrimitive.Content className='native:w-48'>            <MenubarPrimitive.Item>              <Text>Undo</Text>            </MenubarPrimitive.Item>            <MenubarPrimitive.Item>              <Text>Redo</Text>            </MenubarPrimitive.Item>            <MenubarPrimitive.Separator />            <MenubarPrimitive.Item>              <Text>Cut</Text>            </MenubarPrimitive.Item>            <MenubarPrimitive.Item>              <Text>Copy</Text>            </MenubarPrimitive.Item>            <MenubarPrimitive.Item>              <Text>Paste</Text>            </MenubarPrimitive.Item>          </MenubarPrimitive.Content>        </MenubarPrimitive.Menu>        <MenubarPrimitive.Menu value='view'>          <MenubarPrimitive.Trigger onPress={closeSubs}>            <Text>View</Text>          </MenubarPrimitive.Trigger>          <MenubarPrimitive.Portal>            <MenubarPrimitive.Content>              <MenubarPrimitive.CheckboxItem                checked={isChecked}                onCheckedChange={setIsChecked}                closeOnPress={false}              >                <Text>Always Show Bookmarks Bar</Text>              </MenubarPrimitive.CheckboxItem>              <MenubarPrimitive.Item>                <Text>Reload</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Item disabled>                <Text>Force Reload</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Separator />              <MenubarPrimitive.Item>                <Text>Toggle Fullscreen</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Separator />              <MenubarPrimitive.Item>                <Text>Hide Sidebar</Text>              </MenubarPrimitive.Item>            </MenubarPrimitive.Content>          </MenubarPrimitive.Portal>        </MenubarPrimitive.Menu>        <MenubarPrimitive.Menu value='profile'>          <MenubarPrimitive.Trigger onPress={closeSubs}>            <Text>Profiles</Text>          </MenubarPrimitive.Trigger>           <MenubarPrimitive.Portal>            <MenubarPrimitive.Content>              <MenubarPrimitive.RadioGroup value={radio} onValueChange={setRadio}>                <MenubarPrimitive.RadioItem closeOnPress={false} value='andy'>                  <Text>Andy</Text>                </MenubarPrimitive.RadioItem>                <MenubarPrimitive.RadioItem closeOnPress={false} value='michael'>                  <Text>Michael</Text>                </MenubarPrimitive.RadioItem>                <MenubarPrimitive.RadioItem closeOnPress={false} value='creed'>                  <Text>Creed</Text>                </MenubarPrimitive.RadioItem>              </MenubarRadioGroup>              <MenubarPrimitive.Separator />              <MenubarPrimitive.Item>                <Text>Edit...</Text>              </MenubarPrimitive.Item>              <MenubarPrimitive.Separator />              <MenubarPrimitive.Item>                <Text>Add Profile...</Text>              </MenubarPrimitive.Item>            </MenubarPrimitive.Content>           </MenubarPrimitive.Portal>        </MenubarPrimitive.Menu>      </MenubarPrimitive.Root>    </>  );}Extends View props
| Prop | Type | Note | 
|---|---|---|
| value* | boolean | |
| onValueChange* | (value: boolean) => void | |
| asChild | boolean | (optional) | 
Extends View props
| Prop | Type | Note | 
|---|---|---|
| value* | string | |
| asChild | boolean | (optional) | 
Trigger
Section titled “Trigger”Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
Portal
Section titled “Portal”| Prop | Type | Note | 
|---|---|---|
| children* | React.ReactNode | |
| forceMount | true | undefined | (optional) | 
| hostName | string | Web Only (optional) | 
| container | HTMLElement | null | undefined | Web Only (optional) | 
Overlay
Section titled “Overlay”Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| forceMount | true | undefined; | (optional) | 
Content
Section titled “Content”Extends View props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| forceMount | true | undefined | (optional) | 
| alignOffset | number | (optional) | 
| insets | Insets | (optional) | 
| avoidCollisions | boolean | (optional) | 
| align | ’start’ | ‘center’ | ‘end’ | (optional) | 
| side | ’top’ | ‘bottom’ | (optional) | 
| sideOffset | number | (optional) | 
| disablePositioningStyle | boolean | Native Only (optional) | 
| loop | boolean | Web Only (optional) | 
| onCloseAutoFocus | (event: Event) => void | Web Only (optional) | 
| onEscapeKeyDown | (event: KeyboardEvent) => void | Web Only (optional) | 
| onPointerDownOutside | (event: PointerDownOutsideEvent) => void | Web Only (optional) | 
| onFocusOutside | (event: FocusOutsideEvent) => void | Web Only (optional) | 
| onInteractOutside | PointerDownOutsideEvent | FocusOutsideEvent | Web Only (optional) | 
| collisionBoundary | Element | null | Array<Element | null> | Web Only (optional) | 
| sticky | ’partial’ | ‘always’ | Web Only (optional) | 
| hideWhenDetached | boolean | Web Only (optional) | 
Extends Text props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
Extends Text props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| textValue | boolean | (optional) | 
| closeOnPress | boolean | (optional) | 
CheckboxItem
Section titled “CheckboxItem”Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| checked* | boolean | |
| onCheckedChange* | (value: boolean) => void | |
| textValue* | string | |
| asChild | boolean | (optional) | 
| closeOnPress | boolean | Native Only_(optional)_ | 
RadioGroup
Section titled “RadioGroup”Extends View props
| Prop | Type | Note | 
|---|---|---|
| value* | boolean | |
| onValueChange* | (value: boolean) => void | |
| asChild | boolean | (optional) | 
RadioItem
Section titled “RadioItem”Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| value* | boolean | |
| onCheckedChange* | (value: boolean) => void | |
| asChild | boolean | (optional) | 
| closeOnPress | boolean | Native Only_(optional)_ | 
ItemIndicator
Section titled “ItemIndicator”Extends View props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| forceMount | true / | undefined | 
Separator
Section titled “Separator”Extends View props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| decorative | boolean | (optional) | 
Extends View props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| defaultOpen | boolean | (optional) | 
| open | boolean | (optional) | 
| onOpenChange | (value: boolean) => void | (optional) | 
SubTrigger
Section titled “SubTrigger”Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| textValue | string | (optional) | 
| asChild | boolean | (optional) | 
SubContent
Section titled “SubContent”Extends Pressable props
| Prop | Type | Note | 
|---|---|---|
| asChild | boolean | (optional) | 
| forceMount | true / | undefined | 
useRootContext
Section titled “useRootContext”Must be used within a Root component. It provides the following values from the dropdown menu: open, and onOpenChange.
useMenuContext
Section titled “useMenuContext”Must be used within a Menu component. It provides the following values from the dropdown menu: open, and onOpenChange.
useSubContext
Section titled “useSubContext”Must be used within a Sub component. It provides the following values from the dropdown menu: open, and onOpenChange.