You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
3.3 KiB

3 years ago
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { createPopper as defaultCreatePopper } from '@popperjs/core';
import isEqual from 'react-fast-compare';
import { fromEntries, useIsomorphicLayoutEffect } from './utils';
var EMPTY_MODIFIERS = [];
export var usePopper = function usePopper(referenceElement, popperElement, options) {
if (options === void 0) {
options = {};
}
var prevOptions = React.useRef(null);
var optionsWithDefaults = {
onFirstUpdate: options.onFirstUpdate,
placement: options.placement || 'bottom',
strategy: options.strategy || 'absolute',
modifiers: options.modifiers || EMPTY_MODIFIERS
};
var _React$useState = React.useState({
styles: {
popper: {
position: optionsWithDefaults.strategy,
left: '0',
top: '0'
},
arrow: {
position: 'absolute'
}
},
attributes: {}
}),
state = _React$useState[0],
setState = _React$useState[1];
var updateStateModifier = React.useMemo(function () {
return {
name: 'updateState',
enabled: true,
phase: 'write',
fn: function fn(_ref) {
var state = _ref.state;
var elements = Object.keys(state.elements);
ReactDOM.flushSync(function () {
setState({
styles: fromEntries(elements.map(function (element) {
return [element, state.styles[element] || {}];
})),
attributes: fromEntries(elements.map(function (element) {
return [element, state.attributes[element]];
}))
});
});
},
requires: ['computeStyles']
};
}, []);
var popperOptions = React.useMemo(function () {
var newOptions = {
onFirstUpdate: optionsWithDefaults.onFirstUpdate,
placement: optionsWithDefaults.placement,
strategy: optionsWithDefaults.strategy,
modifiers: [].concat(optionsWithDefaults.modifiers, [updateStateModifier, {
name: 'applyStyles',
enabled: false
}])
};
if (isEqual(prevOptions.current, newOptions)) {
return prevOptions.current || newOptions;
} else {
prevOptions.current = newOptions;
return newOptions;
}
}, [optionsWithDefaults.onFirstUpdate, optionsWithDefaults.placement, optionsWithDefaults.strategy, optionsWithDefaults.modifiers, updateStateModifier]);
var popperInstanceRef = React.useRef();
useIsomorphicLayoutEffect(function () {
if (popperInstanceRef.current) {
popperInstanceRef.current.setOptions(popperOptions);
}
}, [popperOptions]);
useIsomorphicLayoutEffect(function () {
if (referenceElement == null || popperElement == null) {
return;
}
var createPopper = options.createPopper || defaultCreatePopper;
var popperInstance = createPopper(referenceElement, popperElement, popperOptions);
popperInstanceRef.current = popperInstance;
return function () {
popperInstance.destroy();
popperInstanceRef.current = null;
};
}, [referenceElement, popperElement, options.createPopper]);
return {
state: popperInstanceRef.current ? popperInstanceRef.current.state : null,
styles: state.styles,
attributes: state.attributes,
update: popperInstanceRef.current ? popperInstanceRef.current.update : null,
forceUpdate: popperInstanceRef.current ? popperInstanceRef.current.forceUpdate : null
};
};