@yamada-ui/menu
Version:
Yamada UI menu component
166 lines (164 loc) • 5.21 kB
JavaScript
"use client"
import {
DescendantsContextProvider,
MenuProvider,
UpstreamMenuProvider,
useContextMenu,
useDescendants,
useUpstreamMenu,
useUpstreamMenuItem
} from "./chunk-IWH3B4PS.mjs";
// src/menu.tsx
import { omitThemeProps, useComponentMultiStyle } from "@yamada-ui/core";
import { Popover } from "@yamada-ui/popover";
import { useDisclosure } from "@yamada-ui/use-disclosure";
import { funcAll, useUnmountEffect, useUpdateEffect } from "@yamada-ui/utils";
import { useCallback, useEffect, useId, useRef, useState } from "react";
import { jsx } from "react/jsx-runtime";
var Menu = (props) => {
var _a, _b, _c;
const { styles: contextMenuStyles } = (_a = useContextMenu()) != null ? _a : {};
const [styles, mergedProps] = useComponentMultiStyle("Menu", props, {
isProcessSkip: !!contextMenuStyles,
styles: contextMenuStyles
});
const { relatedRef, onDownstreamCloseMapRef, onUpstreamClose } = (_b = useUpstreamMenu()) != null ? _b : {};
const nested = !!relatedRef;
const {
closeOnBlur = !nested,
closeOnSelect = true,
duration = 0.2,
initialFocusRef,
offset = nested ? [-8, 8] : void 0,
placement = nested ? "right-start" : "bottom-start",
onClose: onCloseProp,
onOpen: onOpenProp,
...rest
} = omitThemeProps(mergedProps);
const { hasDownstreamRef, setDownstreamOpen } = (_c = useUpstreamMenuItem()) != null ? _c : {};
const descendants = useDescendants();
const [focusedIndex, setFocusedIndex] = useState(-1);
const menuRef = useRef(null);
const buttonRef = useRef(null);
const timeoutIds = useRef(/* @__PURE__ */ new Set([]));
const requestAnimationFrameId = useRef(null);
const onCloseMapRef = useRef(/* @__PURE__ */ new Map());
const onFocusMenu = useCallback(() => {
requestAnimationFrame(
() => {
var _a2;
return (_a2 = menuRef.current) == null ? void 0 : _a2.focus({ preventScroll: false });
}
);
}, []);
const onFocusFirstItem = useCallback(() => {
const id2 = setTimeout(() => {
if (initialFocusRef) return;
const first = descendants.enabledFirstValue();
if (first) setFocusedIndex(first.index);
});
timeoutIds.current.add(id2);
}, [descendants, initialFocusRef]);
const onFocusLastItem = useCallback(() => {
const id2 = setTimeout(() => {
if (initialFocusRef) return;
const last = descendants.enabledLastValue();
if (last) setFocusedIndex(last.index);
});
timeoutIds.current.add(id2);
}, [descendants, initialFocusRef]);
const onOpenInternal = useCallback(() => {
onOpenProp == null ? void 0 : onOpenProp();
if (!nested) onFocusMenu();
}, [onOpenProp, nested, onFocusMenu]);
const onCloseInternal = useCallback(() => {
onCloseProp == null ? void 0 : onCloseProp();
for (const onClose2 of onCloseMapRef.current.values()) {
onClose2();
}
}, [onCloseProp]);
const id = useId();
const { open, onClose, onOpen } = useDisclosure({
...props,
onClose: onCloseInternal,
onOpen: onOpenInternal
});
useEffect(() => {
const onCloseMap = onDownstreamCloseMapRef == null ? void 0 : onDownstreamCloseMapRef.current;
onCloseMap == null ? void 0 : onCloseMap.set(id, onClose);
return () => {
onCloseMap == null ? void 0 : onCloseMap.delete(id);
};
}, [id, onClose, onDownstreamCloseMapRef]);
useEffect(() => {
if (setDownstreamOpen) setDownstreamOpen(open);
}, [setDownstreamOpen, open]);
useEffect(() => {
if (hasDownstreamRef) hasDownstreamRef.current = true;
return () => {
if (hasDownstreamRef) hasDownstreamRef.current = false;
};
});
useUpdateEffect(() => {
if (!open) setFocusedIndex(-1);
}, [open]);
useUnmountEffect(() => {
timeoutIds.current.forEach((id2) => clearTimeout(id2));
timeoutIds.current.clear();
});
return /* @__PURE__ */ jsx(DescendantsContextProvider, { value: descendants, children: /* @__PURE__ */ jsx(
UpstreamMenuProvider,
{
value: {
relatedRef: menuRef,
onDownstreamCloseMapRef: onCloseMapRef,
onUpstreamClose: funcAll(onUpstreamClose, onClose)
},
children: /* @__PURE__ */ jsx(
MenuProvider,
{
value: {
buttonRef,
closeOnSelect,
focusedIndex,
menuRef,
nested,
open,
requestAnimationFrameId,
setFocusedIndex,
styles,
onClose,
onFocusFirstItem,
onFocusLastItem,
onOpen,
onUpstreamClose
},
children: /* @__PURE__ */ jsx(
Popover,
{
...{
trigger: nested ? "hover" : "click",
...rest,
closeOnBlur,
closeOnButton: false,
duration,
initialFocusRef,
offset,
open,
placement,
relatedRef,
onClose,
onOpen
}
}
)
}
)
}
) });
};
Menu.__ui__ = "Menu";
export {
Menu
};
//# sourceMappingURL=chunk-BIEYDHFO.mjs.map