@react-aria/overlays 3.13.0 → 3.14.0

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/dist/module.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import $k7QOs$react, {useState as $k7QOs$useState, useCallback as $k7QOs$useCallback, useRef as $k7QOs$useRef, useEffect as $k7QOs$useEffect, useContext as $k7QOs$useContext, useMemo as $k7QOs$useMemo} from "react";
2
- import {useLayoutEffect as $k7QOs$useLayoutEffect, useResizeObserver as $k7QOs$useResizeObserver, useId as $k7QOs$useId, isIOS as $k7QOs$isIOS, chain as $k7QOs$chain, getScrollParent as $k7QOs$getScrollParent, useLabels as $k7QOs$useLabels, mergeProps as $k7QOs$mergeProps} from "@react-aria/utils";
2
+ import {useLayoutEffect as $k7QOs$useLayoutEffect, useResizeObserver as $k7QOs$useResizeObserver, clamp as $k7QOs$clamp, useId as $k7QOs$useId, isIOS as $k7QOs$isIOS, chain as $k7QOs$chain, getScrollParent as $k7QOs$getScrollParent, useLabels as $k7QOs$useLabels, mergeProps as $k7QOs$mergeProps} from "@react-aria/utils";
3
3
  import {useLocale as $k7QOs$useLocale, useLocalizedStringFormatter as $k7QOs$useLocalizedStringFormatter} from "@react-aria/i18n";
4
4
  import {isElementInChildOfActiveScope as $k7QOs$isElementInChildOfActiveScope, FocusScope as $k7QOs$FocusScope} from "@react-aria/focus";
5
5
  import {useInteractOutside as $k7QOs$useInteractOutside, useFocusWithin as $k7QOs$useFocusWithin} from "@react-aria/interactions";
@@ -40,7 +40,8 @@ function $parcel$interopDefault(a) {
40
40
  * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
41
41
  * OF ANY KIND, either express or implied. See the License for the specific language
42
42
  * governing permissions and limitations under the License.
43
- */ const $edcf132a9284368a$var$AXIS = {
43
+ */
44
+ const $edcf132a9284368a$var$AXIS = {
44
45
  top: "top",
45
46
  bottom: "top",
46
47
  left: "left",
@@ -60,28 +61,38 @@ const $edcf132a9284368a$var$AXIS_SIZE = {
60
61
  top: "height",
61
62
  left: "width"
62
63
  };
64
+ const $edcf132a9284368a$var$TOTAL_SIZE = {
65
+ width: "totalWidth",
66
+ height: "totalHeight"
67
+ };
63
68
  const $edcf132a9284368a$var$PARSED_PLACEMENT_CACHE = {};
64
69
  // @ts-ignore
65
70
  let $edcf132a9284368a$var$visualViewport = typeof window !== "undefined" && window.visualViewport;
66
71
  function $edcf132a9284368a$var$getContainerDimensions(containerNode) {
67
- let width = 0, height = 0, top = 0, left = 0;
72
+ let width = 0, height = 0, totalWidth = 0, totalHeight = 0, top = 0, left = 0;
68
73
  let scroll = {};
69
74
  if (containerNode.tagName === "BODY") {
70
75
  let documentElement = document.documentElement;
76
+ totalWidth = documentElement.clientWidth;
77
+ totalHeight = documentElement.clientHeight;
71
78
  var _visualViewport_width;
72
- width = (_visualViewport_width = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.width) !== null && _visualViewport_width !== void 0 ? _visualViewport_width : documentElement.clientWidth;
79
+ width = (_visualViewport_width = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.width) !== null && _visualViewport_width !== void 0 ? _visualViewport_width : totalWidth;
73
80
  var _visualViewport_height;
74
- height = (_visualViewport_height = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.height) !== null && _visualViewport_height !== void 0 ? _visualViewport_height : documentElement.clientHeight;
81
+ height = (_visualViewport_height = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.height) !== null && _visualViewport_height !== void 0 ? _visualViewport_height : totalHeight;
75
82
  scroll.top = documentElement.scrollTop || containerNode.scrollTop;
76
83
  scroll.left = documentElement.scrollLeft || containerNode.scrollLeft;
77
84
  } else {
78
85
  ({ width: width , height: height , top: top , left: left } = $edcf132a9284368a$var$getOffset(containerNode));
79
86
  scroll.top = containerNode.scrollTop;
80
87
  scroll.left = containerNode.scrollLeft;
88
+ totalWidth = width;
89
+ totalHeight = height;
81
90
  }
82
91
  return {
83
92
  width: width,
84
93
  height: height,
94
+ totalWidth: totalWidth,
95
+ totalHeight: totalHeight,
85
96
  scroll: scroll,
86
97
  top: top,
87
98
  left: left
@@ -131,7 +142,7 @@ function $edcf132a9284368a$var$parsePlacement(input) {
131
142
  };
132
143
  return $edcf132a9284368a$var$PARSED_PLACEMENT_CACHE[input];
133
144
  }
134
- function $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned) {
145
+ function $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset) {
135
146
  let { placement: placement , crossPlacement: crossPlacement , axis: axis , crossAxis: crossAxis , size: size , crossSize: crossSize } = placementInfo;
136
147
  let position = {};
137
148
  // button position
@@ -147,19 +158,18 @@ function $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions,
147
158
  } */
148
159
  // add the crossOffset from props
149
160
  position[crossAxis] += crossOffset;
150
- // this is button center position - the overlay size + half of the button to align bottom of overlay with button center
151
- let minViablePosition = childOffset[crossAxis] + childOffset[crossSize] / 2 - overlaySize[crossSize];
152
- // this is button position of center, aligns top of overlay with button center
153
- let maxViablePosition = childOffset[crossAxis] + childOffset[crossSize] / 2;
154
- // clamp it into the range of the min/max positions
155
- position[crossAxis] = Math.min(Math.max(minViablePosition, position[crossAxis]), maxViablePosition);
161
+ // overlay top overlapping arrow with button bottom
162
+ const minPosition = childOffset[crossAxis] - overlaySize[crossSize] + arrowSize + arrowBoundaryOffset;
163
+ // overlay bottom overlapping arrow with button top
164
+ const maxPosition = childOffset[crossAxis] + childOffset[crossSize] - arrowSize - arrowBoundaryOffset;
165
+ position[crossAxis] = (0, $k7QOs$clamp)(position[crossAxis], minPosition, maxPosition);
156
166
  // Floor these so the position isn't placed on a partial pixel, only whole pixels. Shouldn't matter if it was floored or ceiled, so chose one.
157
167
  if (placement === axis) {
158
168
  // If the container is positioned (non-static), then we use the container's actual
159
169
  // height, as `bottom` will be relative to this height. But if the container is static,
160
170
  // then it can only be the `document.body`, and `bottom` will be relative to _its_
161
171
  // container, which should be as large as boundaryDimensions.
162
- const containerHeight = isContainerPositioned ? containerOffsetWithBoundary[size] : boundaryDimensions[size];
172
+ const containerHeight = isContainerPositioned ? containerOffsetWithBoundary[size] : boundaryDimensions[$edcf132a9284368a$var$TOTAL_SIZE[size]];
163
173
  position[$edcf132a9284368a$var$FLIPPED_DIRECTION[axis]] = Math.floor(containerHeight - childOffset[axis] + offset);
164
174
  } else position[axis] = Math.floor(childOffset[axis] + childOffset[size] + offset);
165
175
  return position;
@@ -178,16 +188,16 @@ function $edcf132a9284368a$var$getAvailableSpace(boundaryDimensions, containerOf
178
188
  if (placement === axis) return Math.max(0, childOffset[axis] - boundaryDimensions[axis] - boundaryDimensions.scroll[axis] + containerOffsetWithBoundary[axis] - margins[axis] - margins[$edcf132a9284368a$var$FLIPPED_DIRECTION[axis]] - padding);
179
189
  return Math.max(0, boundaryDimensions[size] + boundaryDimensions[axis] + boundaryDimensions.scroll[axis] - containerOffsetWithBoundary[axis] - childOffset[axis] - childOffset[size] - margins[axis] - margins[$edcf132a9284368a$var$FLIPPED_DIRECTION[axis]] - padding);
180
190
  }
181
- function $edcf132a9284368a$export$6839422d1f33cee9(placementInput, childOffset, overlaySize, scrollSize, margins, padding, flip, boundaryDimensions, containerOffsetWithBoundary, offset, crossOffset, isContainerPositioned, userSetMaxHeight) {
191
+ function $edcf132a9284368a$export$6839422d1f33cee9(placementInput, childOffset, overlaySize, scrollSize, margins, padding, flip, boundaryDimensions, containerOffsetWithBoundary, offset, crossOffset, isContainerPositioned, userSetMaxHeight, arrowSize, arrowBoundaryOffset) {
182
192
  let placementInfo = $edcf132a9284368a$var$parsePlacement(placementInput);
183
193
  let { size: size , crossAxis: crossAxis , crossSize: crossSize , placement: placement , crossPlacement: crossPlacement } = placementInfo;
184
- let position = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned);
194
+ let position = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
185
195
  let normalizedOffset = offset;
186
196
  let space = $edcf132a9284368a$var$getAvailableSpace(boundaryDimensions, containerOffsetWithBoundary, childOffset, margins, padding + offset, placementInfo);
187
197
  // Check if the scroll size of the overlay is greater than the available space to determine if we need to flip
188
198
  if (flip && scrollSize[size] > space) {
189
199
  let flippedPlacementInfo = $edcf132a9284368a$var$parsePlacement(`${$edcf132a9284368a$var$FLIPPED_DIRECTION[placement]} ${crossPlacement}`);
190
- let flippedPosition = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, flippedPlacementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned);
200
+ let flippedPosition = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, flippedPlacementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
191
201
  let flippedSpace = $edcf132a9284368a$var$getAvailableSpace(boundaryDimensions, containerOffsetWithBoundary, childOffset, margins, padding + offset, flippedPlacementInfo);
192
202
  // If the available space for the flipped position is greater than the original available space, flip.
193
203
  if (flippedSpace > space) {
@@ -201,11 +211,22 @@ function $edcf132a9284368a$export$6839422d1f33cee9(placementInput, childOffset,
201
211
  let maxHeight = $edcf132a9284368a$var$getMaxHeight(position, boundaryDimensions, containerOffsetWithBoundary, childOffset, margins, padding);
202
212
  if (userSetMaxHeight && userSetMaxHeight < maxHeight) maxHeight = userSetMaxHeight;
203
213
  overlaySize.height = Math.min(overlaySize.height, maxHeight);
204
- position = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, normalizedOffset, crossOffset, containerOffsetWithBoundary, isContainerPositioned);
214
+ position = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, normalizedOffset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
205
215
  delta = $edcf132a9284368a$var$getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, padding);
206
216
  position[crossAxis] += delta;
207
217
  let arrowPosition = {};
208
- arrowPosition[crossAxis] = childOffset[crossAxis] - position[crossAxis] + childOffset[crossSize] / 2;
218
+ // All values are transformed so that 0 is at the top/left of the overlay depending on the orientation
219
+ // Prefer the arrow being in the center of the trigger/overlay anchor element
220
+ let preferredArrowPosition = childOffset[crossAxis] + .5 * childOffset[crossSize] - overlaySize[crossAxis];
221
+ // Min/Max position limits for the arrow with respect to the overlay
222
+ const arrowMinPosition = arrowSize / 2 + arrowBoundaryOffset;
223
+ const arrowMaxPosition = overlaySize[crossSize] - arrowSize / 2 - arrowBoundaryOffset;
224
+ // Min/Max position limits for the arrow with respect to the trigger/overlay anchor element
225
+ const arrowOverlappingChildMinEdge = childOffset[crossAxis] - overlaySize[crossAxis] + arrowSize / 2;
226
+ const arrowOverlappingChildMaxEdge = childOffset[crossAxis] + childOffset[crossSize] - overlaySize[crossAxis] - arrowSize / 2;
227
+ // Clamp the arrow positioning so that it always is within the bounds of the anchor and the overlay
228
+ const arrowPositionOverlappingChild = (0, $k7QOs$clamp)(preferredArrowPosition, arrowOverlappingChildMinEdge, arrowOverlappingChildMaxEdge);
229
+ arrowPosition[crossAxis] = (0, $k7QOs$clamp)(arrowPositionOverlappingChild, arrowMinPosition, arrowMaxPosition);
209
230
  return {
210
231
  position: position,
211
232
  maxHeight: maxHeight,
@@ -215,13 +236,13 @@ function $edcf132a9284368a$export$6839422d1f33cee9(placementInput, childOffset,
215
236
  };
216
237
  }
217
238
  function $edcf132a9284368a$export$b3ceb0cbf1056d98(opts) {
218
- let { placement: placement , targetNode: targetNode , overlayNode: overlayNode , scrollNode: scrollNode , padding: padding , shouldFlip: shouldFlip , boundaryElement: boundaryElement , offset: offset , crossOffset: crossOffset , maxHeight: maxHeight } = opts;
219
- let container = overlayNode instanceof HTMLElement && overlayNode.offsetParent || document.body;
220
- let isBodyContainer = container.tagName === "BODY";
239
+ let { placement: placement , targetNode: targetNode , overlayNode: overlayNode , scrollNode: scrollNode , padding: padding , shouldFlip: shouldFlip , boundaryElement: boundaryElement , offset: offset , crossOffset: crossOffset , maxHeight: maxHeight , arrowSize: arrowSize , arrowBoundaryOffset: arrowBoundaryOffset = 0 } = opts;
240
+ let container = overlayNode instanceof HTMLElement ? $edcf132a9284368a$var$getContainingBlock(overlayNode) : document.documentElement;
241
+ let isViewportContainer = container === document.documentElement;
221
242
  const containerPositionStyle = window.getComputedStyle(container).position;
222
243
  let isContainerPositioned = !!containerPositionStyle && containerPositionStyle !== "static";
223
- let childOffset = isBodyContainer ? $edcf132a9284368a$var$getOffset(targetNode) : $edcf132a9284368a$var$getPosition(targetNode, container);
224
- if (!isBodyContainer) {
244
+ let childOffset = isViewportContainer ? $edcf132a9284368a$var$getOffset(targetNode) : $edcf132a9284368a$var$getPosition(targetNode, container);
245
+ if (!isViewportContainer) {
225
246
  let { marginTop: marginTop , marginLeft: marginLeft } = window.getComputedStyle(targetNode);
226
247
  childOffset.top += parseInt(marginTop, 10) || 0;
227
248
  childOffset.left += parseInt(marginLeft, 10) || 0;
@@ -233,7 +254,7 @@ function $edcf132a9284368a$export$b3ceb0cbf1056d98(opts) {
233
254
  let scrollSize = $edcf132a9284368a$var$getScroll(scrollNode);
234
255
  let boundaryDimensions = $edcf132a9284368a$var$getContainerDimensions(boundaryElement);
235
256
  let containerOffsetWithBoundary = boundaryElement.tagName === "BODY" ? $edcf132a9284368a$var$getOffset(container) : $edcf132a9284368a$var$getPosition(container, boundaryElement);
236
- return $edcf132a9284368a$export$6839422d1f33cee9(placement, childOffset, overlaySize, scrollSize, margins, padding, shouldFlip, boundaryDimensions, containerOffsetWithBoundary, offset, crossOffset, isContainerPositioned, maxHeight);
257
+ return $edcf132a9284368a$export$6839422d1f33cee9(placement, childOffset, overlaySize, scrollSize, margins, padding, shouldFlip, boundaryDimensions, containerOffsetWithBoundary, offset, crossOffset, isContainerPositioned, maxHeight, arrowSize, arrowBoundaryOffset);
237
258
  }
238
259
  function $edcf132a9284368a$var$getOffset(node) {
239
260
  let { top: top , left: left , width: width , height: height } = node.getBoundingClientRect();
@@ -269,6 +290,35 @@ function $edcf132a9284368a$var$getPosition(node, parent) {
269
290
  offset.left -= parseInt(style.marginLeft, 10) || 0;
270
291
  return offset;
271
292
  }
293
+ // Returns the containing block of an element, which is the element that
294
+ // this element will be positioned relative to.
295
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block
296
+ function $edcf132a9284368a$var$getContainingBlock(node) {
297
+ // The offsetParent of an element in most cases equals the containing block.
298
+ // https://w3c.github.io/csswg-drafts/cssom-view/#dom-htmlelement-offsetparent
299
+ let offsetParent = node.offsetParent;
300
+ // The offsetParent algorithm terminates at the document body,
301
+ // even if the body is not a containing block. Double check that
302
+ // and use the documentElement if so.
303
+ if (offsetParent && offsetParent === document.body && window.getComputedStyle(offsetParent).position === "static" && !$edcf132a9284368a$var$isContainingBlock(offsetParent)) offsetParent = document.documentElement;
304
+ // TODO(later): handle table elements?
305
+ // The offsetParent can be null if the element has position: fixed, or a few other cases.
306
+ // We have to walk up the tree manually in this case because fixed positioned elements
307
+ // are still positioned relative to their containing block, which is not always the viewport.
308
+ if (offsetParent == null) {
309
+ offsetParent = node.parentElement;
310
+ while(offsetParent && !$edcf132a9284368a$var$isContainingBlock(offsetParent))offsetParent = offsetParent.parentElement;
311
+ }
312
+ // Fall back to the viewport.
313
+ return offsetParent || document.documentElement;
314
+ }
315
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
316
+ function $edcf132a9284368a$var$isContainingBlock(node) {
317
+ let style = window.getComputedStyle(node);
318
+ return style.transform !== "none" || /transform|perspective/.test(style.willChange) || style.filter !== "none" || style.contain === "paint" || // @ts-ignore
319
+ "backdropFilter" in style && style.backdropFilter !== "none" || // @ts-ignore
320
+ "WebkitBackdropFilter" in style && style.WebkitBackdropFilter !== "none";
321
+ }
272
322
 
273
323
 
274
324
 
@@ -314,7 +364,7 @@ function $dd149f63282afbbf$export$18fc8428861184da(opts) {
314
364
  let $2a41e45df1593e64$var$visualViewport = typeof window !== "undefined" && window.visualViewport;
315
365
  function $2a41e45df1593e64$export$d39e1813b3bdd0e1(props) {
316
366
  let { direction: direction } = (0, $k7QOs$useLocale)();
317
- let { targetRef: targetRef , overlayRef: overlayRef , scrollRef: scrollRef = overlayRef , placement: placement = "bottom" , containerPadding: containerPadding = 12 , shouldFlip: shouldFlip = true , boundaryElement: boundaryElement = typeof document !== "undefined" ? document.body : null , offset: offset = 0 , crossOffset: crossOffset = 0 , shouldUpdatePosition: shouldUpdatePosition = true , isOpen: isOpen = true , onClose: onClose , maxHeight: maxHeight } = props;
367
+ let { arrowSize: arrowSize = 0 , targetRef: targetRef , overlayRef: overlayRef , scrollRef: scrollRef = overlayRef , placement: placement = "bottom" , containerPadding: containerPadding = 12 , shouldFlip: shouldFlip = true , boundaryElement: boundaryElement = typeof document !== "undefined" ? document.body : null , offset: offset = 0 , crossOffset: crossOffset = 0 , shouldUpdatePosition: shouldUpdatePosition = true , isOpen: isOpen = true , onClose: onClose , maxHeight: maxHeight , arrowBoundaryOffset: arrowBoundaryOffset = 0 } = props;
318
368
  let [position, setPosition] = (0, $k7QOs$useState)({
319
369
  position: {},
320
370
  arrowOffsetLeft: undefined,
@@ -335,7 +385,9 @@ function $2a41e45df1593e64$export$d39e1813b3bdd0e1(props) {
335
385
  crossOffset,
336
386
  isOpen,
337
387
  direction,
338
- maxHeight
388
+ maxHeight,
389
+ arrowBoundaryOffset,
390
+ arrowSize
339
391
  ];
340
392
  let updatePosition = (0, $k7QOs$useCallback)(()=>{
341
393
  if (shouldUpdatePosition === false || !isOpen || !overlayRef.current || !targetRef.current || !scrollRef.current || !boundaryElement) return;
@@ -349,7 +401,9 @@ function $2a41e45df1593e64$export$d39e1813b3bdd0e1(props) {
349
401
  boundaryElement: boundaryElement,
350
402
  offset: offset,
351
403
  crossOffset: crossOffset,
352
- maxHeight: maxHeight
404
+ maxHeight: maxHeight,
405
+ arrowSize: arrowSize,
406
+ arrowBoundaryOffset: arrowBoundaryOffset
353
407
  });
354
408
  // Modify overlay styles directly so positioning happens immediately without the need of a second render
355
409
  // This is so we don't have to delay autoFocus scrolling or delay applying preventScroll for popovers
@@ -383,8 +437,10 @@ function $2a41e45df1593e64$export$d39e1813b3bdd0e1(props) {
383
437
  updatePosition();
384
438
  };
385
439
  $2a41e45df1593e64$var$visualViewport === null || $2a41e45df1593e64$var$visualViewport === void 0 ? void 0 : $2a41e45df1593e64$var$visualViewport.addEventListener("resize", onResize);
440
+ $2a41e45df1593e64$var$visualViewport === null || $2a41e45df1593e64$var$visualViewport === void 0 ? void 0 : $2a41e45df1593e64$var$visualViewport.addEventListener("scroll", onResize);
386
441
  return ()=>{
387
442
  $2a41e45df1593e64$var$visualViewport === null || $2a41e45df1593e64$var$visualViewport === void 0 ? void 0 : $2a41e45df1593e64$var$visualViewport.removeEventListener("resize", onResize);
443
+ $2a41e45df1593e64$var$visualViewport === null || $2a41e45df1593e64$var$visualViewport === void 0 ? void 0 : $2a41e45df1593e64$var$visualViewport.removeEventListener("scroll", onResize);
388
444
  };
389
445
  }, [
390
446
  updatePosition