{"version":3,"file":"Menubar.cjs","names":["factory","useProps","useStyles","MenubarContextProvider","Box","classes","MenubarMenu","MenubarTarget","MenubarDropdown"],"sources":["../../../src/components/Menubar/Menubar.tsx"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\nimport { useId, useIsomorphicEffect, useMergedRef, useUncontrolled } from '@mantine/hooks';\nimport {\n  Box,\n  BoxProps,\n  ElementProps,\n  factory,\n  Factory,\n  StylesApiProps,\n  useProps,\n  useStyles,\n} from '../../core';\nimport { FloatingPosition } from '../../utils/Floating';\nimport { MenubarContextProvider, type MenubarContextValue } from './Menubar.context';\nimport { MenubarDropdown, type MenubarDropdownProps } from './MenubarDropdown/MenubarDropdown';\nimport { MenubarMenu, type MenubarMenuProps } from './MenubarMenu/MenubarMenu';\nimport { MenubarTarget, type MenubarTargetProps } from './MenubarTarget/MenubarTarget';\nimport classes from './Menubar.module.css';\n\nexport type MenubarStylesNames = 'root' | 'target';\n\nexport type MenubarFactory = Factory<{\n  props: MenubarProps;\n  ref: HTMLDivElement;\n  stylesNames: MenubarStylesNames;\n  staticComponents: {\n    Menu: typeof MenubarMenu;\n    Target: typeof MenubarTarget;\n    Dropdown: typeof MenubarDropdown;\n  };\n}>;\n\nexport interface MenubarProps\n  extends BoxProps, StylesApiProps<MenubarFactory>, ElementProps<'div'> {\n  /** `Menubar.Menu` components */\n  children?: React.ReactNode;\n\n  /** Index of the controlled opened menu, `null` closes all menus */\n  openIndex?: number | null;\n\n  /** Index of the opened menu for uncontrolled component @default `null` */\n  defaultOpenIndex?: number | null;\n\n  /** Called when the opened menu changes with its index or `null` when all menus are closed */\n  onOpenChange?: (index: number | null) => void;\n\n  /** Event that opens a menu when none of the menus is opened. `'click'` opens a menu on target click and then switches menus on hover (desktop application pattern), `'hover'` opens a menu when the target is hovered @default `'click'` */\n  trigger?: 'click' | 'hover';\n\n  /** If set, arrow key navigation wraps from last to first menu and vice versa @default `true` */\n  loop?: boolean;\n\n  /** Dropdown position relative to the target element @default `'bottom-start'` */\n  position?: FloatingPosition;\n}\n\nconst defaultProps = {\n  trigger: 'click',\n  loop: true,\n  position: 'bottom-start',\n} satisfies Partial<MenubarProps>;\n\nexport const Menubar = factory<MenubarFactory>((_props) => {\n  const props = useProps('Menubar', defaultProps, _props);\n  const {\n    classNames,\n    className,\n    style,\n    styles,\n    unstyled,\n    vars,\n    children,\n    openIndex,\n    defaultOpenIndex,\n    onOpenChange,\n    trigger,\n    loop,\n    position,\n    attributes,\n    mod,\n    ref,\n    ...others\n  } = props;\n\n  const getStyles = useStyles<MenubarFactory>({\n    name: 'Menubar',\n    classes,\n    props,\n    className,\n    style,\n    classNames,\n    styles,\n    unstyled,\n    attributes,\n  });\n\n  const rootRef = useRef<HTMLDivElement>(null);\n  const menubarId = useId();\n\n  const [_openIndex, setOpenIndex] = useUncontrolled<number | null>({\n    value: openIndex,\n    defaultValue: defaultOpenIndex,\n    finalValue: null,\n    onChange: onOpenChange,\n  });\n\n  const [activeIndex, setActiveIndex] = useState(0);\n  const openSourceRef = useRef<'click' | 'hover' | null>(null);\n\n  const openMenu = useCallback(\n    (index: number, source: 'click' | 'hover') => {\n      openSourceRef.current = source;\n      setOpenIndex(index);\n    },\n    [setOpenIndex]\n  );\n\n  const closeMenu = useCallback(() => {\n    openSourceRef.current = null;\n    setOpenIndex(null);\n  }, [setOpenIndex]);\n\n  const closeTimeoutRef = useRef(-1);\n\n  const cancelClose = useCallback(() => {\n    window.clearTimeout(closeTimeoutRef.current);\n  }, []);\n\n  const scheduleClose = useCallback(() => {\n    window.clearTimeout(closeTimeoutRef.current);\n    closeTimeoutRef.current = window.setTimeout(closeMenu, 120);\n  }, [closeMenu]);\n\n  useIsomorphicEffect(() => () => window.clearTimeout(closeTimeoutRef.current), []);\n\n  const getOpenSource = useCallback(() => openSourceRef.current, []);\n\n  const previousOpenIndexRef = useRef<number | null>(_openIndex);\n  const getPreviousOpenIndex = useCallback(() => previousOpenIndexRef.current, []);\n\n  useIsomorphicEffect(() => {\n    previousOpenIndexRef.current = _openIndex;\n  });\n\n  const getTargets = useCallback(\n    () =>\n      Array.from(\n        rootRef.current?.querySelectorAll<HTMLButtonElement>('[data-menubar-target]') ?? []\n      ),\n    []\n  );\n\n  const getMenuIndex = useCallback(\n    (id: string) => getTargets().findIndex((node) => node.getAttribute('data-menubar-id') === id),\n    [getTargets]\n  );\n\n  const getEnabledIndexes = useCallback(\n    () =>\n      getTargets().reduce<number[]>((acc, node, index) => {\n        if (!node.disabled && !node.hasAttribute('data-disabled')) {\n          acc.push(index);\n        }\n        return acc;\n      }, []),\n    [getTargets]\n  );\n\n  const focusTarget = useCallback(\n    (index: number) => {\n      getTargets()[index]?.focus();\n    },\n    [getTargets]\n  );\n\n  const focusMenuItem = useCallback(\n    (index: number, itemPosition: 'first' | 'last') => {\n      window.setTimeout(() => {\n        const target = getTargets()[index];\n        const controls = target?.getAttribute('aria-controls');\n        const dropdown = controls\n          ? document.getElementById(controls)\n          : document.querySelector<HTMLElement>(`[data-menubar-dropdown=\"${menubarId}\"]`);\n        const items = dropdown?.querySelectorAll<HTMLElement>(\n          '[data-menu-item]:not([data-disabled])'\n        );\n\n        if (items && items.length > 0) {\n          const item = itemPosition === 'first' ? items[0] : items[items.length - 1];\n          item?.focus();\n        }\n      }, 40);\n    },\n    [getTargets]\n  );\n\n  const getAdjacentIndex = useCallback(\n    (current: number, direction: 1 | -1) => {\n      const enabled = getEnabledIndexes();\n\n      if (enabled.length === 0) {\n        return current;\n      }\n\n      const currentPosition = enabled.indexOf(current);\n      let nextPosition = currentPosition === -1 ? 0 : currentPosition + direction;\n\n      if (loop) {\n        nextPosition = (nextPosition + enabled.length) % enabled.length;\n      } else {\n        nextPosition = Math.max(0, Math.min(enabled.length - 1, nextPosition));\n      }\n\n      return enabled[nextPosition] ?? current;\n    },\n    [getEnabledIndexes, loop]\n  );\n\n  useIsomorphicEffect(() => {\n    const enabled = getEnabledIndexes();\n    if (enabled.length === 0) {\n      return;\n    }\n\n    // While a menu is open, the single tab stop must stay on the opened menu's target,\n    // including when it was opened programmatically via openIndex/defaultOpenIndex.\n    if (_openIndex !== null && enabled.includes(_openIndex)) {\n      if (activeIndex !== _openIndex) {\n        setActiveIndex(_openIndex);\n      }\n      return;\n    }\n\n    if (!enabled.includes(activeIndex)) {\n      setActiveIndex(enabled[0]);\n    }\n  });\n\n  const contextValue: MenubarContextValue = {\n    getStyles,\n    id: menubarId,\n    openIndex: _openIndex,\n    setOpenIndex,\n    openMenu,\n    closeMenu,\n    scheduleClose,\n    cancelClose,\n    getOpenSource,\n    getPreviousOpenIndex,\n    activeIndex,\n    setActiveIndex,\n    trigger: trigger!,\n    loop: loop!,\n    position: position!,\n    unstyled,\n    getMenuIndex,\n    getTargets,\n    getEnabledIndexes,\n    getAdjacentIndex,\n    focusTarget,\n    focusMenuItem,\n  };\n\n  return (\n    <MenubarContextProvider value={contextValue}>\n      <Box\n        ref={useMergedRef(ref, rootRef)}\n        role=\"menubar\"\n        aria-orientation=\"horizontal\"\n        mod={mod}\n        {...getStyles('root')}\n        {...others}\n        data-menubar\n      >\n        {children}\n      </Box>\n    </MenubarContextProvider>\n  );\n});\n\nMenubar.classes = classes;\nMenubar.displayName = '@mantine/core/Menubar';\nMenubar.Menu = MenubarMenu;\nMenubar.Target = MenubarTarget;\nMenubar.Dropdown = MenubarDropdown;\n\nexport namespace Menubar {\n  export type Props = MenubarProps;\n  export type StylesNames = MenubarStylesNames;\n  export type Factory = MenubarFactory;\n\n  export namespace Menu {\n    export type Props = MenubarMenuProps;\n  }\n\n  export namespace Target {\n    export type Props = MenubarTargetProps;\n  }\n\n  export namespace Dropdown {\n    export type Props = MenubarDropdownProps;\n  }\n}\n"],"mappings":"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"}