import { arrow as arrow$1, computePosition } from '@floating-ui/dom'; export { autoPlacement, autoUpdate, computePosition, detectOverflow, flip, getOverflowAncestors, hide, inline, limitShift, offset, platform, shift, size } from '@floating-ui/dom'; import * as React from 'react'; import { useLayoutEffect, useEffect } from 'react'; import * as ReactDOM from 'react-dom'; /** * A data provider that provides data to position an inner element of the * floating element (usually a triangle or caret) so that it is centered to the * reference element. * This wraps the core `arrow` middleware to allow React refs as the element. * @see https://floating-ui.com/docs/arrow */ const arrow = options => { const { element, padding } = options; function isRef(value) { return Object.prototype.hasOwnProperty.call(value, 'current'); } return { name: 'arrow', options, fn(args) { if (isRef(element)) { if (element.current != null) { return arrow$1({ element: element.current, padding }).fn(args); } return {}; } else if (element) { return arrow$1({ element, padding }).fn(args); } return {}; } }; }; var index = typeof document !== 'undefined' ? useLayoutEffect : useEffect; // Fork of `fast-deep-equal` that only does the comparisons we need and compares // functions function deepEqual(a, b) { if (a === b) { return true; } if (typeof a !== typeof b) { return false; } if (typeof a === 'function' && a.toString() === b.toString()) { return true; } let length, i, keys; if (a && b && typeof a == 'object') { if (Array.isArray(a)) { length = a.length; if (length != b.length) return false; for (i = length; i-- !== 0;) { if (!deepEqual(a[i], b[i])) { return false; } } return true; } keys = Object.keys(a); length = keys.length; if (length !== Object.keys(b).length) { return false; } for (i = length; i-- !== 0;) { if (!Object.prototype.hasOwnProperty.call(b, keys[i])) { return false; } } for (i = length; i-- !== 0;) { const key = keys[i]; if (key === '_owner' && a.$$typeof) { continue; } if (!deepEqual(a[key], b[key])) { return false; } } return true; } return a !== a && b !== b; } function useLatestRef(value) { const ref = React.useRef(value); index(() => { ref.current = value; }); return ref; } /** * Provides data to position a floating element. * @see https://floating-ui.com/docs/react */ function useFloating(options) { if (options === void 0) { options = {}; } const { placement = 'bottom', strategy = 'absolute', middleware = [], platform, whileElementsMounted, open } = options; const [data, setData] = React.useState({ x: null, y: null, strategy, placement, middlewareData: {}, isPositioned: false }); const [latestMiddleware, setLatestMiddleware] = React.useState(middleware); if (!deepEqual(latestMiddleware, middleware)) { setLatestMiddleware(middleware); } const referenceRef = React.useRef(null); const floatingRef = React.useRef(null); const dataRef = React.useRef(data); const whileElementsMountedRef = useLatestRef(whileElementsMounted); const platformRef = useLatestRef(platform); const [reference, _setReference] = React.useState(null); const [floating, _setFloating] = React.useState(null); const setReference = React.useCallback(node => { if (referenceRef.current !== node) { referenceRef.current = node; _setReference(node); } }, []); const setFloating = React.useCallback(node => { if (floatingRef.current !== node) { floatingRef.current = node; _setFloating(node); } }, []); const update = React.useCallback(() => { if (!referenceRef.current || !floatingRef.current) { return; } const config = { placement, strategy, middleware: latestMiddleware }; if (platformRef.current) { config.platform = platformRef.current; } computePosition(referenceRef.current, floatingRef.current, config).then(data => { const fullData = { ...data, isPositioned: true }; if (isMountedRef.current && !deepEqual(dataRef.current, fullData)) { dataRef.current = fullData; ReactDOM.flushSync(() => { setData(fullData); }); } }); }, [latestMiddleware, placement, strategy, platformRef]); index(() => { if (open === false && dataRef.current.isPositioned) { dataRef.current.isPositioned = false; setData(data => ({ ...data, isPositioned: false })); } }, [open]); const isMountedRef = React.useRef(false); index(() => { isMountedRef.current = true; return () => { isMountedRef.current = false; }; }, []); index(() => { if (reference && floating) { if (whileElementsMountedRef.current) { return whileElementsMountedRef.current(reference, floating, update); } else { update(); } } }, [reference, floating, update, whileElementsMountedRef]); const refs = React.useMemo(() => ({ reference: referenceRef, floating: floatingRef, setReference, setFloating }), [setReference, setFloating]); const elements = React.useMemo(() => ({ reference, floating }), [reference, floating]); return React.useMemo(() => ({ ...data, update, refs, elements, reference: setReference, floating: setFloating }), [data, update, refs, elements, setReference, setFloating]); } export { arrow, useFloating };