UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

146 lines (145 loc) 5.42 kB
"use client"; import { useProps } from "../../core/MantineProvider/use-props/use-props.mjs"; import { useStyles } from "../../core/styles-api/use-styles/use-styles.mjs"; import { factory } from "../../core/factory/factory.mjs"; import { Box } from "../../core/Box/Box.mjs"; import { MenubarContextProvider } from "./Menubar.context.mjs"; import { MenubarDropdown } from "./MenubarDropdown/MenubarDropdown.mjs"; import { MenubarMenu } from "./MenubarMenu/MenubarMenu.mjs"; import { MenubarTarget } from "./MenubarTarget/MenubarTarget.mjs"; import Menubar_module_default from "./Menubar.module.mjs"; import { useCallback, useRef, useState } from "react"; import { useId as useId$1, useIsomorphicEffect, useMergedRef, useUncontrolled } from "@mantine/hooks"; import { jsx } from "react/jsx-runtime"; //#region packages/@mantine/core/src/components/Menubar/Menubar.tsx const defaultProps = { trigger: "click", loop: true, position: "bottom-start" }; const Menubar = factory((_props) => { const props = useProps("Menubar", defaultProps, _props); const { classNames, className, style, styles, unstyled, vars, children, openIndex, defaultOpenIndex, onOpenChange, trigger, loop, position, attributes, mod, ref, ...others } = props; const getStyles = useStyles({ name: "Menubar", classes: Menubar_module_default, props, className, style, classNames, styles, unstyled, attributes }); const rootRef = useRef(null); const menubarId = useId$1(); const [_openIndex, setOpenIndex] = useUncontrolled({ value: openIndex, defaultValue: defaultOpenIndex, finalValue: null, onChange: onOpenChange }); const [activeIndex, setActiveIndex] = useState(0); const openSourceRef = useRef(null); const openMenu = useCallback((index, source) => { openSourceRef.current = source; setOpenIndex(index); }, [setOpenIndex]); const closeMenu = useCallback(() => { openSourceRef.current = null; setOpenIndex(null); }, [setOpenIndex]); const closeTimeoutRef = useRef(-1); const cancelClose = useCallback(() => { window.clearTimeout(closeTimeoutRef.current); }, []); const scheduleClose = useCallback(() => { window.clearTimeout(closeTimeoutRef.current); closeTimeoutRef.current = window.setTimeout(closeMenu, 120); }, [closeMenu]); useIsomorphicEffect(() => () => window.clearTimeout(closeTimeoutRef.current), []); const getOpenSource = useCallback(() => openSourceRef.current, []); const previousOpenIndexRef = useRef(_openIndex); const getPreviousOpenIndex = useCallback(() => previousOpenIndexRef.current, []); useIsomorphicEffect(() => { previousOpenIndexRef.current = _openIndex; }); const getTargets = useCallback(() => Array.from(rootRef.current?.querySelectorAll("[data-menubar-target]") ?? []), []); const getMenuIndex = useCallback((id) => getTargets().findIndex((node) => node.getAttribute("data-menubar-id") === id), [getTargets]); const getEnabledIndexes = useCallback(() => getTargets().reduce((acc, node, index) => { if (!node.disabled && !node.hasAttribute("data-disabled")) acc.push(index); return acc; }, []), [getTargets]); const focusTarget = useCallback((index) => { getTargets()[index]?.focus(); }, [getTargets]); const focusMenuItem = useCallback((index, itemPosition) => { window.setTimeout(() => { const controls = getTargets()[index]?.getAttribute("aria-controls"); const items = (controls ? document.getElementById(controls) : document.querySelector(`[data-menubar-dropdown="${menubarId}"]`))?.querySelectorAll("[data-menu-item]:not([data-disabled])"); if (items && items.length > 0) (itemPosition === "first" ? items[0] : items[items.length - 1])?.focus(); }, 40); }, [getTargets]); const getAdjacentIndex = useCallback((current, direction) => { const enabled = getEnabledIndexes(); if (enabled.length === 0) return current; const currentPosition = enabled.indexOf(current); let nextPosition = currentPosition === -1 ? 0 : currentPosition + direction; if (loop) nextPosition = (nextPosition + enabled.length) % enabled.length; else nextPosition = Math.max(0, Math.min(enabled.length - 1, nextPosition)); return enabled[nextPosition] ?? current; }, [getEnabledIndexes, loop]); useIsomorphicEffect(() => { const enabled = getEnabledIndexes(); if (enabled.length === 0) return; if (_openIndex !== null && enabled.includes(_openIndex)) { if (activeIndex !== _openIndex) setActiveIndex(_openIndex); return; } if (!enabled.includes(activeIndex)) setActiveIndex(enabled[0]); }); return /* @__PURE__ */ jsx(MenubarContextProvider, { value: { getStyles, id: menubarId, openIndex: _openIndex, setOpenIndex, openMenu, closeMenu, scheduleClose, cancelClose, getOpenSource, getPreviousOpenIndex, activeIndex, setActiveIndex, trigger, loop, position, unstyled, getMenuIndex, getTargets, getEnabledIndexes, getAdjacentIndex, focusTarget, focusMenuItem }, children: /* @__PURE__ */ jsx(Box, { ref: useMergedRef(ref, rootRef), role: "menubar", "aria-orientation": "horizontal", mod, ...getStyles("root"), ...others, "data-menubar": true, children }) }); }); Menubar.classes = Menubar_module_default; Menubar.displayName = "@mantine/core/Menubar"; Menubar.Menu = MenubarMenu; Menubar.Target = MenubarTarget; Menubar.Dropdown = MenubarDropdown; //#endregion export { Menubar }; //# sourceMappingURL=Menubar.mjs.map