@fluentui/react-positioning 0.0.0-nightly-20220714-0418.1 → 0.0.0-nightly-20221007-1237.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.
Files changed (121) hide show
  1. package/CHANGELOG.json +122 -10
  2. package/CHANGELOG.md +53 -8
  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/createArrowStyles.js.map +1 -1
  7. package/lib/createVirtualElementFromClick.js.map +1 -1
  8. package/lib/index.js.map +1 -1
  9. package/lib/middleware/coverTarget.js +40 -0
  10. package/lib/middleware/coverTarget.js.map +1 -0
  11. package/lib/middleware/flip.js +19 -0
  12. package/lib/middleware/flip.js.map +1 -0
  13. package/lib/middleware/index.js +7 -0
  14. package/lib/middleware/index.js.map +1 -0
  15. package/lib/middleware/intersecting.js +21 -0
  16. package/lib/middleware/intersecting.js.map +1 -0
  17. package/lib/middleware/maxSize.js +43 -0
  18. package/lib/middleware/maxSize.js.map +1 -0
  19. package/lib/middleware/offset.js +11 -0
  20. package/lib/middleware/offset.js.map +1 -0
  21. package/lib/middleware/shift.js +30 -0
  22. package/lib/middleware/shift.js.map +1 -0
  23. package/lib/types.js.map +1 -1
  24. package/lib/usePositioning.js +234 -336
  25. package/lib/usePositioning.js.map +1 -1
  26. package/lib/usePositioningMouseTarget.js.map +1 -1
  27. package/lib/utils/debounce.js +22 -0
  28. package/lib/utils/debounce.js.map +1 -0
  29. package/lib/utils/fromFloatingUIPlacement.js +43 -0
  30. package/lib/utils/fromFloatingUIPlacement.js.map +1 -0
  31. package/lib/utils/getBoundary.js +5 -1
  32. package/lib/utils/getBoundary.js.map +1 -1
  33. package/lib/utils/getFloatingUIOffset.js +36 -0
  34. package/lib/utils/getFloatingUIOffset.js.map +1 -0
  35. package/lib/utils/getReactFiberFromNode.js.map +1 -1
  36. package/lib/utils/getScrollParent.js +6 -0
  37. package/lib/utils/getScrollParent.js.map +1 -1
  38. package/lib/utils/hasAutoFocusFilter.js +28 -0
  39. package/lib/utils/hasAutoFocusFilter.js.map +1 -0
  40. package/lib/utils/index.js +6 -2
  41. package/lib/utils/index.js.map +1 -1
  42. package/lib/utils/mergeArrowOffset.js +1 -1
  43. package/lib/utils/mergeArrowOffset.js.map +1 -1
  44. package/lib/utils/parseFloatingUIPlacement.js +14 -0
  45. package/lib/utils/parseFloatingUIPlacement.js.map +1 -0
  46. package/lib/utils/resolvePositioningShorthand.js.map +1 -1
  47. package/lib/utils/toFloatingUIPlacement.js +40 -0
  48. package/lib/utils/toFloatingUIPlacement.js.map +1 -0
  49. package/lib/utils/toggleScrollListener.js +24 -0
  50. package/lib/utils/toggleScrollListener.js.map +1 -0
  51. package/lib/utils/useCallbackRef.js.map +1 -1
  52. package/lib-commonjs/constants.js +11 -0
  53. package/lib-commonjs/constants.js.map +1 -0
  54. package/lib-commonjs/createArrowStyles.js.map +1 -1
  55. package/lib-commonjs/createVirtualElementFromClick.js.map +1 -1
  56. package/lib-commonjs/index.js.map +1 -1
  57. package/lib-commonjs/middleware/coverTarget.js +50 -0
  58. package/lib-commonjs/middleware/coverTarget.js.map +1 -0
  59. package/lib-commonjs/middleware/flip.js +30 -0
  60. package/lib-commonjs/middleware/flip.js.map +1 -0
  61. package/lib-commonjs/middleware/index.js +20 -0
  62. package/lib-commonjs/middleware/index.js.map +1 -0
  63. package/lib-commonjs/middleware/intersecting.js +31 -0
  64. package/lib-commonjs/middleware/intersecting.js.map +1 -0
  65. package/lib-commonjs/middleware/maxSize.js +54 -0
  66. package/lib-commonjs/middleware/maxSize.js.map +1 -0
  67. package/lib-commonjs/middleware/offset.js +22 -0
  68. package/lib-commonjs/middleware/offset.js.map +1 -0
  69. package/lib-commonjs/middleware/shift.js +41 -0
  70. package/lib-commonjs/middleware/shift.js.map +1 -0
  71. package/lib-commonjs/types.js.map +1 -1
  72. package/lib-commonjs/usePositioning.js +236 -337
  73. package/lib-commonjs/usePositioning.js.map +1 -1
  74. package/lib-commonjs/usePositioningMouseTarget.js.map +1 -1
  75. package/lib-commonjs/utils/debounce.js +31 -0
  76. package/lib-commonjs/utils/debounce.js.map +1 -0
  77. package/lib-commonjs/utils/fromFloatingUIPlacement.js +52 -0
  78. package/lib-commonjs/utils/fromFloatingUIPlacement.js.map +1 -0
  79. package/lib-commonjs/utils/getBoundary.js +5 -1
  80. package/lib-commonjs/utils/getBoundary.js.map +1 -1
  81. package/lib-commonjs/utils/getFloatingUIOffset.js +46 -0
  82. package/lib-commonjs/utils/getFloatingUIOffset.js.map +1 -0
  83. package/lib-commonjs/utils/getReactFiberFromNode.js.map +1 -1
  84. package/lib-commonjs/utils/getScrollParent.js +10 -1
  85. package/lib-commonjs/utils/getScrollParent.js.map +1 -1
  86. package/lib-commonjs/utils/hasAutoFocusFilter.js +37 -0
  87. package/lib-commonjs/utils/hasAutoFocusFilter.js.map +1 -0
  88. package/lib-commonjs/utils/index.js +10 -2
  89. package/lib-commonjs/utils/index.js.map +1 -1
  90. package/lib-commonjs/utils/mergeArrowOffset.js +1 -1
  91. package/lib-commonjs/utils/mergeArrowOffset.js.map +1 -1
  92. package/lib-commonjs/utils/parseFloatingUIPlacement.js +23 -0
  93. package/lib-commonjs/utils/parseFloatingUIPlacement.js.map +1 -0
  94. package/lib-commonjs/utils/resolvePositioningShorthand.js.map +1 -1
  95. package/lib-commonjs/utils/toFloatingUIPlacement.js +49 -0
  96. package/lib-commonjs/utils/toFloatingUIPlacement.js.map +1 -0
  97. package/lib-commonjs/utils/toggleScrollListener.js +34 -0
  98. package/lib-commonjs/utils/toggleScrollListener.js.map +1 -0
  99. package/lib-commonjs/utils/useCallbackRef.js.map +1 -1
  100. package/package.json +8 -12
  101. package/dist/tsdoc-metadata.json +0 -11
  102. package/lib/isIntersectingModifier.js +0 -26
  103. package/lib/isIntersectingModifier.js.map +0 -1
  104. package/lib/utils/fromPopperPlacement.js +0 -40
  105. package/lib/utils/fromPopperPlacement.js.map +0 -1
  106. package/lib/utils/getPopperOffset.js +0 -44
  107. package/lib/utils/getPopperOffset.js.map +0 -1
  108. package/lib/utils/parsePopperPlacement.js +0 -14
  109. package/lib/utils/parsePopperPlacement.js.map +0 -1
  110. package/lib/utils/positioningHelper.js +0 -49
  111. package/lib/utils/positioningHelper.js.map +0 -1
  112. package/lib-commonjs/isIntersectingModifier.js +0 -34
  113. package/lib-commonjs/isIntersectingModifier.js.map +0 -1
  114. package/lib-commonjs/utils/fromPopperPlacement.js +0 -50
  115. package/lib-commonjs/utils/fromPopperPlacement.js.map +0 -1
  116. package/lib-commonjs/utils/getPopperOffset.js +0 -54
  117. package/lib-commonjs/utils/getPopperOffset.js.map +0 -1
  118. package/lib-commonjs/utils/parsePopperPlacement.js +0 -23
  119. package/lib-commonjs/utils/parsePopperPlacement.js.map +0 -1
  120. package/lib-commonjs/utils/positioningHelper.js +0 -61
  121. 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