UNPKG

@loke/ui

Version:
270 lines (194 loc) 7.1 kB
# Dropdown Menu — Sub-component Reference All exports from `@loke/ui/dropdown-menu`. ## Root components ### DropdownMenu ```ts interface DropdownMenuProps { children?: ReactNode; defaultOpen?: boolean; dir?: "ltr" | "rtl"; modal?: boolean; // default: true onOpenChange?: (open: boolean) => void; open?: boolean; } ``` Root context provider. `modal={true}` disables pointer events on the background when open. Wrap `DropdownMenuTrigger` and `DropdownMenuPortal` inside. --- ### DropdownMenuTrigger ```ts interface DropdownMenuTriggerProps extends PrimitiveButtonProps { disabled?: boolean; } ``` Renders a `<button>` that toggles the menu. Sets `aria-haspopup="menu"`, `aria-expanded`, and `aria-controls`. `Enter`, `Space`, `ArrowDown` open the menu. `PointerDown` toggles. --- ### DropdownMenuPortal ```ts interface DropdownMenuPortalProps { children?: ReactNode; container?: HTMLElement | null; // default: document.body forceMount?: true; } ``` Portals content into the DOM. Wrap `DropdownMenuContent` inside. Required to avoid z-index and overflow clipping issues. --- ## Content ### DropdownMenuContent ```ts interface DropdownMenuContentProps extends Omit<MenuContentProps, "onEntryFocus"> { // All PopperContent positioning props: side?: "top" | "right" | "bottom" | "left"; // default: "bottom" sideOffset?: number; // default: 0 align?: "start" | "center" | "end"; // default: "center" alignOffset?: number; avoidCollisions?: boolean; // default: true collisionBoundary?: Element | Element[] | null; collisionPadding?: number | Partial<Record<Side, number>>; arrowPadding?: number; sticky?: "partial" | "always"; hideWhenDetached?: boolean; // DismissableLayer props: onEscapeKeyDown?: (event: KeyboardEvent) => void; onPointerDownOutside?: (event: PointerDownOutsideEvent) => void; onFocusOutside?: (event: FocusOutsideEvent) => void; onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void; onCloseAutoFocus?: (event: Event) => void; // Menu-specific: loop?: boolean; // default: false whether keyboard nav wraps } ``` CSS custom properties set on this element: | Property | Description | |---|---| | `--loke-dropdown-menu-content-available-height` | Viewport space above/below trigger | | `--loke-dropdown-menu-content-available-width` | Viewport space left/right of trigger | | `--loke-dropdown-menu-content-transform-origin` | Correct origin for scale animations | | `--loke-dropdown-menu-trigger-height` | Height of the trigger element | | `--loke-dropdown-menu-trigger-width` | Width of the trigger element | --- ## Items ### DropdownMenuItem ```ts interface DropdownMenuItemProps extends PrimitiveDivProps { disabled?: boolean; onSelect?: (event: Event) => void; textValue?: string; // used for typeahead; defaults to textContent } ``` Standard menu item. Fires `onSelect` on pointer-up or Enter/Space, then auto-closes the menu. Call `event.preventDefault()` in `onSelect` to prevent auto-close. --- ### DropdownMenuCheckboxItem ```ts interface DropdownMenuCheckboxItemProps extends PrimitiveDivProps { checked?: boolean | "indeterminate"; disabled?: boolean; onCheckedChange?: (checked: boolean) => void; onSelect?: (event: Event) => void; textValue?: string; } ``` Toggle item. `data-state="checked"` | `"unchecked"` | `"indeterminate"`. Does not auto-close by default when `onSelect` is not prevented call `event.preventDefault()` inside `onSelect` to keep menu open after toggle. --- ### DropdownMenuRadioGroup ```ts interface DropdownMenuRadioGroupProps extends PrimitiveDivProps { onValueChange?: (value: string) => void; value?: string; } ``` Groups `DropdownMenuRadioItem` elements. Manages a single selected value. --- ### DropdownMenuRadioItem ```ts interface DropdownMenuRadioItemProps extends PrimitiveDivProps { disabled?: boolean; onSelect?: (event: Event) => void; textValue?: string; value: string; // required } ``` Radio-style item. `data-state="checked"` | `"unchecked"`. Must be inside `DropdownMenuRadioGroup`. Fires `onValueChange` on the group when selected. --- ### DropdownMenuItemIndicator ```ts interface DropdownMenuItemIndicatorProps extends PrimitiveSpanProps { forceMount?: true; } ``` Renders only when the parent `CheckboxItem` or `RadioItem` is checked. By default unmounts when unchecked. Use `forceMount` to keep it mounted for exit animations. Style with `data-state="checked"` / `"unchecked"`. --- ## Structure ### DropdownMenuGroup ```ts interface DropdownMenuGroupProps extends PrimitiveDivProps {} ``` Semantic grouping container. Renders a `<div>` with no additional behavior. Use alongside `DropdownMenuLabel` to label a group. --- ### DropdownMenuLabel ```ts interface DropdownMenuLabelProps extends PrimitiveDivProps {} ``` Non-interactive label for a group. Not focusable, not selectable. --- ### DropdownMenuSeparator ```ts interface DropdownMenuSeparatorProps extends PrimitiveDivProps {} ``` Visual and semantic separator. Renders with `role="separator"`. --- ### DropdownMenuArrow ```ts interface DropdownMenuArrowProps extends PrimitiveSVGProps { height?: number; // default: 5 width?: number; // default: 10 } ``` SVG arrow pointing toward the trigger. Must be inside `DropdownMenuContent`. --- ## Submenus ### DropdownMenuSub ```ts interface DropdownMenuSubProps { children?: ReactNode; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; open?: boolean; } ``` Submenu root. Manages open state for the nested `DropdownMenuSubTrigger` + `DropdownMenuSubContent` pair. --- ### DropdownMenuSubTrigger ```ts interface DropdownMenuSubTriggerProps extends PrimitiveDivProps { disabled?: boolean; textValue?: string; } ``` Item that opens the submenu on pointer move or Enter/ArrowRight. Renders an arrow indicator automatically. Must be inside `DropdownMenuSub`. --- ### DropdownMenuSubContent ```ts interface DropdownMenuSubContentProps { // Same positioning/dismissal props as DropdownMenuContent avoidCollisions?: boolean; collisionBoundary?: Element | Element[] | null; collisionPadding?: number | Partial<Record<Side, number>>; forceMount?: true; hideWhenDetached?: boolean; loop?: boolean; onEscapeKeyDown?: (event: KeyboardEvent) => void; onFocusOutside?: (event: FocusOutsideEvent) => void; onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void; onPointerDownOutside?: (event: PointerDownOutsideEvent) => void; sticky?: "partial" | "always"; } ``` Content panel for the submenu. Wrap in `DropdownMenuPortal`. Sets the same `--loke-dropdown-menu-*` CSS custom properties as `DropdownMenuContent`. --- ## Scope utility ### createDropdownMenuScope ```ts function createDropdownMenuScope(): CreateScope; ``` For composing `DropdownMenu` inside other compound components. See the [context-and-collection](../../context-and-collection/SKILL.md) skill for scope threading patterns.