123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- 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';
- /**
- * Provides data to position an inner element of the floating element so that it
- * appears 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 => {
- function isRef(value) {
- return {}.hasOwnProperty.call(value, 'current');
- }
- return {
- name: 'arrow',
- options,
- fn(state) {
- const {
- element,
- padding
- } = typeof options === 'function' ? options(state) : options;
- if (element && isRef(element)) {
- if (element.current != null) {
- return arrow$1({
- element: element.current,
- padding
- }).fn(state);
- }
- return {};
- }
- if (element) {
- return arrow$1({
- element,
- padding
- }).fn(state);
- }
- 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;
- let i;
- let 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 (!{}.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;
- }
- // biome-ignore lint/suspicious/noSelfCompare: in source
- return a !== a && b !== b;
- }
- function getDPR(element) {
- if (typeof window === 'undefined') {
- return 1;
- }
- const win = element.ownerDocument.defaultView || window;
- return win.devicePixelRatio || 1;
- }
- function roundByDPR(element, value) {
- const dpr = getDPR(element);
- return Math.round(value * dpr) / dpr;
- }
- 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/useFloating
- */
- function useFloating(options) {
- if (options === void 0) {
- options = {};
- }
- const {
- placement = 'bottom',
- strategy = 'absolute',
- middleware = [],
- platform,
- elements: {
- reference: externalReference,
- floating: externalFloating
- } = {},
- transform = true,
- whileElementsMounted,
- open
- } = options;
- const [data, setData] = React.useState({
- x: 0,
- y: 0,
- strategy,
- placement,
- middlewareData: {},
- isPositioned: false
- });
- const [latestMiddleware, setLatestMiddleware] = React.useState(middleware);
- if (!deepEqual(latestMiddleware, middleware)) {
- setLatestMiddleware(middleware);
- }
- const [_reference, _setReference] = React.useState(null);
- const [_floating, _setFloating] = React.useState(null);
- const setReference = React.useCallback(node => {
- if (node !== referenceRef.current) {
- referenceRef.current = node;
- _setReference(node);
- }
- }, []);
- const setFloating = React.useCallback(node => {
- if (node !== floatingRef.current) {
- floatingRef.current = node;
- _setFloating(node);
- }
- }, []);
- const referenceEl = externalReference || _reference;
- const floatingEl = externalFloating || _floating;
- const referenceRef = React.useRef(null);
- const floatingRef = React.useRef(null);
- const dataRef = React.useRef(data);
- const hasWhileElementsMounted = whileElementsMounted != null;
- const whileElementsMountedRef = useLatestRef(whileElementsMounted);
- const platformRef = useLatestRef(platform);
- 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;
- };
- }, []);
- // biome-ignore lint/correctness/useExhaustiveDependencies: `hasWhileElementsMounted` is intentionally included.
- index(() => {
- if (referenceEl) referenceRef.current = referenceEl;
- if (floatingEl) floatingRef.current = floatingEl;
- if (referenceEl && floatingEl) {
- if (whileElementsMountedRef.current) {
- return whileElementsMountedRef.current(referenceEl, floatingEl, update);
- }
- update();
- }
- }, [referenceEl, floatingEl, update, whileElementsMountedRef, hasWhileElementsMounted]);
- const refs = React.useMemo(() => ({
- reference: referenceRef,
- floating: floatingRef,
- setReference,
- setFloating
- }), [setReference, setFloating]);
- const elements = React.useMemo(() => ({
- reference: referenceEl,
- floating: floatingEl
- }), [referenceEl, floatingEl]);
- const floatingStyles = React.useMemo(() => {
- const initialStyles = {
- position: strategy,
- left: 0,
- top: 0
- };
- if (!elements.floating) {
- return initialStyles;
- }
- const x = roundByDPR(elements.floating, data.x);
- const y = roundByDPR(elements.floating, data.y);
- if (transform) {
- return {
- ...initialStyles,
- transform: "translate(" + x + "px, " + y + "px)",
- ...(getDPR(elements.floating) >= 1.5 && {
- willChange: 'transform'
- })
- };
- }
- return {
- position: strategy,
- left: x,
- top: y
- };
- }, [strategy, transform, elements.floating, data.x, data.y]);
- return React.useMemo(() => ({
- ...data,
- update,
- refs,
- elements,
- floatingStyles
- }), [data, update, refs, elements, floatingStyles]);
- }
- export { arrow, useFloating };
|