@fluentui/react-positioning 0.0.0-nightly-20220715-0418.1 → 0.0.0-nightly-20221007-1528.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +80 -10
- package/CHANGELOG.md +33 -8
- package/dist/index.d.ts +9 -16
- package/lib/constants.js +5 -0
- package/lib/constants.js.map +1 -0
- package/lib/createArrowStyles.js.map +1 -1
- package/lib/createVirtualElementFromClick.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/middleware/coverTarget.js +40 -0
- package/lib/middleware/coverTarget.js.map +1 -0
- package/lib/middleware/flip.js +19 -0
- package/lib/middleware/flip.js.map +1 -0
- package/lib/middleware/index.js +7 -0
- package/lib/middleware/index.js.map +1 -0
- package/lib/middleware/intersecting.js +21 -0
- package/lib/middleware/intersecting.js.map +1 -0
- package/lib/middleware/maxSize.js +43 -0
- package/lib/middleware/maxSize.js.map +1 -0
- package/lib/middleware/offset.js +11 -0
- package/lib/middleware/offset.js.map +1 -0
- package/lib/middleware/shift.js +30 -0
- package/lib/middleware/shift.js.map +1 -0
- package/lib/types.js.map +1 -1
- package/lib/usePositioning.js +234 -336
- package/lib/usePositioning.js.map +1 -1
- package/lib/usePositioningMouseTarget.js.map +1 -1
- package/lib/utils/debounce.js +22 -0
- package/lib/utils/debounce.js.map +1 -0
- package/lib/utils/fromFloatingUIPlacement.js +43 -0
- package/lib/utils/fromFloatingUIPlacement.js.map +1 -0
- package/lib/utils/getBoundary.js +5 -1
- package/lib/utils/getBoundary.js.map +1 -1
- package/lib/utils/getFloatingUIOffset.js +36 -0
- package/lib/utils/getFloatingUIOffset.js.map +1 -0
- package/lib/utils/getReactFiberFromNode.js.map +1 -1
- package/lib/utils/getScrollParent.js +6 -0
- package/lib/utils/getScrollParent.js.map +1 -1
- package/lib/utils/hasAutoFocusFilter.js +28 -0
- package/lib/utils/hasAutoFocusFilter.js.map +1 -0
- package/lib/utils/index.js +6 -2
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/mergeArrowOffset.js +1 -1
- package/lib/utils/mergeArrowOffset.js.map +1 -1
- package/lib/utils/parseFloatingUIPlacement.js +14 -0
- package/lib/utils/parseFloatingUIPlacement.js.map +1 -0
- package/lib/utils/resolvePositioningShorthand.js.map +1 -1
- package/lib/utils/toFloatingUIPlacement.js +40 -0
- package/lib/utils/toFloatingUIPlacement.js.map +1 -0
- package/lib/utils/toggleScrollListener.js +24 -0
- package/lib/utils/toggleScrollListener.js.map +1 -0
- package/lib/utils/useCallbackRef.js.map +1 -1
- package/lib-commonjs/constants.js +11 -0
- package/lib-commonjs/constants.js.map +1 -0
- package/lib-commonjs/createArrowStyles.js.map +1 -1
- package/lib-commonjs/createVirtualElementFromClick.js.map +1 -1
- package/lib-commonjs/index.js.map +1 -1
- package/lib-commonjs/middleware/coverTarget.js +50 -0
- package/lib-commonjs/middleware/coverTarget.js.map +1 -0
- package/lib-commonjs/middleware/flip.js +30 -0
- package/lib-commonjs/middleware/flip.js.map +1 -0
- package/lib-commonjs/middleware/index.js +20 -0
- package/lib-commonjs/middleware/index.js.map +1 -0
- package/lib-commonjs/middleware/intersecting.js +31 -0
- package/lib-commonjs/middleware/intersecting.js.map +1 -0
- package/lib-commonjs/middleware/maxSize.js +54 -0
- package/lib-commonjs/middleware/maxSize.js.map +1 -0
- package/lib-commonjs/middleware/offset.js +22 -0
- package/lib-commonjs/middleware/offset.js.map +1 -0
- package/lib-commonjs/middleware/shift.js +41 -0
- package/lib-commonjs/middleware/shift.js.map +1 -0
- package/lib-commonjs/types.js.map +1 -1
- package/lib-commonjs/usePositioning.js +236 -337
- package/lib-commonjs/usePositioning.js.map +1 -1
- package/lib-commonjs/usePositioningMouseTarget.js.map +1 -1
- package/lib-commonjs/utils/debounce.js +31 -0
- package/lib-commonjs/utils/debounce.js.map +1 -0
- package/lib-commonjs/utils/fromFloatingUIPlacement.js +52 -0
- package/lib-commonjs/utils/fromFloatingUIPlacement.js.map +1 -0
- package/lib-commonjs/utils/getBoundary.js +5 -1
- package/lib-commonjs/utils/getBoundary.js.map +1 -1
- package/lib-commonjs/utils/getFloatingUIOffset.js +46 -0
- package/lib-commonjs/utils/getFloatingUIOffset.js.map +1 -0
- package/lib-commonjs/utils/getReactFiberFromNode.js.map +1 -1
- package/lib-commonjs/utils/getScrollParent.js +10 -1
- package/lib-commonjs/utils/getScrollParent.js.map +1 -1
- package/lib-commonjs/utils/hasAutoFocusFilter.js +37 -0
- package/lib-commonjs/utils/hasAutoFocusFilter.js.map +1 -0
- package/lib-commonjs/utils/index.js +10 -2
- package/lib-commonjs/utils/index.js.map +1 -1
- package/lib-commonjs/utils/mergeArrowOffset.js +1 -1
- package/lib-commonjs/utils/mergeArrowOffset.js.map +1 -1
- package/lib-commonjs/utils/parseFloatingUIPlacement.js +23 -0
- package/lib-commonjs/utils/parseFloatingUIPlacement.js.map +1 -0
- package/lib-commonjs/utils/resolvePositioningShorthand.js.map +1 -1
- package/lib-commonjs/utils/toFloatingUIPlacement.js +49 -0
- package/lib-commonjs/utils/toFloatingUIPlacement.js.map +1 -0
- package/lib-commonjs/utils/toggleScrollListener.js +34 -0
- package/lib-commonjs/utils/toggleScrollListener.js.map +1 -0
- package/lib-commonjs/utils/useCallbackRef.js.map +1 -1
- package/package.json +8 -12
- package/dist/tsdoc-metadata.json +0 -11
- package/lib/isIntersectingModifier.js +0 -26
- package/lib/isIntersectingModifier.js.map +0 -1
- package/lib/utils/fromPopperPlacement.js +0 -40
- package/lib/utils/fromPopperPlacement.js.map +0 -1
- package/lib/utils/getPopperOffset.js +0 -44
- package/lib/utils/getPopperOffset.js.map +0 -1
- package/lib/utils/parsePopperPlacement.js +0 -14
- package/lib/utils/parsePopperPlacement.js.map +0 -1
- package/lib/utils/positioningHelper.js +0 -49
- package/lib/utils/positioningHelper.js.map +0 -1
- package/lib-commonjs/isIntersectingModifier.js +0 -34
- package/lib-commonjs/isIntersectingModifier.js.map +0 -1
- package/lib-commonjs/utils/fromPopperPlacement.js +0 -50
- package/lib-commonjs/utils/fromPopperPlacement.js.map +0 -1
- package/lib-commonjs/utils/getPopperOffset.js +0 -54
- package/lib-commonjs/utils/getPopperOffset.js.map +0 -1
- package/lib-commonjs/utils/parsePopperPlacement.js +0 -23
- package/lib-commonjs/utils/parsePopperPlacement.js.map +0 -1
- package/lib-commonjs/utils/positioningHelper.js +0 -61
- package/lib-commonjs/utils/positioningHelper.js.map +0 -1
@@ -5,347 +5,101 @@ Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
});
|
6
6
|
exports.usePositioning = void 0;
|
7
7
|
|
8
|
-
const
|
8
|
+
const dom_1 = /*#__PURE__*/require("@floating-ui/dom");
|
9
9
|
|
10
10
|
const react_shared_contexts_1 = /*#__PURE__*/require("@fluentui/react-shared-contexts");
|
11
11
|
|
12
|
-
const
|
13
|
-
|
14
|
-
const React = /*#__PURE__*/require("react");
|
15
|
-
|
16
|
-
const isIntersectingModifier_1 = /*#__PURE__*/require("./isIntersectingModifier");
|
17
|
-
|
18
|
-
const index_1 = /*#__PURE__*/require("./utils/index");
|
19
|
-
|
20
|
-
const getPopperOffset_1 = /*#__PURE__*/require("./utils/getPopperOffset"); //
|
21
|
-
// Dev utils to detect if nodes have "autoFocus" props.
|
22
|
-
//
|
23
|
-
|
24
|
-
/**
|
25
|
-
* Detects if a passed HTML node has "autoFocus" prop on a React's fiber. Is needed as React handles autofocus behavior
|
26
|
-
* in React DOM and will not pass "autoFocus" to an actual HTML.
|
27
|
-
*/
|
28
|
-
|
29
|
-
|
30
|
-
function hasAutofocusProp(node) {
|
31
|
-
var _a; // https://github.com/facebook/react/blob/848bb2426e44606e0a55dfe44c7b3ece33772485/packages/react-dom/src/client/ReactDOMHostConfig.js#L157-L166
|
12
|
+
const react_utilities_1 = /*#__PURE__*/require("@fluentui/react-utilities");
|
32
13
|
|
14
|
+
const react_utilities_2 = /*#__PURE__*/require("@fluentui/react-utilities");
|
33
15
|
|
34
|
-
|
16
|
+
const React = /*#__PURE__*/require("react");
|
35
17
|
|
36
|
-
|
37
|
-
return !!((_a = index_1.getReactFiberFromNode(node)) === null || _a === void 0 ? void 0 : _a.pendingProps.autoFocus);
|
38
|
-
}
|
18
|
+
const utils_1 = /*#__PURE__*/require("./utils");
|
39
19
|
|
40
|
-
|
41
|
-
}
|
20
|
+
const middleware_1 = /*#__PURE__*/require("./middleware");
|
42
21
|
|
43
|
-
|
44
|
-
return hasAutofocusProp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
45
|
-
}
|
22
|
+
const constants_1 = /*#__PURE__*/require("./constants");
|
46
23
|
/**
|
47
|
-
*
|
48
|
-
* of Popper options.
|
49
|
-
*
|
50
|
-
* A callback is used there intentionally as some of Popper.js modifiers require DOM nodes (targer, container, arrow)
|
51
|
-
* that can't be resolved properly during an initial rendering.
|
24
|
+
* @internal
|
52
25
|
*/
|
53
26
|
|
54
27
|
|
55
|
-
function
|
28
|
+
function usePositioning(options) {
|
56
29
|
const {
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
flipBoundary,
|
62
|
-
offset,
|
63
|
-
overflowBoundary,
|
64
|
-
pinned,
|
65
|
-
position,
|
66
|
-
positionFixed,
|
67
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
68
|
-
unstable_disableTether
|
30
|
+
targetDocument
|
31
|
+
} = react_shared_contexts_1.useFluent_unstable();
|
32
|
+
const {
|
33
|
+
enabled = true
|
69
34
|
} = options;
|
70
|
-
const
|
71
|
-
const
|
72
|
-
const strategy = positionFixed ? 'fixed' : 'absolute';
|
73
|
-
const offsetModifier = React.useMemo(() => offset ? {
|
74
|
-
name: 'offset',
|
75
|
-
options: {
|
76
|
-
offset: isRtl ? index_1.applyRtlToOffset(getPopperOffset_1.getPopperOffset(offset)) : getPopperOffset_1.getPopperOffset(offset)
|
77
|
-
}
|
78
|
-
} : null, [offset, isRtl]);
|
79
|
-
return React.useCallback((target, container, arrow) => {
|
35
|
+
const resolvePositioningOptions = usePositioningOptions(options);
|
36
|
+
const forceUpdate = react_utilities_2.useEventCallback(() => {
|
80
37
|
var _a;
|
81
38
|
|
82
|
-
const
|
83
|
-
const hasScrollableElement = scrollParentElement ? scrollParentElement !== ((_a = scrollParentElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.body) : false;
|
84
|
-
const modifiers = [isIntersectingModifier_1.isIntersectingModifier,
|
85
|
-
/**
|
86
|
-
* We are setting the position to `fixed` in the first effect to prevent scroll jumps in case of the content
|
87
|
-
* with managed focus. Modifier sets the position to `fixed` before all other modifier effects. Another part of
|
88
|
-
* a patch modifies ".forceUpdate()" directly after a Popper will be created.
|
89
|
-
*/
|
90
|
-
{
|
91
|
-
name: 'positionStyleFix',
|
92
|
-
enabled: true,
|
93
|
-
phase: 'afterWrite',
|
94
|
-
effect: ({
|
95
|
-
state,
|
96
|
-
instance
|
97
|
-
}) => {
|
98
|
-
// ".isFirstRun" is a part of our patch, on a first evaluation it will "undefined"
|
99
|
-
// should be disabled for subsequent runs as it breaks positioning for them
|
100
|
-
if (instance.isFirstRun !== false) {
|
101
|
-
popperOriginalPositionRef.current = state.elements.popper.style.position;
|
102
|
-
state.elements.popper.style.position = 'fixed';
|
103
|
-
}
|
104
|
-
|
105
|
-
return () => undefined;
|
106
|
-
},
|
107
|
-
requires: []
|
108
|
-
}, {
|
109
|
-
name: 'flip',
|
110
|
-
options: {
|
111
|
-
flipVariations: true
|
112
|
-
}
|
113
|
-
},
|
114
|
-
/**
|
115
|
-
* pinned disables the flip modifier by setting flip.enabled to false; this
|
116
|
-
* disables automatic repositioning of the popper box; it will always be placed according to
|
117
|
-
* the values of `align` and `position` props, regardless of the size of the component, the
|
118
|
-
* reference element or the viewport.
|
119
|
-
*/
|
120
|
-
pinned && {
|
121
|
-
name: 'flip',
|
122
|
-
enabled: false
|
123
|
-
},
|
124
|
-
/**
|
125
|
-
* When the popper box is placed in the context of a scrollable element, we need to set
|
126
|
-
* preventOverflow.escapeWithReference to true and flip.boundariesElement to 'scrollParent'
|
127
|
-
* (default is 'viewport') so that the popper box will stick with the targetRef when we
|
128
|
-
* scroll targetRef out of the viewport.
|
129
|
-
*/
|
130
|
-
hasScrollableElement && {
|
131
|
-
name: 'flip',
|
132
|
-
options: {
|
133
|
-
boundary: 'clippingParents'
|
134
|
-
}
|
135
|
-
}, hasScrollableElement && {
|
136
|
-
name: 'preventOverflow',
|
137
|
-
options: {
|
138
|
-
boundary: 'clippingParents'
|
139
|
-
}
|
140
|
-
}, offsetModifier,
|
141
|
-
/**
|
142
|
-
* This modifier is necessary to retain behaviour from popper v1 where untethered poppers are allowed by
|
143
|
-
* default. i.e. popper is still rendered fully in the viewport even if anchor element is no longer in the
|
144
|
-
* viewport.
|
145
|
-
*/
|
146
|
-
unstable_disableTether && {
|
147
|
-
name: 'preventOverflow',
|
148
|
-
options: {
|
149
|
-
altAxis: unstable_disableTether === 'all',
|
150
|
-
tether: false
|
151
|
-
}
|
152
|
-
}, flipBoundary && {
|
153
|
-
name: 'flip',
|
154
|
-
options: {
|
155
|
-
altBoundary: true,
|
156
|
-
boundary: index_1.getBoundary(container, flipBoundary)
|
157
|
-
}
|
158
|
-
}, overflowBoundary && {
|
159
|
-
name: 'preventOverflow',
|
160
|
-
options: {
|
161
|
-
altBoundary: true,
|
162
|
-
boundary: index_1.getBoundary(container, overflowBoundary)
|
163
|
-
}
|
164
|
-
}, {
|
165
|
-
// Similar code as popper-maxsize-modifier: https://github.com/atomiks/popper.js/blob/master/src/modifiers/maxSize.js
|
166
|
-
// popper-maxsize-modifier only calculates the max sizes.
|
167
|
-
// This modifier can apply max sizes always, or apply the max sizes only when overflow is detected
|
168
|
-
name: 'applyMaxSize',
|
169
|
-
enabled: !!autoSize,
|
170
|
-
phase: 'beforeWrite',
|
171
|
-
requiresIfExists: ['offset', 'preventOverflow', 'flip'],
|
172
|
-
options: {
|
173
|
-
altBoundary: true,
|
174
|
-
boundary: index_1.getBoundary(container, overflowBoundary)
|
175
|
-
},
|
176
|
-
|
177
|
-
fn({
|
178
|
-
state,
|
179
|
-
options: modifierOptions
|
180
|
-
}) {
|
181
|
-
const overflow = PopperJs.detectOverflow(state, modifierOptions);
|
182
|
-
const {
|
183
|
-
x,
|
184
|
-
y
|
185
|
-
} = state.modifiersData.preventOverflow || {
|
186
|
-
x: 0,
|
187
|
-
y: 0
|
188
|
-
};
|
189
|
-
const {
|
190
|
-
width,
|
191
|
-
height
|
192
|
-
} = state.rects.popper;
|
193
|
-
const basePlacement = index_1.parsePopperPlacement(state.placement).basePlacement;
|
194
|
-
const widthProp = basePlacement === 'left' ? 'left' : 'right';
|
195
|
-
const heightProp = basePlacement === 'top' ? 'top' : 'bottom';
|
196
|
-
const applyMaxWidth = autoSize === 'always' || autoSize === 'width-always' || overflow[widthProp] > 0 && (autoSize === true || autoSize === 'width');
|
197
|
-
const applyMaxHeight = autoSize === 'always' || autoSize === 'height-always' || overflow[heightProp] > 0 && (autoSize === true || autoSize === 'height');
|
198
|
-
|
199
|
-
if (applyMaxWidth) {
|
200
|
-
state.styles.popper.maxWidth = `${width - overflow[widthProp] - x}px`;
|
201
|
-
}
|
202
|
-
|
203
|
-
if (applyMaxHeight) {
|
204
|
-
state.styles.popper.maxHeight = `${height - overflow[heightProp] - y}px`;
|
205
|
-
}
|
206
|
-
}
|
207
|
-
|
208
|
-
},
|
209
|
-
/**
|
210
|
-
* This modifier is necessary in order to render the pointer. Refs are resolved in effects, so it can't be
|
211
|
-
* placed under computed modifiers. Deep merge is not required as this modifier has only these properties.
|
212
|
-
*/
|
213
|
-
{
|
214
|
-
name: 'arrow',
|
215
|
-
enabled: !!arrow,
|
216
|
-
options: {
|
217
|
-
element: arrow,
|
218
|
-
padding: arrowPadding
|
219
|
-
}
|
220
|
-
},
|
221
|
-
/**
|
222
|
-
* Modifies popper offsets to cover the reference rect, but still keep edge alignment
|
223
|
-
*/
|
224
|
-
{
|
225
|
-
name: 'coverTarget',
|
226
|
-
enabled: !!coverTarget,
|
227
|
-
phase: 'main',
|
228
|
-
requiresIfExists: ['offset', 'preventOverflow', 'flip'],
|
229
|
-
|
230
|
-
fn({
|
231
|
-
state
|
232
|
-
}) {
|
233
|
-
const basePlacement = index_1.parsePopperPlacement(state.placement).basePlacement;
|
234
|
-
|
235
|
-
switch (basePlacement) {
|
236
|
-
case 'bottom':
|
237
|
-
state.modifiersData.popperOffsets.y -= state.rects.reference.height;
|
238
|
-
break;
|
239
|
-
|
240
|
-
case 'top':
|
241
|
-
state.modifiersData.popperOffsets.y += state.rects.reference.height;
|
242
|
-
break;
|
243
|
-
|
244
|
-
case 'left':
|
245
|
-
state.modifiersData.popperOffsets.x += state.rects.reference.width;
|
246
|
-
break;
|
247
|
-
|
248
|
-
case 'right':
|
249
|
-
state.modifiersData.popperOffsets.x -= state.rects.reference.width;
|
250
|
-
break;
|
251
|
-
}
|
252
|
-
}
|
39
|
+
const target = (_a = overrideTargetRef.current) !== null && _a !== void 0 ? _a : targetRef.current;
|
253
40
|
|
254
|
-
|
41
|
+
if (!react_utilities_1.canUseDOM || !enabled || !target || !containerRef.current) {
|
42
|
+
return;
|
43
|
+
}
|
255
44
|
|
256
|
-
const
|
257
|
-
modifiers,
|
45
|
+
const {
|
258
46
|
placement,
|
47
|
+
middleware,
|
259
48
|
strategy
|
260
|
-
};
|
261
|
-
|
262
|
-
}, [arrowPadding, autoSize, coverTarget, flipBoundary, offsetModifier, overflowBoundary, placement, strategy, unstable_disableTether, pinned, // These can be skipped from deps as they will not ever change
|
263
|
-
popperOriginalPositionRef]);
|
264
|
-
}
|
265
|
-
/**
|
266
|
-
* @internal
|
267
|
-
* Exposes Popper positioning API via React hook. Contains few important differences between an official "react-popper"
|
268
|
-
* package:
|
269
|
-
* - style attributes are applied directly on DOM to avoid re-renders
|
270
|
-
* - refs changes and resolution is handled properly without re-renders
|
271
|
-
* - contains a specific to React fix related to initial positioning when containers have components with managed focus
|
272
|
-
* to avoid focus jumps
|
273
|
-
*/
|
49
|
+
} = resolvePositioningOptions(target, containerRef.current, arrowRef.current); // Container is always initialized with `position: fixed` to avoid scroll jumps
|
50
|
+
// Before computing the positioned coordinates, revert the container to the deisred positioning strategy
|
274
51
|
|
52
|
+
Object.assign(containerRef.current.style, {
|
53
|
+
position: strategy
|
54
|
+
});
|
55
|
+
dom_1.computePosition(target, containerRef.current, {
|
56
|
+
placement,
|
57
|
+
middleware,
|
58
|
+
strategy
|
59
|
+
}).then(({
|
60
|
+
x,
|
61
|
+
y,
|
62
|
+
middlewareData,
|
63
|
+
placement: computedPlacement
|
64
|
+
}) => {
|
65
|
+
var _a;
|
275
66
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
67
|
+
writeArrowUpdates({
|
68
|
+
arrow: arrowRef.current,
|
69
|
+
middlewareData
|
70
|
+
});
|
71
|
+
writeContainerUpdates({
|
72
|
+
container: containerRef.current,
|
73
|
+
middlewareData,
|
74
|
+
placement: computedPlacement,
|
75
|
+
coordinates: {
|
76
|
+
x,
|
77
|
+
y
|
78
|
+
},
|
79
|
+
lowPPI: (((_a = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView) === null || _a === void 0 ? void 0 : _a.devicePixelRatio) || 1) <= 1,
|
80
|
+
strategy
|
81
|
+
});
|
82
|
+
}).catch(err => {
|
83
|
+
// https://github.com/floating-ui/floating-ui/issues/1845
|
84
|
+
// FIXME for node > 14
|
85
|
+
// node 15 introduces promise rejection which means that any components
|
86
|
+
// tests need to be `it('', async () => {})` otherwise there can be race conditions with
|
87
|
+
// JSDOM being torn down before this promise is resolved so globals like `window` and `document` don't exist
|
88
|
+
// Unless all tests that ever use `usePositioning` are turned into async tests, any logging during testing
|
89
|
+
// will actually be counter productive
|
90
|
+
if (process.env.NODE_ENV === 'development') {
|
91
|
+
// eslint-disable-next-line no-console
|
92
|
+
console.error('[usePositioning]: Failed to calculate position', err);
|
295
93
|
}
|
296
|
-
}
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
const originalForceUpdate = popperInstance.forceUpdate;
|
304
|
-
popperInstance.isFirstRun = true;
|
305
|
-
|
306
|
-
popperInstance.forceUpdate = () => {
|
307
|
-
if (popperInstance === null || popperInstance === void 0 ? void 0 : popperInstance.isFirstRun) {
|
308
|
-
popperInstance.state.elements.popper.style.position = popperOriginalPositionRef.current;
|
309
|
-
popperInstance.isFirstRun = false;
|
310
|
-
}
|
311
|
-
|
312
|
-
originalForceUpdate();
|
313
|
-
};
|
314
|
-
}
|
315
|
-
|
316
|
-
popperInstanceRef.current = popperInstance;
|
317
|
-
}); // Refs are managed by useCallbackRef() to handle ref updates scenarios.
|
318
|
-
//
|
319
|
-
// The first scenario are updates for a targetRef, we can handle it properly only via callback refs, but it causes
|
320
|
-
// re-renders (we would like to avoid them).
|
321
|
-
//
|
322
|
-
// The second problem is related to refs resolution on React's layer: refs are resolved in the same order as effects
|
323
|
-
// that causes an issue when you have a container inside a target, for example: a menu in ChatMessage.
|
324
|
-
//
|
325
|
-
// function ChatMessage(props) {
|
326
|
-
// <div className="message" ref={targetRef}> // 3) ref will be resolved only now, but it's too late already
|
327
|
-
// <Popper target={targetRef}> // 2) create a popper instance
|
328
|
-
// <div className="menu" /> // 1) capture ref from this element
|
329
|
-
// </Popper>
|
330
|
-
// </div>
|
331
|
-
// }
|
332
|
-
//
|
333
|
-
// Check a demo on CodeSandbox: https://codesandbox.io/s/popper-refs-emy60.
|
334
|
-
//
|
335
|
-
// This again can be solved with callback refs. It's not a huge issue as with hooks we are moving popper's creation
|
336
|
-
// to ChatMessage itself, however, without `useCallback()` refs it's still a Pandora box.
|
337
|
-
|
338
|
-
const targetRef = index_1.useCallbackRef(null, handlePopperUpdate, true);
|
339
|
-
const containerRef = index_1.useCallbackRef(null, handlePopperUpdate, true);
|
340
|
-
const arrowRef = index_1.useCallbackRef(null, handlePopperUpdate, true); // Stores external target from options.target or setTarget
|
341
|
-
|
342
|
-
const overrideTargetRef = index_1.useCallbackRef(null, handlePopperUpdate, true);
|
94
|
+
});
|
95
|
+
});
|
96
|
+
const updatePosition = React.useState(() => utils_1.debounce(forceUpdate))[0];
|
97
|
+
const targetRef = useTargetRef(updatePosition);
|
98
|
+
const overrideTargetRef = useTargetRef(updatePosition);
|
99
|
+
const containerRef = useContainerRef(updatePosition, enabled);
|
100
|
+
const arrowRef = useArrowRef(updatePosition);
|
343
101
|
React.useImperativeHandle(options.positioningRef, () => ({
|
344
|
-
updatePosition
|
345
|
-
var _a;
|
346
|
-
|
347
|
-
(_a = popperInstanceRef.current) === null || _a === void 0 ? void 0 : _a.update();
|
348
|
-
},
|
102
|
+
updatePosition,
|
349
103
|
setTarget: target => {
|
350
104
|
if (options.target && process.env.NODE_ENV !== 'production') {
|
351
105
|
const err = new Error(); // eslint-disable-next-line no-console
|
@@ -359,34 +113,31 @@ function usePositioning(options = {}) {
|
|
359
113
|
}
|
360
114
|
}), // Missing deps:
|
361
115
|
// options.target - only used for a runtime warning
|
362
|
-
//
|
116
|
+
// overrideTargetRef - Stable between renders
|
117
|
+
// updatePosition - Stable between renders
|
363
118
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
364
119
|
[]);
|
365
120
|
react_utilities_1.useIsomorphicLayoutEffect(() => {
|
366
121
|
if (options.target) {
|
367
122
|
overrideTargetRef.current = options.target;
|
368
123
|
}
|
369
|
-
}, [options.target, overrideTargetRef]);
|
124
|
+
}, [options.target, overrideTargetRef, containerRef]);
|
370
125
|
react_utilities_1.useIsomorphicLayoutEffect(() => {
|
371
|
-
|
372
|
-
|
373
|
-
var _a;
|
126
|
+
updatePosition();
|
127
|
+
}, [enabled, resolvePositioningOptions, updatePosition]); // Add window resize and scroll listeners to update position
|
374
128
|
|
375
|
-
(_a = popperInstanceRef.current) === null || _a === void 0 ? void 0 : _a.destroy();
|
376
|
-
popperInstanceRef.current = null;
|
377
|
-
};
|
378
|
-
}, [handlePopperUpdate, options.enabled]);
|
379
129
|
react_utilities_1.useIsomorphicLayoutEffect(() => {
|
380
|
-
|
381
|
-
|
382
|
-
if (
|
383
|
-
|
130
|
+
const win = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView;
|
131
|
+
|
132
|
+
if (win) {
|
133
|
+
win.addEventListener('resize', updatePosition);
|
134
|
+
win.addEventListener('scroll', updatePosition);
|
135
|
+
return () => {
|
136
|
+
win.removeEventListener('resize', updatePosition);
|
137
|
+
win.removeEventListener('scroll', updatePosition);
|
138
|
+
};
|
384
139
|
}
|
385
|
-
},
|
386
|
-
// isFirstMount - Should never change after mount
|
387
|
-
// arrowRef, containerRef, targetRef - Stable between renders
|
388
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
389
|
-
[resolvePopperOptions]);
|
140
|
+
}, [updatePosition, targetDocument]);
|
390
141
|
|
391
142
|
if (process.env.NODE_ENV !== 'production') {
|
392
143
|
// This checked should run only in development mode
|
@@ -397,10 +148,10 @@ function usePositioning(options = {}) {
|
|
397
148
|
if (containerRef.current) {
|
398
149
|
const contentNode = containerRef.current;
|
399
150
|
const treeWalker = (_a = contentNode.ownerDocument) === null || _a === void 0 ? void 0 : _a.createTreeWalker(contentNode, NodeFilter.SHOW_ELEMENT, {
|
400
|
-
acceptNode: hasAutofocusFilter
|
151
|
+
acceptNode: utils_1.hasAutofocusFilter
|
401
152
|
});
|
402
153
|
|
403
|
-
while (treeWalker
|
154
|
+
while (treeWalker.nextNode()) {
|
404
155
|
const node = treeWalker.currentNode; // eslint-disable-next-line no-console
|
405
156
|
|
406
157
|
console.warn('<Popper>:', node); // eslint-disable-next-line no-console
|
@@ -422,4 +173,152 @@ function usePositioning(options = {}) {
|
|
422
173
|
}
|
423
174
|
|
424
175
|
exports.usePositioning = usePositioning;
|
176
|
+
|
177
|
+
function usePositioningOptions(options) {
|
178
|
+
const {
|
179
|
+
align,
|
180
|
+
arrowPadding,
|
181
|
+
autoSize,
|
182
|
+
coverTarget,
|
183
|
+
flipBoundary,
|
184
|
+
offset,
|
185
|
+
overflowBoundary,
|
186
|
+
pinned,
|
187
|
+
position,
|
188
|
+
unstable_disableTether: disableTether,
|
189
|
+
positionFixed
|
190
|
+
} = options;
|
191
|
+
const {
|
192
|
+
dir
|
193
|
+
} = react_shared_contexts_1.useFluent_unstable();
|
194
|
+
const isRtl = dir === 'rtl';
|
195
|
+
const strategy = positionFixed ? 'fixed' : 'absolute';
|
196
|
+
return React.useCallback((target, container, arrow) => {
|
197
|
+
const hasScrollableElement = utils_1.hasScrollParent(container);
|
198
|
+
const placement = utils_1.toFloatingUIPlacement(align, position, isRtl);
|
199
|
+
const middleware = [offset && middleware_1.offset(offset), coverTarget && middleware_1.coverTarget(), !pinned && middleware_1.flip({
|
200
|
+
container,
|
201
|
+
flipBoundary,
|
202
|
+
hasScrollableElement
|
203
|
+
}), middleware_1.shift({
|
204
|
+
container,
|
205
|
+
hasScrollableElement,
|
206
|
+
overflowBoundary,
|
207
|
+
disableTether
|
208
|
+
}), autoSize && middleware_1.maxSize(autoSize), middleware_1.intersecting(), arrow && dom_1.arrow({
|
209
|
+
element: arrow,
|
210
|
+
padding: arrowPadding
|
211
|
+
}), dom_1.hide({
|
212
|
+
strategy: 'referenceHidden'
|
213
|
+
}), dom_1.hide({
|
214
|
+
strategy: 'escaped'
|
215
|
+
})].filter(Boolean);
|
216
|
+
return {
|
217
|
+
placement,
|
218
|
+
middleware,
|
219
|
+
strategy
|
220
|
+
};
|
221
|
+
}, [align, arrowPadding, autoSize, coverTarget, disableTether, flipBoundary, isRtl, offset, overflowBoundary, pinned, position, strategy]);
|
222
|
+
}
|
223
|
+
|
224
|
+
function useContainerRef(updatePosition, enabled) {
|
225
|
+
return utils_1.useCallbackRef(null, (container, prevContainer) => {
|
226
|
+
if (container && enabled) {
|
227
|
+
// When the container is first resolved, set position `fixed` to avoid scroll jumps.
|
228
|
+
// Without this scroll jumps can occur when the element is rendered initially and receives focus
|
229
|
+
Object.assign(container.style, {
|
230
|
+
position: 'fixed',
|
231
|
+
left: 0,
|
232
|
+
top: 0,
|
233
|
+
margin: 0
|
234
|
+
});
|
235
|
+
}
|
236
|
+
|
237
|
+
utils_1.toggleScrollListener(container, prevContainer, updatePosition);
|
238
|
+
updatePosition();
|
239
|
+
});
|
240
|
+
}
|
241
|
+
|
242
|
+
function useTargetRef(updatePosition) {
|
243
|
+
return utils_1.useCallbackRef(null, (target, prevTarget) => {
|
244
|
+
utils_1.toggleScrollListener(target, prevTarget, updatePosition);
|
245
|
+
updatePosition();
|
246
|
+
});
|
247
|
+
}
|
248
|
+
|
249
|
+
function useArrowRef(updatePosition) {
|
250
|
+
return utils_1.useCallbackRef(null, updatePosition);
|
251
|
+
}
|
252
|
+
/**
|
253
|
+
* Writes all DOM element updates after position is computed
|
254
|
+
*/
|
255
|
+
|
256
|
+
|
257
|
+
function writeContainerUpdates(options) {
|
258
|
+
var _a, _b;
|
259
|
+
|
260
|
+
const {
|
261
|
+
container,
|
262
|
+
placement,
|
263
|
+
middlewareData,
|
264
|
+
strategy,
|
265
|
+
lowPPI,
|
266
|
+
coordinates: {
|
267
|
+
x,
|
268
|
+
y
|
269
|
+
}
|
270
|
+
} = options;
|
271
|
+
|
272
|
+
if (!container) {
|
273
|
+
return;
|
274
|
+
}
|
275
|
+
|
276
|
+
container.setAttribute(constants_1.DATA_POSITIONING_PLACEMENT, placement);
|
277
|
+
container.removeAttribute(constants_1.DATA_POSITIONING_INTERSECTING);
|
278
|
+
|
279
|
+
if (middlewareData.intersectionObserver.intersecting) {
|
280
|
+
container.setAttribute(constants_1.DATA_POSITIONING_INTERSECTING, '');
|
281
|
+
}
|
282
|
+
|
283
|
+
container.removeAttribute(constants_1.DATA_POSITIONING_ESCAPED);
|
284
|
+
|
285
|
+
if ((_a = middlewareData.hide) === null || _a === void 0 ? void 0 : _a.escaped) {
|
286
|
+
container.setAttribute(constants_1.DATA_POSITIONING_ESCAPED, '');
|
287
|
+
}
|
288
|
+
|
289
|
+
container.removeAttribute(constants_1.DATA_POSITIONING_HIDDEN);
|
290
|
+
|
291
|
+
if ((_b = middlewareData.hide) === null || _b === void 0 ? void 0 : _b.referenceHidden) {
|
292
|
+
container.setAttribute(constants_1.DATA_POSITIONING_HIDDEN, '');
|
293
|
+
}
|
294
|
+
|
295
|
+
Object.assign(container.style, {
|
296
|
+
transform: lowPPI ? `translate(${x}px, ${y}px)` : `translate3d(${x}px, ${y}px, 0)`,
|
297
|
+
position: strategy
|
298
|
+
});
|
299
|
+
}
|
300
|
+
/**
|
301
|
+
* Writes all DOM element updates after position is computed
|
302
|
+
*/
|
303
|
+
|
304
|
+
|
305
|
+
function writeArrowUpdates(options) {
|
306
|
+
const {
|
307
|
+
arrow,
|
308
|
+
middlewareData
|
309
|
+
} = options;
|
310
|
+
|
311
|
+
if (!middlewareData.arrow || !arrow) {
|
312
|
+
return;
|
313
|
+
}
|
314
|
+
|
315
|
+
const {
|
316
|
+
x: arrowX,
|
317
|
+
y: arrowY
|
318
|
+
} = middlewareData.arrow;
|
319
|
+
Object.assign(arrow.style, {
|
320
|
+
left: `${arrowX}px`,
|
321
|
+
top: `${arrowY}px`
|
322
|
+
});
|
323
|
+
}
|
425
324
|
//# sourceMappingURL=usePositioning.js.map
|