{"version":3,"file":"menu.mjs","names":[],"sources":["../../../../package/common/menu/menu.tsx"],"sourcesContent":["import { cloneElement, isValidElement, useEffect, useId, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\n\nimport styles from './menu.module.pcss';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { isSelfActivation } from '../utils/activationKey';\nimport { useLinkClick } from '../utils/navigation';\nimport { useFocusBoundary } from '../hooks/useFocusBoundary';\nimport { ariaKeyshortcuts, formatHotkey } from '../hooks/useHotkeys';\nimport { isMenuAction, isMenuHeading, isMenuSeparator, type MenuEntry, type MenuProps } from './menu.types';\nimport { hasAnyIcon, renderItemIcon } from './menuItem';\n\n/** How long a typed run stays one search before it starts over. */\nconst TYPEAHEAD_RESET_MS = 600;\n\n/** Index of the next action that can be focused, wrapping, or -1 if there is none. */\nfunction nextEnabled(items: MenuEntry[], from: number, step: 1 | -1): number {\n  for (let i = 1; i <= items.length; i++) {\n    // The `items.length * i` term only keeps the value positive for a backwards\n    // step; JavaScript's `%` would otherwise return a negative index.\n    const index = (from + step * i + items.length * i) % items.length;\n    const entry = items[index];\n    if (isMenuAction(entry) && !entry.disabled) return index;\n  }\n  return -1;\n}\n\nfunction firstEnabled(items: MenuEntry[]): number {\n  return items.findIndex((entry) => isMenuAction(entry) && !entry.disabled);\n}\n\nfunction lastEnabled(items: MenuEntry[]): number {\n  for (let i = items.length - 1; i >= 0; i--) {\n    const entry = items[i];\n    if (isMenuAction(entry) && !entry.disabled) return i;\n  }\n  return -1;\n}\n\n/**\n * A menu of actions on a trigger of your choosing.\n *\n * `Popover` does the anchoring, portalling and outside-click work but takes\n * arbitrary `content`, which leaves every consumer to write their own `ul`/`li`\n * and, in practice, to leave out the roles and the arrow keys. This is that list,\n * done once: `role=\"menu\"`, a roving focus that skips disabled entries, Escape\n * back to the trigger, and separators and headings that stay out of the keyboard\n * order.\n */\nfunction Menu({\n  items,\n  children,\n  onAction,\n  isOpen: controlledOpen,\n  onOpenChange,\n  placement = PopoverPlacement.Bottom,\n  align = PopoverAlign.Start,\n  presentation,\n  className,\n  style,\n  classNames,\n  styles: slotStyles,\n  ...rest\n}: MenuProps): ReactElement {\n  const isControlled = controlledOpen !== undefined;\n  const [internalOpen, setInternalOpen] = useState(false);\n  const isOpen = isControlled ? controlledOpen : internalOpen;\n\n  const [activeIndex, setActiveIndex] = useState(-1);\n  const itemRefs = useRef<(HTMLElement | null)[]>([]);\n  const triggerRef = useRef<HTMLSpanElement>(null);\n  const menuRef = useRef<HTMLDivElement>(null);\n  // Tab leaves the panel in both directions, so the menu needs the same boundary\n  // Popover uses: back to the trigger, or on to whatever follows it.\n  const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({ triggerRef, contentRef: menuRef });\n  const menuId = useId();\n  const followLink = useLinkClick();\n  // Which end to land on when the menu opens: `ArrowUp` on the trigger opens at\n  // the bottom, everything else at the top.\n  const openAtRef = useRef<'first' | 'last'>('first');\n  const typeahead = useRef<{ query: string; timer: ReturnType<typeof setTimeout> | undefined }>({\n    query: '',\n    timer: undefined,\n  });\n\n  // Whether a key opened the menu, which decides between landing the focus on an\n  // entry and leaving it on the trigger. Set from Popover, which is what sees the\n  // trigger's events, or here when an arrow key did the opening.\n  const openedByKeyboardRef = useRef(false);\n\n  function setOpen(next: boolean, fromKeyboard = false) {\n    if (next) openedByKeyboardRef.current = fromKeyboard;\n    if (!isControlled) setInternalOpen(next);\n    onOpenChange?.(next);\n  }\n\n  // The effect below needs the entries, but must not re-run when the array is rebuilt. A consumer\n  // writes `items={[…]}` inline, so it is a new identity on every render of *their* component:\n  // keyed off it, any parent re-render while the menu was open threw the focus back to the first\n  // entry, mid-navigation. Declared above the effect that reads it, so it has already run.\n  const itemsRef = useRef(items);\n  useEffect(() => {\n    itemsRef.current = items;\n  });\n\n  // Focus follows the active entry rather than the menu keeping focus and\n  // pointing at it: the items are real buttons, so Enter and Space are theirs.\n  // Popover's own `focusOnOpen` would take the first focusable and stop there;\n  // the active index has to move with it, so the menu does it itself.\n  useEffect(() => {\n    if (!isOpen) return;\n    // A pointer open leaves the focus where the pointer put it. A highlight on an\n    // entry nobody pointed at reads as a selection, and the mouse is about to land\n    // somewhere else anyway; the first arrow key moves in, see the trigger's keys.\n    if (!openedByKeyboardRef.current) {\n      setActiveIndex(-1);\n      return;\n    }\n    const entries = itemsRef.current;\n    const target = openAtRef.current === 'last' ? lastEnabled(entries) : firstEnabled(entries);\n    setActiveIndex(target);\n    // The panel is portalled and animated in, so its buttons exist a frame later.\n    const frame = requestAnimationFrame(() => {\n      itemRefs.current[target]?.focus();\n    });\n    return () => {\n      cancelAnimationFrame(frame);\n      openAtRef.current = 'first';\n    };\n  }, [isOpen]);\n\n  useEffect(() => () => clearTimeout(typeahead.current.timer), []);\n\n  function moveTo(index: number) {\n    if (index < 0) return;\n    setActiveIndex(index);\n    itemRefs.current[index]?.focus();\n  }\n\n  function close(returnFocus: boolean) {\n    setOpen(false);\n    if (returnFocus) restoreFocusToTrigger();\n  }\n\n  /**\n   * Jumps to the next entry whose label starts with what has been typed. The\n   * text comes off the rendered button rather than the `label` prop, which is a\n   * `ReactNode` and may be an icon, a badge or anything else.\n   */\n  function handleTypeahead(key: string): boolean {\n    if (key.length !== 1 || !key.trim()) return false;\n    clearTimeout(typeahead.current.timer);\n    typeahead.current.query += key.toLowerCase();\n    typeahead.current.timer = setTimeout(() => {\n      typeahead.current.query = '';\n    }, TYPEAHEAD_RESET_MS);\n\n    const query = typeahead.current.query;\n    // A repeated single character walks through the entries starting with it,\n    // rather than sticking to the first one.\n    const repeated = query.length > 1 && [...query].every((c) => c === query[0]);\n    const needle = repeated ? query[0] : query;\n    const from = repeated || query.length === 1 ? activeIndex : activeIndex - 1;\n\n    for (let i = 1; i <= items.length; i++) {\n      const index = (from + i + items.length) % items.length;\n      const entry = items[index];\n      if (!isMenuAction(entry) || entry.disabled) continue;\n      const text = itemRefs.current[index]?.textContent?.trim().toLowerCase() ?? '';\n      if (text.startsWith(needle)) {\n        moveTo(index);\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /** The trigger's own keys, which decide where the menu opens. */\n  function handleTriggerKeyDown(event: React.KeyboardEvent) {\n    if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n    // Popover opens on these keys too; letting both act would be harmless but\n    // this keeps the decision about where to land in one place.\n    event.preventDefault();\n    event.stopPropagation();\n    // Already open means a pointer opened it and the focus never left the trigger,\n    // since an entry's own keys never reach here. This is the key that moves in.\n    if (isOpen) {\n      moveTo(event.key === 'ArrowUp' ? lastEnabled(items) : firstEnabled(items));\n      return;\n    }\n    openAtRef.current = event.key === 'ArrowUp' ? 'last' : 'first';\n    setOpen(true, true);\n  }\n\n  function handleKeyDown(event: React.KeyboardEvent) {\n    switch (event.key) {\n      case 'ArrowDown':\n        moveTo(nextEnabled(items, activeIndex, 1));\n        break;\n      case 'ArrowUp':\n        // Stepping back from \"nothing active\" lands two short of the end, so the end is named.\n        moveTo(activeIndex < 0 ? lastEnabled(items) : nextEnabled(items, activeIndex, -1));\n        break;\n      case 'Home':\n        moveTo(firstEnabled(items));\n        break;\n      case 'End':\n        moveTo(lastEnabled(items));\n        break;\n      // Popover handles both of these too, but only once the focus has actually\n      // reached the panel: its Escape restores focus on that condition, and its\n      // Tab handling acts at the first and last focusable. A menu focuses its\n      // first entry a frame after opening, so a key pressed in between would\n      // fall through. Here they are unconditional, which is also what a menu\n      // wants from Tab: leave, whatever is focused.\n      case 'Escape':\n        close(true);\n        break;\n      case 'Tab':\n        // Carry on from the trigger, as if the panel had never been in the tab\n        // order. Closing and letting the browser take it from here would move on\n        // from an entry that is about to be removed, which lands at the top of\n        // the document.\n        close(false);\n        if (event.shiftKey) restoreFocusToTrigger();\n        else focusAfterTrigger();\n        break;\n      default:\n        if (!handleTypeahead(event.key)) return;\n    }\n    event.preventDefault();\n    event.stopPropagation();\n  }\n\n  function handleAction(index: number) {\n    const entry = items[index];\n    if (!isMenuAction(entry) || entry.disabled) return;\n    // Not runMenuAction: a link entry is an <a>, which the browser follows by itself.\n    entry.onClick?.();\n    onAction?.(entry.id);\n    close(true);\n  }\n\n  // A screen reader has no way to tell that this button opens a menu unless the\n  // button itself says so. Only filled in where the consumer has not, so a\n  // trigger that describes itself keeps doing that.\n  const triggerWithMenuSemantics = isValidElement<Record<string, unknown>>(children)\n    ? cloneElement(children, {\n        'aria-haspopup': children.props['aria-haspopup'] ?? 'menu',\n        'aria-expanded': children.props['aria-expanded'] ?? isOpen,\n        'aria-controls': isOpen ? (children.props['aria-controls'] ?? menuId) : children.props['aria-controls'],\n      })\n    : children;\n\n  const hasIcons = hasAnyIcon(items);\n\n  const content = (\n    <div\n      ref={menuRef}\n      id={menuId}\n      role='menu'\n      className={cx(styles.menu, classNames?.menu)}\n      style={slotStyles?.menu}\n      onKeyDown={handleKeyDown}\n    >\n      {items.map((entry, index) => {\n        if (isMenuSeparator(entry))\n          return (\n            <div\n              // Separators and headings carry no id of their own, and reordering\n              // the list re-renders it wholesale anyway.\n              key={`separator-${index}`}\n              role='separator'\n              className={cx(styles.menuSeparator, classNames?.separator)}\n              style={slotStyles?.separator}\n            />\n          );\n\n        if (isMenuHeading(entry))\n          return (\n            <div\n              key={`heading-${index}`}\n              role='presentation'\n              className={cx(styles.menuHeading, classNames?.heading)}\n              style={slotStyles?.heading}\n            >\n              {entry.heading}\n            </div>\n          );\n\n        const itemProps = {\n          ref: (el: HTMLElement | null) => {\n            itemRefs.current[index] = el;\n          },\n          role: 'menuitem',\n          'aria-keyshortcuts': ariaKeyshortcuts(entry.shortcut),\n          // One tab stop for the whole menu: the arrow keys move between items.\n          tabIndex: index === activeIndex ? 0 : -1,\n          className: cx(styles.menuItem, entry.danger && styles.menuItemDanger, classNames?.item),\n          style: slotStyles?.item,\n          onClick: () => handleAction(index),\n          onMouseEnter: () => setActiveIndex(index),\n        };\n        const itemContent = (\n          <>\n            {renderItemIcon(entry.icon, hasIcons, {\n              className: cx(styles.menuItemIcon, classNames?.itemIcon),\n              style: slotStyles?.itemIcon,\n            })}\n            <span className={cx(styles.menuItemLabel, classNames?.itemLabel)} style={slotStyles?.itemLabel}>\n              {entry.label}\n            </span>\n            {entry.shortcut != null && (\n              <span\n                aria-hidden\n                className={cx(styles.menuItemShortcut, classNames?.itemShortcut)}\n                style={slotStyles?.itemShortcut}\n              >\n                {formatHotkey(entry.shortcut)}\n              </span>\n            )}\n          </>\n        );\n\n        // An <a> cannot be disabled, so a disabled link is a disabled button.\n        return entry.href && !entry.disabled ? (\n          <a\n            key={entry.id}\n            href={entry.href}\n            {...itemProps}\n            onClick={(event) => {\n              handleAction(index);\n              followLink(event);\n            }}\n            // A link takes Enter but not Space, which every other entry answers to.\n            onKeyDown={(event) => {\n              if (event.key !== ' ' || !isSelfActivation(event)) return;\n              event.preventDefault();\n              event.currentTarget.click();\n            }}\n          >\n            {itemContent}\n          </a>\n        ) : (\n          <button key={entry.id} type='button' disabled={entry.disabled} {...itemProps}>\n            {itemContent}\n          </button>\n        );\n      })}\n    </div>\n  );\n\n  return (\n    <Popover\n      {...rest}\n      isOpen={isOpen}\n      onOpenChange={(next, { fromKeyboard }) => setOpen(next, fromKeyboard)}\n      placement={placement}\n      align={align}\n      presentation={presentation}\n      content={content}\n      // The list pads its own rows, so a hover highlight reaches the panel edge,\n      // and it sizes itself. Focus is the menu's own business, see above.\n      focusOnOpen={false}\n      constrainWidth={false}\n      classNames={{ panel: styles.menuPanel }}\n      className={cx(className, classNames?.root)}\n      style={{ ...style, ...slotStyles?.root }}\n    >\n      <span\n        ref={triggerRef}\n        className={cx(styles.menuTrigger, classNames?.trigger)}\n        style={slotStyles?.trigger}\n        onKeyDown={handleTriggerKeyDown}\n      >\n        {triggerWithMenuSemantics}\n      </span>\n    </Popover>\n  );\n}\n\nexport default Menu;\n"],"mappings":"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"}