UNPKG

6.47 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5exports.__esModule = true;
6exports.toModifierMap = toModifierMap;
7exports.toModifierArray = toModifierArray;
8exports["default"] = void 0;
9
10var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
12var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
13
14var _react = require("react");
15
16var _useSafeState2 = _interopRequireDefault(require("@restart/hooks/useSafeState"));
17
18var _popper = require("./popper");
19
20var initialPopperStyles = {
21 position: 'absolute',
22 top: '0',
23 left: '0',
24 opacity: '0',
25 pointerEvents: 'none'
26};
27var initialArrowStyles = {}; // until docjs supports type exports...
28
29function toModifierMap(modifiers) {
30 var result = {};
31
32 if (!Array.isArray(modifiers)) {
33 return modifiers || result;
34 } // eslint-disable-next-line no-unused-expressions
35
36
37 modifiers == null ? void 0 : modifiers.forEach(function (m) {
38 result[m.name] = m;
39 });
40 return result;
41}
42
43function toModifierArray(map) {
44 if (map === void 0) {
45 map = {};
46 }
47
48 if (Array.isArray(map)) return map;
49 return Object.keys(map).map(function (k) {
50 map[k].name = k;
51 return map[k];
52 });
53}
54
55/**
56 * Position an element relative some reference element using Popper.js
57 *
58 * @param referenceElement
59 * @param popperElement
60 * @param {object} options
61 * @param {object=} options.modifiers Popper.js modifiers
62 * @param {boolean=} options.enabled toggle the popper functionality on/off
63 * @param {string=} options.placement The popper element placement relative to the reference element
64 * @param {string=} options.strategy the positioning strategy
65 * @param {boolean=} options.eventsEnabled have Popper listen on window resize events to reposition the element
66 * @param {function=} options.onCreate called when the popper is created
67 * @param {function=} options.onUpdate called when the popper is updated
68 *
69 * @returns {UsePopperState} The popper state
70 */
71function usePopper(referenceElement, popperElement, _temp) {
72 var _ref = _temp === void 0 ? {} : _temp,
73 _ref$enabled = _ref.enabled,
74 enabled = _ref$enabled === void 0 ? true : _ref$enabled,
75 _ref$placement = _ref.placement,
76 placement = _ref$placement === void 0 ? 'bottom' : _ref$placement,
77 _ref$strategy = _ref.strategy,
78 strategy = _ref$strategy === void 0 ? 'absolute' : _ref$strategy,
79 _ref$eventsEnabled = _ref.eventsEnabled,
80 eventsEnabled = _ref$eventsEnabled === void 0 ? true : _ref$eventsEnabled,
81 userModifiers = _ref.modifiers,
82 popperOptions = (0, _objectWithoutPropertiesLoose2["default"])(_ref, ["enabled", "placement", "strategy", "eventsEnabled", "modifiers"]);
83
84 var popperInstanceRef = (0, _react.useRef)();
85 var scheduleUpdate = (0, _react.useCallback)(function () {
86 if (popperInstanceRef.current) {
87 popperInstanceRef.current.update();
88 }
89 }, []);
90
91 var _useSafeState = (0, _useSafeState2["default"])((0, _react.useState)({
92 placement: placement,
93 scheduleUpdate: scheduleUpdate,
94 outOfBoundaries: false,
95 styles: initialPopperStyles,
96 arrowStyles: initialArrowStyles
97 })),
98 state = _useSafeState[0],
99 setState = _useSafeState[1];
100
101 var updateModifier = (0, _react.useMemo)(function () {
102 return {
103 name: 'updateStateModifier',
104 enabled: true,
105 phase: 'afterWrite',
106 requires: ['computeStyles'],
107 fn: function fn(data) {
108 var _data$state$modifiers, _data$state$styles, _data$state$styles2;
109
110 setState({
111 scheduleUpdate: scheduleUpdate,
112 outOfBoundaries: !!((_data$state$modifiers = data.state.modifiersData.hide) == null ? void 0 : _data$state$modifiers.isReferenceHidden),
113 placement: data.state.placement,
114 styles: (0, _extends2["default"])({}, (_data$state$styles = data.state.styles) == null ? void 0 : _data$state$styles.popper),
115 arrowStyles: (0, _extends2["default"])({}, (_data$state$styles2 = data.state.styles) == null ? void 0 : _data$state$styles2.arrow),
116 state: data.state
117 });
118 }
119 };
120 }, [scheduleUpdate, setState]);
121 var modifiers = toModifierArray(userModifiers);
122 var eventsModifier = modifiers.find(function (m) {
123 return m.name === 'eventListeners';
124 });
125
126 if (!eventsModifier && eventsEnabled) {
127 eventsModifier = {
128 name: 'eventListeners',
129 enabled: true
130 };
131 modifiers = [].concat(modifiers, [eventsModifier]);
132 } // A placement difference in state means popper determined a new placement
133 // apart from the props value. By the time the popper element is rendered with
134 // the new position Popper has already measured it, if the place change triggers
135 // a size change it will result in a misaligned popper. So we schedule an update to be sure.
136
137
138 (0, _react.useEffect)(function () {
139 scheduleUpdate();
140 }, [state.placement, scheduleUpdate]);
141 (0, _react.useEffect)(function () {
142 if (!popperInstanceRef.current || !enabled) return;
143 popperInstanceRef.current.setOptions({
144 placement: placement,
145 strategy: strategy,
146 modifiers: [].concat(modifiers, [updateModifier])
147 }); // intentionally NOT re-running on new modifiers
148 // eslint-disable-next-line react-hooks/exhaustive-deps
149 }, [strategy, placement, eventsModifier.enabled, updateModifier, enabled]);
150 (0, _react.useEffect)(function () {
151 if (!enabled || referenceElement == null || popperElement == null) {
152 return undefined;
153 }
154
155 popperInstanceRef.current = (0, _popper.createPopper)(referenceElement, popperElement, (0, _extends2["default"])({}, popperOptions, {
156 placement: placement,
157 strategy: strategy,
158 modifiers: [].concat(modifiers, [updateModifier])
159 }));
160 return function () {
161 if (popperInstanceRef.current != null) {
162 popperInstanceRef.current.destroy();
163 popperInstanceRef.current = undefined;
164 setState(function (s) {
165 return (0, _extends2["default"])({}, s, {
166 styles: initialPopperStyles,
167 arrowStyles: initialArrowStyles
168 });
169 });
170 }
171 }; // This is only run once to _create_ the popper
172 // eslint-disable-next-line react-hooks/exhaustive-deps
173 }, [enabled, referenceElement, popperElement]);
174 return state;
175}
176
177var _default = usePopper;
178exports["default"] = _default;
\No newline at end of file