UNPKG

@blueprintjs/core

Version:
78 lines 3.94 kB
"use strict"; /* ! * (c) Copyright 2026 Palantir Technologies Inc. All rights reserved. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.usePopover = usePopover; const react_1 = require("@floating-ui/react"); const react_2 = require("react"); function usePopover({ autoUpdateOptions, disabled = false, isControlled = false, isOpen = false, middleware, placement, positioningStrategy = "absolute", onOpenChange, } = {}) { const [isOpenState, setIsOpenState] = (0, react_2.useState)(isOpen); (0, react_2.useEffect)(() => { setIsOpenState(isOpen); }, [isOpen]); const handleOpenChange = (0, react_2.useCallback)((nextOpen, event) => { // Only update internal state for uncontrolled components if (!isControlled) { setIsOpenState(nextOpen); } // Always call the external callback if provided if (onOpenChange) { onOpenChange(nextOpen, event); } }, [onOpenChange, isControlled]); // Store options in a ref so the memoized callback always reads the latest // values without changing its identity on every render. const autoUpdateOptionsRef = (0, react_2.useRef)(autoUpdateOptions); autoUpdateOptionsRef.current = autoUpdateOptions; const whileElementsMounted = (0, react_2.useMemo)(() => autoUpdateOptions != null ? (reference, floating, update) => (0, react_1.autoUpdate)(reference, floating, update, autoUpdateOptionsRef.current) : react_1.autoUpdate, // Only change identity when toggling between with/without options; // actual option values are read from the ref at call time. // eslint-disable-next-line react-hooks/exhaustive-deps [autoUpdateOptions != null]); const data = (0, react_1.useFloating)({ middleware, onOpenChange: handleOpenChange, open: isOpenState, placement, strategy: positioningStrategy, whileElementsMounted, }); const { context } = data; const click = (0, react_1.useClick)(context, { enabled: !disabled, // Disable Floating UI's built-in Space/Enter keyboard handlers because they // call `preventDefault()` on the Space keydown event to prevent page scrolling. // This also prevents space characters from being typed in <input>/<textarea> // elements that are children of the target wrapper element. // See: https://github.com/palantir/blueprint/pull/7997 // // PopoverTarget provides its own keyboard click handling that avoids this issue // by skipping typeable elements while still maintaining keyboard accessibility // for non-typeable targets. keyboardHandlers: false, }); const dismiss = (0, react_1.useDismiss)(context, { // Escape handling lives on Overlay2 (`canEscapeKeyClose`), which is stack-aware via // OverlayContext so only the topmost overlay closes per keystroke. Floating UI's // `useDismiss` attaches a non-stack-aware document keydown listener — enabling both // means every stacked popover/tooltip closes on a single Escape. escapeKey: false, // Outside-press handling lives on Overlay2 (`canOutsideClickClose`), which is // stack-aware via OverlayContext so clicks inside portaled child overlays (e.g. a // Dialog rendered in popover content) don't incorrectly close the popover. Floating // UI's `useDismiss` treats those clicks as "outside" the popover because the child // overlay is rendered outside the popover's DOM subtree. outsidePress: false, }); const interactions = (0, react_1.useInteractions)([click, dismiss]); return (0, react_2.useMemo)(() => ({ isOpen: isOpenState, setIsOpen: setIsOpenState, ...interactions, ...data, }), [data, interactions, isOpenState]); } //# sourceMappingURL=usePopover.js.map