UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

109 lines (107 loc) 3.99 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.useFloating = useFloating; var React = _interopRequireWildcard(require("react")); var _reactDom = require("@floating-ui/react-dom"); var _dom = require("@floating-ui/utils/dom"); var _useIsoLayoutEffect = require("@base-ui-components/utils/useIsoLayoutEffect"); var _FloatingTree = require("../components/FloatingTree"); var _useFloatingRootContext = require("./useFloatingRootContext"); /** * Provides data to position a floating element and context to add interactions. * @see https://floating-ui.com/docs/useFloating */ function useFloating(options = {}) { const { nodeId } = options; const internalRootContext = (0, _useFloatingRootContext.useFloatingRootContext)({ ...options, elements: { reference: null, floating: null, ...options.elements } }); const rootContext = options.rootContext || internalRootContext; const computedElements = rootContext.elements; const [domReferenceState, setDomReference] = React.useState(null); const [positionReference, setPositionReferenceRaw] = React.useState(null); const optionDomReference = computedElements?.domReference; const domReference = optionDomReference || domReferenceState; const domReferenceRef = React.useRef(null); const tree = (0, _FloatingTree.useFloatingTree)(); (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => { if (domReference) { domReferenceRef.current = domReference; } }, [domReference]); const position = (0, _reactDom.useFloating)({ ...options, elements: { ...computedElements, ...(positionReference && { reference: positionReference }) } }); const setPositionReference = React.useCallback(node => { const computedPositionReference = (0, _dom.isElement)(node) ? { getBoundingClientRect: () => node.getBoundingClientRect(), getClientRects: () => node.getClientRects(), contextElement: node } : node; // Store the positionReference in state if the DOM reference is specified externally via the // `elements.reference` option. This ensures that it won't be overridden on future renders. setPositionReferenceRaw(computedPositionReference); position.refs.setReference(computedPositionReference); }, [position.refs]); const setReference = React.useCallback(node => { if ((0, _dom.isElement)(node) || node === null) { domReferenceRef.current = node; setDomReference(node); } // Backwards-compatibility for passing a virtual element to `reference` // after it has set the DOM reference. if ((0, _dom.isElement)(position.refs.reference.current) || position.refs.reference.current === null || // Don't allow setting virtual elements using the old technique back to // `null` to support `positionReference` + an unstable `reference` // callback ref. node !== null && !(0, _dom.isElement)(node)) { position.refs.setReference(node); } }, [position.refs]); const refs = React.useMemo(() => ({ ...position.refs, setReference, setPositionReference, domReference: domReferenceRef }), [position.refs, setReference, setPositionReference]); const elements = React.useMemo(() => ({ ...position.elements, domReference }), [position.elements, domReference]); const context = React.useMemo(() => ({ ...position, ...rootContext, refs, elements, nodeId }), [position, refs, elements, nodeId, rootContext]); (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => { rootContext.dataRef.current.floatingContext = context; const node = tree?.nodesRef.current.find(n => n.id === nodeId); if (node) { node.context = context; } }); return React.useMemo(() => ({ ...position, context, refs, elements }), [position, refs, elements, context]); }