@ariakit/react-core
Version:
Ariakit React core
141 lines (138 loc) • 4.29 kB
JavaScript
"use client";
import {
useMenuScopedContext
} from "./SPU3NB66.js";
import {
useMenubarScopedContext
} from "./TGNQMQ45.js";
import {
useCompositeHover
} from "./RIJYZEV5.js";
import {
useCompositeItem
} from "./FIT2LC3L.js";
import {
useStoreState
} from "./Q3KUZPD7.js";
import {
createElement,
createHook,
forwardRef,
memo
} from "./ILRXHV7V.js";
import {
useBooleanEvent,
useEvent
} from "./K2XTQB3X.js";
// src/menu/menu-item.tsx
import { getDocument, getPopupItemRole } from "@ariakit/core/utils/dom";
import { isDownloading, isOpeningInNewTab } from "@ariakit/core/utils/events";
import { hasFocusWithin } from "@ariakit/core/utils/focus";
import { invariant } from "@ariakit/core/utils/misc";
var TagName = "div";
function menuHasFocus(baseElement, items, currentTarget) {
var _a;
if (!baseElement) return false;
if (hasFocusWithin(baseElement)) return true;
const expandedItem = items == null ? void 0 : items.find((item) => {
var _a2;
if (item.element === currentTarget) return false;
return ((_a2 = item.element) == null ? void 0 : _a2.getAttribute("aria-expanded")) === "true";
});
const expandedMenuId = (_a = expandedItem == null ? void 0 : expandedItem.element) == null ? void 0 : _a.getAttribute("aria-controls");
if (!expandedMenuId) return false;
const doc = getDocument(baseElement);
const expandedMenu = doc.getElementById(expandedMenuId);
if (!expandedMenu) return false;
if (hasFocusWithin(expandedMenu)) return true;
return !!expandedMenu.querySelector("[role=menuitem][aria-expanded=true]");
}
var useMenuItem = createHook(
function useMenuItem2({
store,
hideOnClick = true,
preventScrollOnKeyDown = true,
focusOnHover,
blurOnHoverEnd,
...props
}) {
const menuContext = useMenuScopedContext(true);
const menubarContext = useMenubarScopedContext();
store = store || menuContext || menubarContext;
invariant(
store,
process.env.NODE_ENV !== "production" && "MenuItem must be wrapped in a MenuList, Menu or Menubar component"
);
const onClickProp = props.onClick;
const hideOnClickProp = useBooleanEvent(hideOnClick);
const hideMenu = "hideAll" in store ? store.hideAll : void 0;
const isWithinMenu = !!hideMenu;
const onClick = useEvent((event) => {
onClickProp == null ? void 0 : onClickProp(event);
if (event.defaultPrevented) return;
if (isDownloading(event)) return;
if (isOpeningInNewTab(event)) return;
if (!hideMenu) return;
const popupType = event.currentTarget.getAttribute("aria-haspopup");
if (popupType === "menu") return;
if (!hideOnClickProp(event)) return;
hideMenu();
});
const contentElement = useStoreState(
store,
(state) => "contentElement" in state ? state.contentElement : null
);
const role = getPopupItemRole(contentElement, "menuitem");
props = {
role,
...props,
onClick
};
props = useCompositeItem({
store,
preventScrollOnKeyDown,
...props
});
props = useCompositeHover({
store,
...props,
focusOnHover(event) {
const getFocusOnHover = () => {
if (typeof focusOnHover === "function") return focusOnHover(event);
if (focusOnHover != null) return focusOnHover;
return true;
};
if (!store) return false;
if (!getFocusOnHover()) return false;
const { baseElement, items } = store.getState();
if (isWithinMenu) {
if (event.currentTarget.hasAttribute("aria-expanded")) {
event.currentTarget.focus();
}
return true;
}
if (menuHasFocus(baseElement, items, event.currentTarget)) {
event.currentTarget.focus();
return true;
}
return false;
},
blurOnHoverEnd(event) {
if (typeof blurOnHoverEnd === "function") return blurOnHoverEnd(event);
if (blurOnHoverEnd != null) return blurOnHoverEnd;
return isWithinMenu;
}
});
return props;
}
);
var MenuItem = memo(
forwardRef(function MenuItem2(props) {
const htmlProps = useMenuItem(props);
return createElement(TagName, htmlProps);
})
);
export {
useMenuItem,
MenuItem
};