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
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
|
||
|
};
|
||
|
};
|