@fluentui/react-positioning 9.1.1 → 9.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. package/CHANGELOG.json +72 -2
  2. package/CHANGELOG.md +28 -3
  3. package/dist/index.d.ts +9 -16
  4. package/lib/constants.js +5 -0
  5. package/lib/constants.js.map +1 -0
  6. package/lib/middleware/coverTarget.js +40 -0
  7. package/lib/middleware/coverTarget.js.map +1 -0
  8. package/lib/middleware/flip.js +19 -0
  9. package/lib/middleware/flip.js.map +1 -0
  10. package/lib/middleware/index.js +7 -0
  11. package/lib/middleware/index.js.map +1 -0
  12. package/lib/middleware/intersecting.js +21 -0
  13. package/lib/middleware/intersecting.js.map +1 -0
  14. package/lib/middleware/maxSize.js +43 -0
  15. package/lib/middleware/maxSize.js.map +1 -0
  16. package/lib/middleware/offset.js +11 -0
  17. package/lib/middleware/offset.js.map +1 -0
  18. package/lib/middleware/shift.js +30 -0
  19. package/lib/middleware/shift.js.map +1 -0
  20. package/lib/usePositioning.js +234 -336
  21. package/lib/usePositioning.js.map +1 -1
  22. package/lib/utils/debounce.js +22 -0
  23. package/lib/utils/debounce.js.map +1 -0
  24. package/lib/utils/fromFloatingUIPlacement.js +43 -0
  25. package/lib/utils/fromFloatingUIPlacement.js.map +1 -0
  26. package/lib/utils/getBoundary.js +5 -1
  27. package/lib/utils/getBoundary.js.map +1 -1
  28. package/lib/utils/getFloatingUIOffset.js +36 -0
  29. package/lib/utils/getFloatingUIOffset.js.map +1 -0
  30. package/lib/utils/getScrollParent.js +6 -0
  31. package/lib/utils/getScrollParent.js.map +1 -1
  32. package/lib/utils/hasAutoFocusFilter.js +28 -0
  33. package/lib/utils/hasAutoFocusFilter.js.map +1 -0
  34. package/lib/utils/index.js +6 -2
  35. package/lib/utils/index.js.map +1 -1
  36. package/lib/utils/mergeArrowOffset.js +1 -1
  37. package/lib/utils/mergeArrowOffset.js.map +1 -1
  38. package/lib/utils/parseFloatingUIPlacement.js +14 -0
  39. package/lib/utils/parseFloatingUIPlacement.js.map +1 -0
  40. package/lib/utils/toFloatingUIPlacement.js +40 -0
  41. package/lib/utils/toFloatingUIPlacement.js.map +1 -0
  42. package/lib/utils/toggleScrollListener.js +24 -0
  43. package/lib/utils/toggleScrollListener.js.map +1 -0
  44. package/lib-commonjs/constants.js +11 -0
  45. package/lib-commonjs/constants.js.map +1 -0
  46. package/lib-commonjs/middleware/coverTarget.js +50 -0
  47. package/lib-commonjs/middleware/coverTarget.js.map +1 -0
  48. package/lib-commonjs/middleware/flip.js +30 -0
  49. package/lib-commonjs/middleware/flip.js.map +1 -0
  50. package/lib-commonjs/middleware/index.js +20 -0
  51. package/lib-commonjs/middleware/index.js.map +1 -0
  52. package/lib-commonjs/middleware/intersecting.js +31 -0
  53. package/lib-commonjs/middleware/intersecting.js.map +1 -0
  54. package/lib-commonjs/middleware/maxSize.js +54 -0
  55. package/lib-commonjs/middleware/maxSize.js.map +1 -0
  56. package/lib-commonjs/middleware/offset.js +22 -0
  57. package/lib-commonjs/middleware/offset.js.map +1 -0
  58. package/lib-commonjs/middleware/shift.js +41 -0
  59. package/lib-commonjs/middleware/shift.js.map +1 -0
  60. package/lib-commonjs/usePositioning.js +236 -337
  61. package/lib-commonjs/usePositioning.js.map +1 -1
  62. package/lib-commonjs/utils/debounce.js +31 -0
  63. package/lib-commonjs/utils/debounce.js.map +1 -0
  64. package/lib-commonjs/utils/fromFloatingUIPlacement.js +52 -0
  65. package/lib-commonjs/utils/fromFloatingUIPlacement.js.map +1 -0
  66. package/lib-commonjs/utils/getBoundary.js +5 -1
  67. package/lib-commonjs/utils/getBoundary.js.map +1 -1
  68. package/lib-commonjs/utils/getFloatingUIOffset.js +46 -0
  69. package/lib-commonjs/utils/getFloatingUIOffset.js.map +1 -0
  70. package/lib-commonjs/utils/getScrollParent.js +10 -1
  71. package/lib-commonjs/utils/getScrollParent.js.map +1 -1
  72. package/lib-commonjs/utils/hasAutoFocusFilter.js +37 -0
  73. package/lib-commonjs/utils/hasAutoFocusFilter.js.map +1 -0
  74. package/lib-commonjs/utils/index.js +10 -2
  75. package/lib-commonjs/utils/index.js.map +1 -1
  76. package/lib-commonjs/utils/mergeArrowOffset.js +1 -1
  77. package/lib-commonjs/utils/mergeArrowOffset.js.map +1 -1
  78. package/lib-commonjs/utils/parseFloatingUIPlacement.js +23 -0
  79. package/lib-commonjs/utils/parseFloatingUIPlacement.js.map +1 -0
  80. package/lib-commonjs/utils/toFloatingUIPlacement.js +49 -0
  81. package/lib-commonjs/utils/toFloatingUIPlacement.js.map +1 -0
  82. package/lib-commonjs/utils/toggleScrollListener.js +34 -0
  83. package/lib-commonjs/utils/toggleScrollListener.js.map +1 -0
  84. package/package.json +7 -7
  85. package/dist/tsdoc-metadata.json +0 -11
  86. package/lib/isIntersectingModifier.js +0 -26
  87. package/lib/isIntersectingModifier.js.map +0 -1
  88. package/lib/utils/fromPopperPlacement.js +0 -40
  89. package/lib/utils/fromPopperPlacement.js.map +0 -1
  90. package/lib/utils/getPopperOffset.js +0 -44
  91. package/lib/utils/getPopperOffset.js.map +0 -1
  92. package/lib/utils/parsePopperPlacement.js +0 -14
  93. package/lib/utils/parsePopperPlacement.js.map +0 -1
  94. package/lib/utils/positioningHelper.js +0 -49
  95. package/lib/utils/positioningHelper.js.map +0 -1
  96. package/lib-commonjs/isIntersectingModifier.js +0 -34
  97. package/lib-commonjs/isIntersectingModifier.js.map +0 -1
  98. package/lib-commonjs/utils/fromPopperPlacement.js +0 -50
  99. package/lib-commonjs/utils/fromPopperPlacement.js.map +0 -1
  100. package/lib-commonjs/utils/getPopperOffset.js +0 -54
  101. package/lib-commonjs/utils/getPopperOffset.js.map +0 -1
  102. package/lib-commonjs/utils/parsePopperPlacement.js +0 -23
  103. package/lib-commonjs/utils/parsePopperPlacement.js.map +0 -1
  104. package/lib-commonjs/utils/positioningHelper.js +0 -61
  105. 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 react_utilities_1 = /*#__PURE__*/require("@fluentui/react-utilities");
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 PopperJs = /*#__PURE__*/require("@popperjs/core");
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
- const isAutoFocusableElement = node.nodeName === 'BUTTON' || node.nodeName === 'INPUT' || node.nodeName === 'SELECT' || node.nodeName === 'TEXTAREA';
16
+ const React = /*#__PURE__*/require("react");
35
17
 
36
- if (isAutoFocusableElement) {
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
- return false;
41
- }
20
+ const middleware_1 = /*#__PURE__*/require("./middleware");
42
21
 
43
- function hasAutofocusFilter(node) {
44
- return hasAutofocusProp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
45
- }
22
+ const constants_1 = /*#__PURE__*/require("./constants");
46
23
  /**
47
- * Provides a callback to resolve Popper options, it's stable and should be used as a dependency to trigger updates
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 usePopperOptions(options, popperOriginalPositionRef) {
28
+ function usePositioning(options) {
56
29
  const {
57
- align,
58
- arrowPadding,
59
- autoSize,
60
- coverTarget,
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 isRtl = react_shared_contexts_1.useFluent_unstable().dir === 'rtl';
71
- const placement = index_1.getPlacement(align, position, isRtl);
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 scrollParentElement = index_1.getScrollParent(container);
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
- }].filter(Boolean); // filter boolean conditional spreading values
41
+ if (!react_utilities_1.canUseDOM || !enabled || !target || !containerRef.current) {
42
+ return;
43
+ }
255
44
 
256
- const popperOptions = {
257
- modifiers,
45
+ const {
258
46
  placement,
47
+ middleware,
259
48
  strategy
260
- };
261
- return popperOptions;
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
- function usePositioning(options = {}) {
277
- const {
278
- enabled = true
279
- } = options;
280
- const isFirstMount = react_utilities_1.useFirstMount();
281
- const popperOriginalPositionRef = React.useRef('absolute');
282
- const resolvePopperOptions = usePopperOptions(options, popperOriginalPositionRef);
283
- const popperInstanceRef = React.useRef(null);
284
- const handlePopperUpdate = react_utilities_1.useEventCallback(() => {
285
- var _a, _b;
286
-
287
- (_a = popperInstanceRef.current) === null || _a === void 0 ? void 0 : _a.destroy();
288
- popperInstanceRef.current = null;
289
- const target = (_b = overrideTargetRef.current) !== null && _b !== void 0 ? _b : targetRef.current;
290
- let popperInstance = null;
291
-
292
- if (react_utilities_1.canUseDOM() && enabled) {
293
- if (target && containerRef.current) {
294
- popperInstance = PopperJs.createPopper(target, containerRef.current, resolvePopperOptions(target, containerRef.current, arrowRef.current));
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
- if (popperInstance) {
299
- /**
300
- * The patch updates `.forceUpdate()` Popper function which restores the original position before the first
301
- * forceUpdate() call. See also "positionStyleFix" modifier in usePopperOptions().
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
- // targetRef - Stable between renders
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
- handlePopperUpdate();
372
- return () => {
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
- var _a, _b;
381
-
382
- if (!isFirstMount) {
383
- (_a = popperInstanceRef.current) === null || _a === void 0 ? void 0 : _a.setOptions(resolvePopperOptions((_b = overrideTargetRef.current) !== null && _b !== void 0 ? _b : targetRef.current, containerRef.current, arrowRef.current));
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
- }, // Missing deps:
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 === null || treeWalker === void 0 ? void 0 : treeWalker.nextNode()) {
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