UNPKG

@lobehub/ui

Version:

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

171 lines (168 loc) 5.7 kB
'use client'; import { useNativeButton } from "../hooks/useNativeButton.mjs"; import { useIsClient } from "../hooks/useIsClient.mjs"; import { placementMap } from "../utils/placement.mjs"; import { parseTrigger } from "../utils/parseTrigger.mjs"; import { PopoverArrowIcon } from "./ArrowIcon.mjs"; import { usePopoverPortalContainer } from "./PopoverPortal.mjs"; import { PopoverArrow, PopoverPopup, PopoverPortal, PopoverPositioner, PopoverRoot, PopoverTriggerElement, PopoverViewport } from "./atoms.mjs"; import { PopoverProvider } from "./context.mjs"; import { memo, useCallback, useMemo, useState } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; import { Popover } from "@base-ui/react/popover"; //#region src/Popover/PopoverStandalone.tsx /** * Popover component - displays floating content relative to a trigger element * Compatible with Ant Design Popover API */ const PopoverStandalone = memo(({ children, content, arrow: originArrow = false, inset = false, trigger = "hover", placement = "top", styles: styleProps, classNames, className, open, onOpenChange, defaultOpen = false, mouseEnterDelay = .1, mouseLeaveDelay = .1, openDelay, closeDelay, getPopupContainer, disabled = false, zIndex, nativeButton, ref: refProp, positionerProps, triggerProps, popupProps, backdropProps, portalProps }) => { const arrow = inset ? false : originArrow; const isClient = useIsClient(); const popoverHandle = useMemo(() => Popover.createHandle(), []); const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen)); const close = useCallback(() => { popoverHandle.close(); }, [popoverHandle]); const contextValue = useMemo(() => ({ close }), [close]); const resolvedOpen = disabled ? false : open ?? uncontrolledOpen; const handleOpenChange = useCallback((nextOpen) => { if (disabled && nextOpen) return; onOpenChange?.(nextOpen); if (open === void 0) setUncontrolledOpen(nextOpen); }, [ onOpenChange, open, disabled ]); const { openOnHover } = useMemo(() => parseTrigger(trigger), [trigger]); const resolvedOpenDelay = openDelay ?? mouseEnterDelay * 1e3; const resolvedCloseDelay = closeDelay ?? mouseLeaveDelay * 1e3; const placementConfig = placementMap[placement] ?? placementMap.top; const baseSideOffset = arrow ? 10 : 6; const resolvedSideOffset = useMemo(() => { if (!inset) return baseSideOffset; return ({ side, positioner }) => { if (side === "left" || side === "right" || side === "inline-start" || side === "inline-end") return -positioner.width; return -positioner.height; }; }, [baseSideOffset, inset]); const portalContainer = usePopoverPortalContainer(); const { resolvedNativeButton } = useNativeButton({ children, nativeButton }); const resolvedClassNames = useMemo(() => ({ arrow: classNames?.arrow, popup: className, positioner: classNames?.root, trigger: classNames?.trigger, viewport: classNames?.content }), [ className, classNames?.arrow, classNames?.content, classNames?.root, classNames?.trigger ]); const triggerElement = useMemo(() => { return /* @__PURE__ */ jsx(PopoverTriggerElement, { handle: popoverHandle, closeDelay: resolvedCloseDelay, delay: resolvedOpenDelay, disabled, openOnHover: openOnHover && !disabled, ...triggerProps, className: resolvedClassNames.trigger, nativeButton: resolvedNativeButton, ref: refProp, children }); }, [ children, disabled, openOnHover, popoverHandle, refProp, resolvedClassNames.trigger, resolvedNativeButton, resolvedOpenDelay, resolvedCloseDelay, triggerProps ]); const customContainer = useMemo(() => { if (!getPopupContainer || !isClient) return void 0; }, [getPopupContainer, isClient]); const resolvedStyles = useMemo(() => ({ arrow: styleProps?.arrow, positioner: { ...styleProps?.root, zIndex: zIndex ?? 1100 }, viewport: styleProps?.content }), [ styleProps?.arrow, styleProps?.content, styleProps?.root, zIndex ]); const popup = useMemo(() => /* @__PURE__ */ jsx(PopoverPositioner, { align: placementConfig.align, className: resolvedClassNames.positioner, hoverTrigger: openOnHover, placement, side: placementConfig.side, sideOffset: resolvedSideOffset, style: resolvedStyles.positioner, ...positionerProps, children: /* @__PURE__ */ jsxs(PopoverPopup, { className: resolvedClassNames.popup, ...popupProps, children: [arrow && /* @__PURE__ */ jsx(PopoverArrow, { className: resolvedClassNames.arrow, style: resolvedStyles.arrow, children: PopoverArrowIcon }), /* @__PURE__ */ jsx(PopoverViewport, { className: resolvedClassNames.viewport, style: resolvedStyles.viewport, children: /* @__PURE__ */ jsx(PopoverProvider, { value: contextValue, children: content }) })] }) }), [ arrow, content, contextValue, openOnHover, placement, placementConfig.align, placementConfig.side, popupProps, positionerProps, resolvedClassNames, resolvedSideOffset, resolvedStyles ]); if (!content) return children; const resolvedPortalContainer = customContainer ?? portalContainer; return /* @__PURE__ */ jsxs(PopoverRoot, { defaultOpen, handle: popoverHandle, onOpenChange: handleOpenChange, open: resolvedOpen, children: [ triggerElement, backdropProps && /* @__PURE__ */ jsx(Popover.Backdrop, { ...backdropProps }), resolvedPortalContainer ? /* @__PURE__ */ jsx(PopoverPortal, { container: resolvedPortalContainer, ...portalProps, children: popup }) : null ] }); }); PopoverStandalone.displayName = "PopoverStandalone"; //#endregion export { PopoverStandalone }; //# sourceMappingURL=PopoverStandalone.mjs.map