@mantine/core
Version:
React components library focused on usability, accessibility and developer experience
146 lines (145 loc) • 5.42 kB
JavaScript
"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