@react-aria/overlays 3.15.0 → 3.17.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/overlays",
3
- "version": "3.15.0",
3
+ "version": "3.17.0",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -22,16 +22,16 @@
22
22
  "url": "https://github.com/adobe/react-spectrum"
23
23
  },
24
24
  "dependencies": {
25
- "@react-aria/focus": "^3.13.0",
26
- "@react-aria/i18n": "^3.8.0",
27
- "@react-aria/interactions": "^3.16.0",
28
- "@react-aria/ssr": "^3.7.0",
29
- "@react-aria/utils": "^3.18.0",
30
- "@react-aria/visually-hidden": "^3.8.2",
31
- "@react-stately/overlays": "^3.6.0",
32
- "@react-types/button": "^3.7.3",
33
- "@react-types/overlays": "^3.8.0",
34
- "@react-types/shared": "^3.18.1",
25
+ "@react-aria/focus": "^3.14.1",
26
+ "@react-aria/i18n": "^3.8.2",
27
+ "@react-aria/interactions": "^3.18.0",
28
+ "@react-aria/ssr": "^3.8.0",
29
+ "@react-aria/utils": "^3.20.0",
30
+ "@react-aria/visually-hidden": "^3.8.4",
31
+ "@react-stately/overlays": "^3.6.2",
32
+ "@react-types/button": "^3.8.0",
33
+ "@react-types/overlays": "^3.8.2",
34
+ "@react-types/shared": "^3.20.0",
35
35
  "@swc/helpers": "^0.5.0"
36
36
  },
37
37
  "peerDependencies": {
@@ -41,5 +41,5 @@
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  },
44
- "gitHead": "504e40e0a50c1b20ed0fb3ba9561a263b6d5565e"
44
+ "gitHead": "54fbaa67cc56867506811819fef765546d403253"
45
45
  }
package/src/Overlay.tsx CHANGED
@@ -29,7 +29,12 @@ export interface OverlayProps {
29
29
  * This option should be used very carefully. When focus management is disabled, you must
30
30
  * implement focus containment and restoration to ensure the overlay is keyboard accessible.
31
31
  */
32
- disableFocusManagement?: boolean
32
+ disableFocusManagement?: boolean,
33
+ /**
34
+ * Whether the overlay is currently performing an exit animation. When true,
35
+ * focus is allowed to move outside.
36
+ */
37
+ isExiting?: boolean
33
38
  }
34
39
 
35
40
  export const OverlayContext = React.createContext(null);
@@ -40,7 +45,7 @@ export const OverlayContext = React.createContext(null);
40
45
  */
41
46
  export function Overlay(props: OverlayProps) {
42
47
  let isSSR = useIsSSR();
43
- let {portalContainer = isSSR ? null : document.body} = props;
48
+ let {portalContainer = isSSR ? null : document.body, isExiting} = props;
44
49
  let [contain, setContain] = useState(false);
45
50
  let contextValue = useMemo(() => ({contain, setContain}), [contain, setContain]);
46
51
 
@@ -52,7 +57,7 @@ export function Overlay(props: OverlayProps) {
52
57
  if (!props.disableFocusManagement) {
53
58
  contents = (
54
59
  <OverlayContext.Provider value={contextValue}>
55
- <FocusScope restoreFocus contain={contain}>
60
+ <FocusScope restoreFocus contain={contain && !isExiting}>
56
61
  {props.children}
57
62
  </FocusScope>
58
63
  </OverlayContext.Provider>
@@ -101,7 +101,7 @@ const TOTAL_SIZE = {
101
101
  const PARSED_PLACEMENT_CACHE = {};
102
102
 
103
103
  // @ts-ignore
104
- let visualViewport = typeof window !== 'undefined' && window.visualViewport;
104
+ let visualViewport = typeof document !== 'undefined' && window.visualViewport;
105
105
 
106
106
  function getContainerDimensions(containerNode: Element): Dimensions {
107
107
  let width = 0, height = 0, totalWidth = 0, totalHeight = 0, top = 0, left = 0;
@@ -143,7 +143,9 @@ function getDelta(
143
143
  containerDimensions: Dimensions,
144
144
  padding: number
145
145
  ) {
146
- let containerScroll = containerDimensions.scroll[axis];
146
+ let root = document.scrollingElement || document.documentElement;
147
+ let isScrollPrevented = window.getComputedStyle(root).overflow === 'hidden';
148
+ let containerScroll = isScrollPrevented ? 0 : containerDimensions.scroll[axis];
147
149
  let containerHeight = containerDimensions[AXIS_SIZE[axis]];
148
150
 
149
151
  let startEdgeOffset = offset - padding - containerScroll;
@@ -393,7 +395,7 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
393
395
  offset,
394
396
  crossOffset,
395
397
  maxHeight,
396
- arrowSize,
398
+ arrowSize = 0,
397
399
  arrowBoundaryOffset = 0
398
400
  } = opts;
399
401
 
package/src/useOverlay.ts CHANGED
@@ -125,10 +125,16 @@ export function useOverlay(props: AriaOverlayProps, ref: RefObject<Element>): Ov
125
125
  let {focusWithinProps} = useFocusWithin({
126
126
  isDisabled: !shouldCloseOnBlur,
127
127
  onBlurWithin: (e) => {
128
+ // Do not close if relatedTarget is null, which means focus is lost to the body.
129
+ // That can happen when switching tabs, or due to a VoiceOver/Chrome bug with Control+Option+Arrow navigation.
130
+ // Clicking on the body to close the overlay should already be handled by useInteractOutside.
131
+ // https://github.com/adobe/react-spectrum/issues/4130
132
+ // https://github.com/adobe/react-spectrum/issues/4922
133
+ //
128
134
  // If focus is moving into a child focus scope (e.g. menu inside a dialog),
129
135
  // do not close the outer overlay. At this point, the active scope should
130
136
  // still be the outer overlay, since blur events run before focus.
131
- if (e.relatedTarget && isElementInChildOfActiveScope(e.relatedTarget)) {
137
+ if (!e.relatedTarget || isElementInChildOfActiveScope(e.relatedTarget)) {
132
138
  return;
133
139
  }
134
140
 
@@ -73,7 +73,7 @@ export interface PositionAria {
73
73
  }
74
74
 
75
75
  // @ts-ignore
76
- let visualViewport = typeof window !== 'undefined' && window.visualViewport;
76
+ let visualViewport = typeof document !== 'undefined' && window.visualViewport;
77
77
 
78
78
  /**
79
79
  * Handles positioning overlays like popovers and menus relative to a trigger
@@ -217,6 +217,8 @@ export function useOverlayPosition(props: AriaPositionProps): PositionAria {
217
217
  },
218
218
  placement: position.placement,
219
219
  arrowProps: {
220
+ 'aria-hidden': 'true',
221
+ role: 'presentation',
220
222
  style: {
221
223
  left: position.arrowOffsetLeft,
222
224
  top: position.arrowOffsetTop
@@ -18,7 +18,7 @@ interface PreventScrollOptions {
18
18
  }
19
19
 
20
20
  // @ts-ignore
21
- const visualViewport = typeof window !== 'undefined' && window.visualViewport;
21
+ const visualViewport = typeof document !== 'undefined' && window.visualViewport;
22
22
 
23
23
  // HTML input types that do not cause the software keyboard to appear.
24
24
  const nonTextInputTypes = new Set([