@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
69 lines (66 loc) • 2.79 kB
JavaScript
'use client';
import { useIsClient } from "../hooks/useIsClient.mjs";
import { LOBE_THEME_APP_ID } from "../ThemeProvider/constants.mjs";
import { preventDefaultAndStopPropagation } from "../utils/dom.mjs";
import { styles } from "../Menu/sharedStyle.mjs";
import { usePortalContainer } from "../hooks/usePortalContainer.mjs";
import { registerDevSingleton } from "../utils/devSingleton.mjs";
import { renderContextMenuItems } from "./renderItems.mjs";
import { closeContextMenu, getServerSnapshot, getSnapshot, setContextMenuState, subscribe, updateLastPointer } from "./store.mjs";
import { memo, useEffect, useMemo, useSyncExternalStore } from "react";
import { jsx } from "react/jsx-runtime";
import { ContextMenu } from "@base-ui/react/context-menu";
//#region src/ContextMenu/ContextMenuHost.tsx
const CONTEXT_MENU_CONTAINER_ATTR = "data-lobe-ui-context-menu-container";
const ContextMenuHost = memo(() => {
const isClient = useIsClient();
const state = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
useEffect(() => {
const DEV = process.env.NODE_ENV === "development";
if (!isClient || !DEV) return;
const themeApp = document.querySelector(`#${LOBE_THEME_APP_ID}`);
const contextMenuContainer = document.querySelector(`[${CONTEXT_MENU_CONTAINER_ATTR}="true"]`);
return registerDevSingleton("ContextMenuHost", themeApp ?? contextMenuContainer ?? document.body);
}, [isClient]);
useEffect(() => {
const handler = (event) => updateLastPointer(event);
window.addEventListener("pointerdown", handler, true);
window.addEventListener("contextmenu", handler, true);
return () => {
window.removeEventListener("pointerdown", handler, true);
window.removeEventListener("contextmenu", handler, true);
};
}, []);
const menuItems = useMemo(() => renderContextMenuItems(state.items), [state.items]);
const portalContainer = usePortalContainer(CONTEXT_MENU_CONTAINER_ATTR);
if (!isClient) return null;
if (!state.open && state.items.length === 0) return null;
if (!portalContainer) return null;
return /* @__PURE__ */ jsx(ContextMenu.Root, {
onOpenChange: (open) => {
if (open) {
setContextMenuState({ open });
return;
}
closeContextMenu();
},
open: state.open,
children: /* @__PURE__ */ jsx(ContextMenu.Portal, {
container: portalContainer,
children: /* @__PURE__ */ jsx(ContextMenu.Positioner, {
anchor: state.anchor ?? void 0,
className: styles.positioner,
sideOffset: 6,
children: /* @__PURE__ */ jsx(ContextMenu.Popup, {
className: styles.popup,
onContextMenu: preventDefaultAndStopPropagation,
children: menuItems
})
})
})
});
});
ContextMenuHost.displayName = "ContextMenuHost";
//#endregion
export { ContextMenuHost };
//# sourceMappingURL=ContextMenuHost.mjs.map