UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

102 lines (99 loc) 4.27 kB
'use client'; import { useNativeButton } from "../hooks/useNativeButton.mjs"; import { placementMap } from "../utils/placement.mjs"; import { CLASSNAMES } from "../styles/classNames.mjs"; import { styles } from "../Menu/sharedStyle.mjs"; import { usePortalContainer } from "../hooks/usePortalContainer.mjs"; import { renderDropdownMenuItems } from "./renderItems.mjs"; import { cloneElement, isValidElement, memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; import { cx } from "antd-style"; import { mergeProps } from "@base-ui/react/merge-props"; import { Menu } from "@base-ui/react/menu"; import clsx from "clsx"; //#region src/DropdownMenu/DropdownMenu.tsx const DROPDOWN_MENU_CONTAINER_ATTR = "data-lobe-ui-dropdown-menu-container"; const DropdownMenu = memo(({ children, defaultOpen, items, nativeButton, onOpenChange, onOpenChangeComplete, open, placement = "bottomLeft", popupProps, portalProps, positionerProps, triggerProps, ...rest }) => { const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen)); useEffect(() => { if (open === void 0) return; setUncontrolledOpen(open); }, [open]); const handleOpenChange = useCallback((nextOpen, details) => { onOpenChange?.(nextOpen, details); if (open === void 0) setUncontrolledOpen(nextOpen); }, [onOpenChange, open]); const menuItemsRef = useRef(null); const isOpen = open ?? uncontrolledOpen; const menuItems = useMemo(() => { if (isOpen) { const renderedItems = renderDropdownMenuItems(typeof items === "function" ? items() : items); menuItemsRef.current = renderedItems; return renderedItems; } return menuItemsRef.current; }, [isOpen, items]); const handleOpenChangeComplete = useCallback((nextOpen) => { onOpenChangeComplete?.(nextOpen); if (!nextOpen) menuItemsRef.current = null; }, [onOpenChangeComplete]); const portalContainer = usePortalContainer(DROPDOWN_MENU_CONTAINER_ATTR); const placementConfig = placementMap[placement]; const hoverTrigger = Boolean(triggerProps?.openOnHover); const { isNativeButtonTriggerElement, resolvedNativeButton } = useNativeButton({ children, nativeButton, triggerNativeButton: triggerProps?.nativeButton }); const renderer = useCallback((props) => { const resolvedProps = (() => { if (isNativeButtonTriggerElement) return props; const { type, ...restProps } = props; return restProps; })(); return cloneElement(children, mergeProps(children.props, resolvedProps)); }, [children, isNativeButtonTriggerElement]); const trigger = isValidElement(children) ? /* @__PURE__ */ jsx(Menu.Trigger, { ...triggerProps, className: clsx(CLASSNAMES.DropdownMenuTrigger, triggerProps?.className), nativeButton: resolvedNativeButton, render: renderer }) : /* @__PURE__ */ jsx(Menu.Trigger, { ...triggerProps, className: clsx(CLASSNAMES.DropdownMenuTrigger, triggerProps?.className), children }); const resolvedPositionerProps = { ...positionerProps, align: positionerProps?.align ?? placementConfig?.align ?? "center", side: positionerProps?.side ?? placementConfig?.side ?? "bottom", sideOffset: positionerProps?.sideOffset ?? 6 }; return /* @__PURE__ */ jsxs(Menu.Root, { ...rest, defaultOpen, onOpenChange: handleOpenChange, onOpenChangeComplete: handleOpenChangeComplete, open, children: [trigger, /* @__PURE__ */ jsx(Menu.Portal, { container: portalProps?.container ?? portalContainer, ...portalProps, children: /* @__PURE__ */ jsx(Menu.Positioner, { ...resolvedPositionerProps, className: (state) => cx(styles.positioner, typeof positionerProps?.className === "function" ? positionerProps.className(state) : positionerProps?.className), "data-hover-trigger": hoverTrigger || void 0, "data-placement": placement, children: /* @__PURE__ */ jsx(Menu.Popup, { ...popupProps, className: (state) => cx(styles.popup, typeof popupProps?.className === "function" ? popupProps.className(state) : popupProps?.className), children: menuItems }) }) })] }); }); DropdownMenu.displayName = "DropdownMenuV2"; var DropdownMenu_default = DropdownMenu; //#endregion export { DropdownMenu_default as default }; //# sourceMappingURL=DropdownMenu.mjs.map