// Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { memo } from 'react'; import { DropdownMenu } from 'radix-ui'; import type { FC } from 'react'; import { AxoSymbol } from './AxoSymbol'; import { AxoBaseMenu } from './_internal/AxoBaseMenu'; import { tw } from './tw'; const Namespace = 'AxoDropdownMenu'; /** * Displays a menu to the user—such as a set of actions or functions—triggered * by a button. * * Note: For menus that are triggered by a right-click, you should use * `AxoContextMenu`. * * @example Anatomy * ```tsx * import { AxoDropdownMenu } from "./axo/DropdownMenu/AxoDropdownMenu.tsx"; * * export default () => ( * * * * * * * * * * * * * * * * * * * * * * * * * * * * ) * ``` */ // eslint-disable-next-line @typescript-eslint/no-namespace export namespace AxoDropdownMenu { /** * Component: * --------------------------------- */ export type RootProps = AxoBaseMenu.MenuRootProps; /** * Contains all the parts of a dropdown menu. */ export const Root: FC = memo(props => { return {props.children}; }); Root.displayName = `${Namespace}.Root`; /** * Component: * ------------------------------------ */ export type TriggerProps = AxoBaseMenu.MenuTriggerProps; /** * The button that toggles the dropdown menu. * By default, the {@link AxoDropdownMenu.Content} will position itself * against the trigger. */ export const Trigger: FC = memo(props => { return ( {props.children} ); }); Trigger.displayName = `${Namespace}.Trigger`; /** * Component: * ------------------------------------ */ export type ContentProps = AxoBaseMenu.MenuContentProps; /** * The component that pops out when the dropdown menu is open. * Uses a portal to render the content part into the `body`. */ export const Content: FC = memo(props => { return ( {props.children} ); }); Content.displayName = `${Namespace}.Content`; /** * Component: * --------------------------------- */ export type ItemProps = AxoBaseMenu.MenuItemProps; /** * The component that contains the dropdown menu items. * @example * ```tsx * }> * {i18n("myContextMenuText")} * * ```` */ export const Item: FC = memo(props => { return ( {props.symbol && ( )} {props.children} {props.keyboardShortcut && ( )} ); }); Item.displayName = `${Namespace}.Item`; /** * Component: * ---------------------------------- */ export type GroupProps = AxoBaseMenu.MenuGroupProps; /** * Used to group multiple {@link AxoDropdownMenu.Item}'s. */ export const Group: FC = memo(props => { return ( {props.children} ); }); Group.displayName = `${Namespace}.Group`; /** * Component: * ---------------------------------- */ export type LabelProps = AxoBaseMenu.MenuLabelProps; /** * Used to render a label. It won't be focusable using arrow keys. */ export const Label: FC = memo(props => { return ( {props.children} ); }); Label.displayName = `${Namespace}.Label`; /** * Component: * ----------------------------------------- */ export type CheckboxItemProps = AxoBaseMenu.MenuCheckboxItemProps; /** * An item that can be controlled and rendered like a checkbox. */ export const CheckboxItem: FC = memo(props => { return ( {props.symbol && ( )} {props.children} {props.keyboardShortcut && ( )} ); }); CheckboxItem.displayName = `${Namespace}.CheckboxItem`; /** * Component: * --------------------------------------- */ export type RadioGroupProps = AxoBaseMenu.MenuRadioGroupProps; /** * Used to group multiple {@link AxoDropdownMenu.RadioItem}'s. */ export const RadioGroup: FC = memo(props => { return ( {props.children} ); }); RadioGroup.displayName = `${Namespace}.RadioGroup`; /** * Component: * -------------------------------------- */ export type RadioItemProps = AxoBaseMenu.MenuRadioItemProps; /** * An item that can be controlled and rendered like a radio. */ export const RadioItem: FC = memo(props => { return ( {props.symbol && } {props.children} {props.keyboardShortcut && ( )} ); }); RadioItem.displayName = `${Namespace}.RadioItem`; /** * Component: * -------------------------------------- */ export type SeparatorProps = AxoBaseMenu.MenuSeparatorProps; /** * Used to visually separate items in the dropdown menu. */ export const Separator: FC = memo(() => { return ( ); }); Separator.displayName = `${Namespace}.Separator`; /** * Component: * ------------------------------- */ export type SubProps = AxoBaseMenu.MenuSubProps; /** * Contains all the parts of a submenu. */ export const Sub: FC = memo(props => { return {props.children}; }); Sub.displayName = `${Namespace}.Sub`; /** * Component: * --------------------------------------- */ export type SubTriggerProps = AxoBaseMenu.MenuSubTriggerProps; /** * An item that opens a submenu. Must be rendered inside * {@link ContextMenu.Sub}. */ export const SubTrigger: FC = memo(props => { return ( {props.symbol && ( )} {props.children} ); }); SubTrigger.displayName = `${Namespace}.SubTrigger`; /** * Component: * --------------------------------------- */ export type SubContentProps = AxoBaseMenu.MenuSubContentProps; /** * The component that pops out when a submenu is open. Must be rendered * inside {@link AxoDropdownMenu.Sub}. */ export const SubContent: FC = memo(props => { return ( {props.children} ); }); SubContent.displayName = `${Namespace}.SubContent`; }