@react-aria/overlays 3.8.2 → 3.10.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/main.js +174 -113
- package/dist/main.js.map +1 -1
- package/dist/module.js +164 -95
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +30 -30
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/DismissButton.tsx +4 -4
- package/src/ariaHideOutside.ts +4 -4
- package/src/calculatePosition.ts +50 -26
- package/src/index.ts +12 -7
- package/src/useCloseOnScroll.ts +2 -2
- package/src/useModal.tsx +18 -11
- package/src/useOverlay.ts +14 -13
- package/src/useOverlayPosition.ts +12 -11
- package/src/useOverlayTrigger.ts +8 -6
package/dist/types.d.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DOMAttributes, AriaLabelingProps, DOMProps } from "@react-types/shared";
|
|
2
2
|
import { PlacementAxis, PositionProps } from "@react-types/overlays";
|
|
3
|
+
import React, { RefObject, AriaAttributes, ReactNode } from "react";
|
|
3
4
|
import { AriaButtonProps } from "@react-types/button";
|
|
4
5
|
import { OverlayTriggerState } from "@react-stately/overlays";
|
|
5
|
-
|
|
6
|
-
interface AriaPositionProps extends PositionProps {
|
|
6
|
+
export interface AriaPositionProps extends PositionProps {
|
|
7
7
|
/**
|
|
8
8
|
* Element that that serves as the positioning boundary.
|
|
9
9
|
* @default document.body
|
|
10
10
|
*/
|
|
11
|
-
boundaryElement?:
|
|
11
|
+
boundaryElement?: Element;
|
|
12
12
|
/**
|
|
13
13
|
* The ref for the element which the overlay positions itself with respect to.
|
|
14
14
|
*/
|
|
15
|
-
targetRef: RefObject<
|
|
15
|
+
targetRef: RefObject<Element>;
|
|
16
16
|
/**
|
|
17
17
|
* The ref for the overlay element.
|
|
18
18
|
*/
|
|
19
|
-
overlayRef: RefObject<
|
|
19
|
+
overlayRef: RefObject<Element>;
|
|
20
20
|
/**
|
|
21
21
|
* A ref for the scrollable region within the overlay.
|
|
22
22
|
* @default overlayRef
|
|
23
23
|
*/
|
|
24
|
-
scrollRef?: RefObject<
|
|
24
|
+
scrollRef?: RefObject<Element>;
|
|
25
25
|
/**
|
|
26
26
|
* Whether the overlay should update its position automatically.
|
|
27
27
|
* @default true
|
|
@@ -35,11 +35,11 @@ interface AriaPositionProps extends PositionProps {
|
|
|
35
35
|
*/
|
|
36
36
|
maxHeight?: number;
|
|
37
37
|
}
|
|
38
|
-
interface PositionAria {
|
|
38
|
+
export interface PositionAria {
|
|
39
39
|
/** Props for the overlay container element. */
|
|
40
|
-
overlayProps:
|
|
40
|
+
overlayProps: DOMAttributes;
|
|
41
41
|
/** Props for the overlay tip arrow if any. */
|
|
42
|
-
arrowProps:
|
|
42
|
+
arrowProps: DOMAttributes;
|
|
43
43
|
/** Placement of the overlay with respect to the overlay trigger. */
|
|
44
44
|
placement: PlacementAxis;
|
|
45
45
|
/** Updates the position of the overlay. */
|
|
@@ -50,7 +50,7 @@ interface PositionAria {
|
|
|
50
50
|
* element, and updating the position when the window resizes.
|
|
51
51
|
*/
|
|
52
52
|
export function useOverlayPosition(props: AriaPositionProps): PositionAria;
|
|
53
|
-
interface
|
|
53
|
+
export interface AriaOverlayProps {
|
|
54
54
|
/** Whether the overlay is currently open. */
|
|
55
55
|
isOpen?: boolean;
|
|
56
56
|
/** Handler that is called when the overlay should close. */
|
|
@@ -73,35 +73,35 @@ interface OverlayProps {
|
|
|
73
73
|
* out interaction with elements that should not dismiss the overlay.
|
|
74
74
|
* By default, onClose will always be called on interaction outside the overlay ref.
|
|
75
75
|
*/
|
|
76
|
-
shouldCloseOnInteractOutside?: (element:
|
|
76
|
+
shouldCloseOnInteractOutside?: (element: Element) => boolean;
|
|
77
77
|
}
|
|
78
|
-
interface OverlayAria {
|
|
78
|
+
export interface OverlayAria {
|
|
79
79
|
/** Props to apply to the overlay container element. */
|
|
80
|
-
overlayProps:
|
|
80
|
+
overlayProps: DOMAttributes;
|
|
81
81
|
/** Props to apply to the underlay element, if any. */
|
|
82
|
-
underlayProps:
|
|
82
|
+
underlayProps: DOMAttributes;
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
85
|
* Provides the behavior for overlays such as dialogs, popovers, and menus.
|
|
86
86
|
* Hides the overlay when the user interacts outside it, when the Escape key is pressed,
|
|
87
87
|
* or optionally, on blur. Only the top-most overlay will close at once.
|
|
88
88
|
*/
|
|
89
|
-
export function useOverlay(props:
|
|
90
|
-
interface OverlayTriggerProps {
|
|
89
|
+
export function useOverlay(props: AriaOverlayProps, ref: RefObject<Element>): OverlayAria;
|
|
90
|
+
export interface OverlayTriggerProps {
|
|
91
91
|
/** Type of overlay that is opened by the trigger. */
|
|
92
92
|
type: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid';
|
|
93
93
|
}
|
|
94
|
-
interface OverlayTriggerAria {
|
|
94
|
+
export interface OverlayTriggerAria {
|
|
95
95
|
/** Props for the trigger element. */
|
|
96
96
|
triggerProps: AriaButtonProps;
|
|
97
97
|
/** Props for the overlay container element. */
|
|
98
|
-
overlayProps:
|
|
98
|
+
overlayProps: DOMAttributes;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* Handles the behavior and accessibility for an overlay trigger, e.g. a button
|
|
102
102
|
* that opens a popover, menu, or other overlay that is positioned relative to the trigger.
|
|
103
103
|
*/
|
|
104
|
-
export function useOverlayTrigger(props: OverlayTriggerProps, state: OverlayTriggerState, ref: RefObject<
|
|
104
|
+
export function useOverlayTrigger(props: OverlayTriggerProps, state: OverlayTriggerState, ref: RefObject<Element>): OverlayTriggerAria;
|
|
105
105
|
interface PreventScrollOptions {
|
|
106
106
|
/** Whether the scroll lock is disabled. */
|
|
107
107
|
isDisabled?: boolean;
|
|
@@ -112,7 +112,7 @@ interface PreventScrollOptions {
|
|
|
112
112
|
* shift due to the scrollbars disappearing.
|
|
113
113
|
*/
|
|
114
114
|
export function usePreventScroll(options?: PreventScrollOptions): void;
|
|
115
|
-
interface ModalProviderProps extends
|
|
115
|
+
export interface ModalProviderProps extends DOMAttributes {
|
|
116
116
|
children: ReactNode;
|
|
117
117
|
}
|
|
118
118
|
/**
|
|
@@ -124,7 +124,7 @@ interface ModalProviderProps extends HTMLAttributes<HTMLElement> {
|
|
|
124
124
|
* like portals, which can cause the React tree and the DOM tree to differ significantly in structure.
|
|
125
125
|
*/
|
|
126
126
|
export function ModalProvider(props: ModalProviderProps): JSX.Element;
|
|
127
|
-
interface ModalProviderAria {
|
|
127
|
+
export interface ModalProviderAria {
|
|
128
128
|
/**
|
|
129
129
|
* Props to be spread on the container element.
|
|
130
130
|
*/
|
|
@@ -144,12 +144,12 @@ export function useModalProvider(): ModalProviderAria;
|
|
|
144
144
|
* overlay should be accessible at once.
|
|
145
145
|
*/
|
|
146
146
|
export function OverlayProvider(props: ModalProviderProps): JSX.Element;
|
|
147
|
-
interface OverlayContainerProps extends ModalProviderProps {
|
|
147
|
+
export interface OverlayContainerProps extends ModalProviderProps {
|
|
148
148
|
/**
|
|
149
149
|
* The container element in which the overlay portal will be placed.
|
|
150
150
|
* @default document.body
|
|
151
151
|
*/
|
|
152
|
-
portalContainer?:
|
|
152
|
+
portalContainer?: Element;
|
|
153
153
|
}
|
|
154
154
|
/**
|
|
155
155
|
* A container for overlays like modals and popovers. Renders the overlay
|
|
@@ -159,14 +159,14 @@ interface OverlayContainerProps extends ModalProviderProps {
|
|
|
159
159
|
* be accessible at once.
|
|
160
160
|
*/
|
|
161
161
|
export function OverlayContainer(props: OverlayContainerProps): React.ReactPortal;
|
|
162
|
-
interface ModalAriaProps extends
|
|
162
|
+
interface ModalAriaProps extends DOMAttributes {
|
|
163
163
|
/** Data attribute marks the dom node as a modal for the aria-modal-polyfill. */
|
|
164
164
|
'data-ismodal': boolean;
|
|
165
165
|
}
|
|
166
|
-
interface
|
|
166
|
+
export interface AriaModalOptions {
|
|
167
167
|
isDisabled?: boolean;
|
|
168
168
|
}
|
|
169
|
-
interface ModalAria {
|
|
169
|
+
export interface ModalAria {
|
|
170
170
|
/** Props for the modal content element. */
|
|
171
171
|
modalProps: ModalAriaProps;
|
|
172
172
|
}
|
|
@@ -176,8 +176,8 @@ interface ModalAria {
|
|
|
176
176
|
* other types of overlays to ensure that only the top-most modal is
|
|
177
177
|
* accessible at once.
|
|
178
178
|
*/
|
|
179
|
-
export function useModal(options?:
|
|
180
|
-
interface DismissButtonProps extends AriaLabelingProps, DOMProps {
|
|
179
|
+
export function useModal(options?: AriaModalOptions): ModalAria;
|
|
180
|
+
export interface DismissButtonProps extends AriaLabelingProps, DOMProps {
|
|
181
181
|
/** Called when the dismiss button is activated. */
|
|
182
182
|
onDismiss?: () => void;
|
|
183
183
|
}
|
|
@@ -195,6 +195,6 @@ export function DismissButton(props: DismissButtonProps): JSX.Element;
|
|
|
195
195
|
* @param root - Nothing will be hidden above this element.
|
|
196
196
|
* @returns - A function to restore all hidden elements.
|
|
197
197
|
*/
|
|
198
|
-
export function ariaHideOutside(targets:
|
|
198
|
+
export function ariaHideOutside(targets: Element[], root?: HTMLElement): () => void;
|
|
199
199
|
|
|
200
200
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/calculatePosition.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useCloseOnScroll.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlayPosition.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlay.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlayTrigger.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/usePreventScroll.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useModal.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/DismissButton.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/ariaHideOutside.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/index.ts","packages/@react-aria/overlays/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {useOverlayPosition} from './useOverlayPosition';\nexport {useOverlay} from './useOverlay';\nexport {useOverlayTrigger} from './useOverlayTrigger';\nexport {usePreventScroll} from './usePreventScroll';\nexport {ModalProvider, useModalProvider, OverlayProvider, OverlayContainer, useModal} from './useModal';\nexport {DismissButton} from './DismissButton';\nexport {ariaHideOutside} from './ariaHideOutside';\n\nexport type {AriaPositionProps, PositionAria} from './useOverlayPosition';\nexport type {AriaOverlayProps, OverlayAria} from './useOverlay';\nexport type {OverlayTriggerAria, OverlayTriggerProps} from './useOverlayTrigger';\nexport type {AriaModalOptions, ModalAria, ModalProviderAria, ModalProviderProps, OverlayContainerProps} from './useModal';\nexport type {DismissButtonProps} from './DismissButton';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/overlays",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -18,22 +18,22 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/runtime": "^7.6.2",
|
|
21
|
-
"@react-aria/i18n": "^3.
|
|
22
|
-
"@react-aria/interactions": "^3.
|
|
23
|
-
"@react-aria/
|
|
24
|
-
"@react-aria/
|
|
25
|
-
"@react-
|
|
26
|
-
"@react-
|
|
27
|
-
"@react-types/
|
|
28
|
-
"@react-types/
|
|
29
|
-
"
|
|
21
|
+
"@react-aria/i18n": "^3.5.0",
|
|
22
|
+
"@react-aria/interactions": "^3.10.0",
|
|
23
|
+
"@react-aria/ssr": "^3.3.0",
|
|
24
|
+
"@react-aria/utils": "^3.13.2",
|
|
25
|
+
"@react-aria/visually-hidden": "^3.4.0",
|
|
26
|
+
"@react-stately/overlays": "^3.4.0",
|
|
27
|
+
"@react-types/button": "^3.6.0",
|
|
28
|
+
"@react-types/overlays": "^3.6.2",
|
|
29
|
+
"@react-types/shared": "^3.14.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"react": "^16.8.0 || ^17.0.0-rc.1",
|
|
33
|
-
"react-dom": "^16.8.0 || ^17.0.0-rc.1"
|
|
32
|
+
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0",
|
|
33
|
+
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "cd7c0ec917122c7612f653c22f8ed558f8b66ecd"
|
|
39
39
|
}
|
package/src/DismissButton.tsx
CHANGED
|
@@ -15,10 +15,10 @@ import {AriaLabelingProps, DOMProps} from '@react-types/shared';
|
|
|
15
15
|
import intlMessages from '../intl/*.json';
|
|
16
16
|
import React from 'react';
|
|
17
17
|
import {useLabels} from '@react-aria/utils';
|
|
18
|
-
import {
|
|
18
|
+
import {useLocalizedStringFormatter} from '@react-aria/i18n';
|
|
19
19
|
import {VisuallyHidden} from '@react-aria/visually-hidden';
|
|
20
20
|
|
|
21
|
-
interface DismissButtonProps extends AriaLabelingProps, DOMProps {
|
|
21
|
+
export interface DismissButtonProps extends AriaLabelingProps, DOMProps {
|
|
22
22
|
/** Called when the dismiss button is activated. */
|
|
23
23
|
onDismiss?: () => void
|
|
24
24
|
}
|
|
@@ -30,9 +30,9 @@ interface DismissButtonProps extends AriaLabelingProps, DOMProps {
|
|
|
30
30
|
*/
|
|
31
31
|
export function DismissButton(props: DismissButtonProps) {
|
|
32
32
|
let {onDismiss, ...otherProps} = props;
|
|
33
|
-
let
|
|
33
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
34
34
|
|
|
35
|
-
let labels = useLabels(otherProps,
|
|
35
|
+
let labels = useLabels(otherProps, stringFormatter.format('dismiss'));
|
|
36
36
|
|
|
37
37
|
let onClick = () => {
|
|
38
38
|
if (onDismiss) {
|
package/src/ariaHideOutside.ts
CHANGED
|
@@ -22,7 +22,7 @@ let refCountMap = new WeakMap<Element, number>();
|
|
|
22
22
|
* @param root - Nothing will be hidden above this element.
|
|
23
23
|
* @returns - A function to restore all hidden elements.
|
|
24
24
|
*/
|
|
25
|
-
export function ariaHideOutside(targets:
|
|
25
|
+
export function ariaHideOutside(targets: Element[], root = document.body) {
|
|
26
26
|
let visibleNodes = new Set<Element>(targets);
|
|
27
27
|
let hiddenNodes = new Set<Element>();
|
|
28
28
|
let walker = document.createTreeWalker(
|
|
@@ -31,7 +31,7 @@ export function ariaHideOutside(targets: HTMLElement[], root = document.body) {
|
|
|
31
31
|
{
|
|
32
32
|
acceptNode(node) {
|
|
33
33
|
// If this node is a live announcer, add it to the set of nodes to keep visible.
|
|
34
|
-
if ((node instanceof HTMLElement && node.dataset.liveAnnouncer === 'true')) {
|
|
34
|
+
if (((node instanceof HTMLElement || node instanceof SVGElement) && node.dataset.liveAnnouncer === 'true')) {
|
|
35
35
|
visibleNodes.add(node);
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -46,7 +46,7 @@ export function ariaHideOutside(targets: HTMLElement[], root = document.body) {
|
|
|
46
46
|
|
|
47
47
|
// VoiceOver on iOS has issues hiding elements with role="row". Hide the cells inside instead.
|
|
48
48
|
// https://bugs.webkit.org/show_bug.cgi?id=222623
|
|
49
|
-
if (node instanceof
|
|
49
|
+
if (node instanceof Element && node.getAttribute('role') === 'row') {
|
|
50
50
|
return NodeFilter.FILTER_SKIP;
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -93,7 +93,7 @@ export function ariaHideOutside(targets: HTMLElement[], root = document.body) {
|
|
|
93
93
|
// and not already inside a hidden node, hide all of the new children.
|
|
94
94
|
if (![...visibleNodes, ...hiddenNodes].some(node => node.contains(change.target))) {
|
|
95
95
|
for (let node of change.addedNodes) {
|
|
96
|
-
if ((node instanceof HTMLElement && node.dataset.liveAnnouncer === 'true')) {
|
|
96
|
+
if (((node instanceof HTMLElement || node instanceof SVGElement) && node.dataset.liveAnnouncer === 'true')) {
|
|
97
97
|
visibleNodes.add(node);
|
|
98
98
|
} else if (node instanceof Element) {
|
|
99
99
|
hide(node);
|
package/src/calculatePosition.ts
CHANGED
|
@@ -11,12 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {Axis, Placement, PlacementAxis, SizeAxis} from '@react-types/overlays';
|
|
14
|
-
import getCss from 'dom-helpers/style';
|
|
15
|
-
import getOffset from 'dom-helpers/query/offset';
|
|
16
|
-
import getPosition from 'dom-helpers/query/position';
|
|
17
|
-
import getScrollLeft from 'dom-helpers/query/scrollLeft';
|
|
18
|
-
import getScrollTop from 'dom-helpers/query/scrollTop';
|
|
19
|
-
import ownerDocument from 'dom-helpers/ownerDocument';
|
|
20
14
|
|
|
21
15
|
interface Position {
|
|
22
16
|
top?: number,
|
|
@@ -51,12 +45,12 @@ interface Offset {
|
|
|
51
45
|
|
|
52
46
|
interface PositionOpts {
|
|
53
47
|
placement: Placement,
|
|
54
|
-
targetNode:
|
|
55
|
-
overlayNode:
|
|
56
|
-
scrollNode:
|
|
48
|
+
targetNode: Element,
|
|
49
|
+
overlayNode: Element,
|
|
50
|
+
scrollNode: Element,
|
|
57
51
|
padding: number,
|
|
58
52
|
shouldFlip: boolean,
|
|
59
|
-
boundaryElement:
|
|
53
|
+
boundaryElement: Element,
|
|
60
54
|
offset: number,
|
|
61
55
|
crossOffset: number,
|
|
62
56
|
maxHeight?: number
|
|
@@ -104,25 +98,22 @@ function getContainerDimensions(containerNode: Element): Dimensions {
|
|
|
104
98
|
let scroll: Position = {};
|
|
105
99
|
|
|
106
100
|
if (containerNode.tagName === 'BODY') {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
scroll.left =
|
|
114
|
-
getScrollLeft(ownerDocument(containerNode).documentElement) ||
|
|
115
|
-
getScrollLeft(containerNode);
|
|
101
|
+
let documentElement = document.documentElement;
|
|
102
|
+
width = visualViewport?.width ?? documentElement.clientWidth;
|
|
103
|
+
height = visualViewport?.height ?? documentElement.clientHeight;
|
|
104
|
+
|
|
105
|
+
scroll.top = documentElement.scrollTop || containerNode.scrollTop;
|
|
106
|
+
scroll.left = documentElement.scrollLeft || containerNode.scrollLeft;
|
|
116
107
|
} else {
|
|
117
108
|
({width, height, top, left} = getOffset(containerNode));
|
|
118
|
-
scroll.top =
|
|
119
|
-
scroll.left =
|
|
109
|
+
scroll.top = containerNode.scrollTop;
|
|
110
|
+
scroll.left = containerNode.scrollLeft;
|
|
120
111
|
}
|
|
121
112
|
|
|
122
113
|
return {width, height, scroll, top, left};
|
|
123
114
|
}
|
|
124
115
|
|
|
125
|
-
function getScroll(node:
|
|
116
|
+
function getScroll(node: Element): Offset {
|
|
126
117
|
return {
|
|
127
118
|
top: node.scrollTop,
|
|
128
119
|
left: node.scrollLeft,
|
|
@@ -153,7 +144,7 @@ function getDelta(
|
|
|
153
144
|
}
|
|
154
145
|
}
|
|
155
146
|
|
|
156
|
-
function getMargins(node:
|
|
147
|
+
function getMargins(node: Element): Position {
|
|
157
148
|
let style = window.getComputedStyle(node);
|
|
158
149
|
return {
|
|
159
150
|
top: parseInt(style.marginTop, 10) || 0,
|
|
@@ -373,15 +364,16 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
|
|
|
373
364
|
maxHeight
|
|
374
365
|
} = opts;
|
|
375
366
|
|
|
376
|
-
let container = overlayNode.offsetParent || document.body;
|
|
367
|
+
let container = ((overlayNode instanceof HTMLElement && overlayNode.offsetParent) || document.body) as Element;
|
|
377
368
|
let isBodyContainer = container.tagName === 'BODY';
|
|
378
369
|
const containerPositionStyle = window.getComputedStyle(container).position;
|
|
379
370
|
let isContainerPositioned = !!containerPositionStyle && containerPositionStyle !== 'static';
|
|
380
371
|
let childOffset: Offset = isBodyContainer ? getOffset(targetNode) : getPosition(targetNode, container);
|
|
381
372
|
|
|
382
373
|
if (!isBodyContainer) {
|
|
383
|
-
|
|
384
|
-
childOffset.
|
|
374
|
+
let {marginTop, marginLeft} = window.getComputedStyle(targetNode);
|
|
375
|
+
childOffset.top += parseInt(marginTop, 10) || 0;
|
|
376
|
+
childOffset.left += parseInt(marginLeft, 10) || 0;
|
|
385
377
|
}
|
|
386
378
|
|
|
387
379
|
let overlaySize: Offset = getOffset(overlayNode);
|
|
@@ -409,3 +401,35 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
|
|
|
409
401
|
maxHeight
|
|
410
402
|
);
|
|
411
403
|
}
|
|
404
|
+
|
|
405
|
+
function getOffset(node: Element): Offset {
|
|
406
|
+
let {top, left, width, height} = node.getBoundingClientRect();
|
|
407
|
+
let {scrollTop, scrollLeft, clientTop, clientLeft} = document.documentElement;
|
|
408
|
+
return {
|
|
409
|
+
top: top + scrollTop - clientTop,
|
|
410
|
+
left: left + scrollLeft - clientLeft,
|
|
411
|
+
width,
|
|
412
|
+
height
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function getPosition(node: Element, parent: Element): Offset {
|
|
417
|
+
let style = window.getComputedStyle(node);
|
|
418
|
+
let offset: Offset;
|
|
419
|
+
if (style.position === 'fixed') {
|
|
420
|
+
let {top, left, width, height} = node.getBoundingClientRect();
|
|
421
|
+
offset = {top, left, width, height};
|
|
422
|
+
} else {
|
|
423
|
+
offset = getOffset(node);
|
|
424
|
+
let parentOffset = getOffset(parent);
|
|
425
|
+
let parentStyle = window.getComputedStyle(parent);
|
|
426
|
+
parentOffset.top += (parseInt(parentStyle.borderTopWidth, 10) || 0) - parent.scrollTop;
|
|
427
|
+
parentOffset.left += (parseInt(parentStyle.borderLeftWidth, 10) || 0) - parent.scrollLeft;
|
|
428
|
+
offset.top -= parentOffset.top;
|
|
429
|
+
offset.left -= parentOffset.left;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
offset.top -= parseInt(style.marginTop, 10) || 0;
|
|
433
|
+
offset.left -= parseInt(style.marginLeft, 10) || 0;
|
|
434
|
+
return offset;
|
|
435
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,11 +9,16 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
+
export {useOverlayPosition} from './useOverlayPosition';
|
|
13
|
+
export {useOverlay} from './useOverlay';
|
|
14
|
+
export {useOverlayTrigger} from './useOverlayTrigger';
|
|
15
|
+
export {usePreventScroll} from './usePreventScroll';
|
|
16
|
+
export {ModalProvider, useModalProvider, OverlayProvider, OverlayContainer, useModal} from './useModal';
|
|
17
|
+
export {DismissButton} from './DismissButton';
|
|
18
|
+
export {ariaHideOutside} from './ariaHideOutside';
|
|
12
19
|
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
export
|
|
17
|
-
export
|
|
18
|
-
export * from './DismissButton';
|
|
19
|
-
export * from './ariaHideOutside';
|
|
20
|
+
export type {AriaPositionProps, PositionAria} from './useOverlayPosition';
|
|
21
|
+
export type {AriaOverlayProps, OverlayAria} from './useOverlay';
|
|
22
|
+
export type {OverlayTriggerAria, OverlayTriggerProps} from './useOverlayTrigger';
|
|
23
|
+
export type {AriaModalOptions, ModalAria, ModalProviderAria, ModalProviderProps, OverlayContainerProps} from './useModal';
|
|
24
|
+
export type {DismissButtonProps} from './DismissButton';
|
package/src/useCloseOnScroll.ts
CHANGED
|
@@ -17,10 +17,10 @@ import {RefObject, useEffect} from 'react';
|
|
|
17
17
|
// it sets a close function here mapped from the trigger element. This way we can avoid
|
|
18
18
|
// forcing users to pass an onClose function to useOverlayPosition which could be considered
|
|
19
19
|
// a breaking change.
|
|
20
|
-
export const onCloseMap: WeakMap<
|
|
20
|
+
export const onCloseMap: WeakMap<Element, () => void> = new WeakMap();
|
|
21
21
|
|
|
22
22
|
interface CloseOnScrollOptions {
|
|
23
|
-
triggerRef: RefObject<
|
|
23
|
+
triggerRef: RefObject<Element>,
|
|
24
24
|
isOpen?: boolean,
|
|
25
25
|
onClose?: () => void
|
|
26
26
|
}
|
package/src/useModal.tsx
CHANGED
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
import {DOMAttributes} from '@react-types/shared';
|
|
14
|
+
import React, {AriaAttributes, ReactNode, useContext, useEffect, useMemo, useState} from 'react';
|
|
14
15
|
import ReactDOM from 'react-dom';
|
|
16
|
+
import {useIsSSR} from '@react-aria/ssr';
|
|
15
17
|
|
|
16
|
-
interface ModalProviderProps extends
|
|
18
|
+
export interface ModalProviderProps extends DOMAttributes {
|
|
17
19
|
children: ReactNode
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -62,7 +64,7 @@ export function ModalProvider(props: ModalProviderProps) {
|
|
|
62
64
|
);
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
interface ModalProviderAria {
|
|
67
|
+
export interface ModalProviderAria {
|
|
66
68
|
/**
|
|
67
69
|
* Props to be spread on the container element.
|
|
68
70
|
*/
|
|
@@ -106,12 +108,12 @@ export function OverlayProvider(props: ModalProviderProps) {
|
|
|
106
108
|
);
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
interface OverlayContainerProps extends ModalProviderProps {
|
|
111
|
+
export interface OverlayContainerProps extends ModalProviderProps {
|
|
110
112
|
/**
|
|
111
113
|
* The container element in which the overlay portal will be placed.
|
|
112
114
|
* @default document.body
|
|
113
115
|
*/
|
|
114
|
-
portalContainer?:
|
|
116
|
+
portalContainer?: Element
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
/**
|
|
@@ -122,28 +124,33 @@ interface OverlayContainerProps extends ModalProviderProps {
|
|
|
122
124
|
* be accessible at once.
|
|
123
125
|
*/
|
|
124
126
|
export function OverlayContainer(props: OverlayContainerProps): React.ReactPortal {
|
|
125
|
-
let
|
|
127
|
+
let isSSR = useIsSSR();
|
|
128
|
+
let {portalContainer = isSSR ? null : document.body, ...rest} = props;
|
|
126
129
|
|
|
127
130
|
React.useEffect(() => {
|
|
128
|
-
if (portalContainer
|
|
131
|
+
if (portalContainer?.closest('[data-overlay-container]')) {
|
|
129
132
|
throw new Error('An OverlayContainer must not be inside another container. Please change the portalContainer prop.');
|
|
130
133
|
}
|
|
131
134
|
}, [portalContainer]);
|
|
132
135
|
|
|
136
|
+
if (!portalContainer) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
133
140
|
let contents = <OverlayProvider {...rest} />;
|
|
134
141
|
return ReactDOM.createPortal(contents, portalContainer);
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
interface ModalAriaProps extends
|
|
144
|
+
interface ModalAriaProps extends DOMAttributes {
|
|
138
145
|
/** Data attribute marks the dom node as a modal for the aria-modal-polyfill. */
|
|
139
146
|
'data-ismodal': boolean
|
|
140
147
|
}
|
|
141
148
|
|
|
142
|
-
interface
|
|
149
|
+
export interface AriaModalOptions {
|
|
143
150
|
isDisabled?: boolean
|
|
144
151
|
}
|
|
145
152
|
|
|
146
|
-
interface ModalAria {
|
|
153
|
+
export interface ModalAria {
|
|
147
154
|
/** Props for the modal content element. */
|
|
148
155
|
modalProps: ModalAriaProps
|
|
149
156
|
}
|
|
@@ -154,7 +161,7 @@ interface ModalAria {
|
|
|
154
161
|
* other types of overlays to ensure that only the top-most modal is
|
|
155
162
|
* accessible at once.
|
|
156
163
|
*/
|
|
157
|
-
export function useModal(options?:
|
|
164
|
+
export function useModal(options?: AriaModalOptions): ModalAria {
|
|
158
165
|
// Add aria-hidden to all parent providers on mount, and restore on unmount.
|
|
159
166
|
let context = useContext(Context);
|
|
160
167
|
if (!context) {
|
package/src/useOverlay.ts
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {DOMAttributes} from '@react-types/shared';
|
|
14
|
+
import {RefObject, SyntheticEvent, useEffect} from 'react';
|
|
14
15
|
import {useFocusWithin, useInteractOutside} from '@react-aria/interactions';
|
|
15
16
|
|
|
16
|
-
interface
|
|
17
|
+
export interface AriaOverlayProps {
|
|
17
18
|
/** Whether the overlay is currently open. */
|
|
18
19
|
isOpen?: boolean,
|
|
19
20
|
|
|
@@ -41,24 +42,24 @@ interface OverlayProps {
|
|
|
41
42
|
* out interaction with elements that should not dismiss the overlay.
|
|
42
43
|
* By default, onClose will always be called on interaction outside the overlay ref.
|
|
43
44
|
*/
|
|
44
|
-
shouldCloseOnInteractOutside?: (element:
|
|
45
|
+
shouldCloseOnInteractOutside?: (element: Element) => boolean
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
interface OverlayAria {
|
|
48
|
+
export interface OverlayAria {
|
|
48
49
|
/** Props to apply to the overlay container element. */
|
|
49
|
-
overlayProps:
|
|
50
|
+
overlayProps: DOMAttributes,
|
|
50
51
|
/** Props to apply to the underlay element, if any. */
|
|
51
|
-
underlayProps:
|
|
52
|
+
underlayProps: DOMAttributes
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
const visibleOverlays: RefObject<
|
|
55
|
+
const visibleOverlays: RefObject<Element>[] = [];
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* Provides the behavior for overlays such as dialogs, popovers, and menus.
|
|
58
59
|
* Hides the overlay when the user interacts outside it, when the Escape key is pressed,
|
|
59
60
|
* or optionally, on blur. Only the top-most overlay will close at once.
|
|
60
61
|
*/
|
|
61
|
-
export function useOverlay(props:
|
|
62
|
+
export function useOverlay(props: AriaOverlayProps, ref: RefObject<Element>): OverlayAria {
|
|
62
63
|
let {
|
|
63
64
|
onClose,
|
|
64
65
|
shouldCloseOnBlur,
|
|
@@ -89,8 +90,8 @@ export function useOverlay(props: OverlayProps, ref: RefObject<HTMLElement>): Ov
|
|
|
89
90
|
}
|
|
90
91
|
};
|
|
91
92
|
|
|
92
|
-
let onInteractOutsideStart = (e: SyntheticEvent<
|
|
93
|
-
if (!shouldCloseOnInteractOutside || shouldCloseOnInteractOutside(e.target as
|
|
93
|
+
let onInteractOutsideStart = (e: SyntheticEvent<Element>) => {
|
|
94
|
+
if (!shouldCloseOnInteractOutside || shouldCloseOnInteractOutside(e.target as Element)) {
|
|
94
95
|
if (visibleOverlays[visibleOverlays.length - 1] === ref) {
|
|
95
96
|
e.stopPropagation();
|
|
96
97
|
e.preventDefault();
|
|
@@ -98,8 +99,8 @@ export function useOverlay(props: OverlayProps, ref: RefObject<HTMLElement>): Ov
|
|
|
98
99
|
}
|
|
99
100
|
};
|
|
100
101
|
|
|
101
|
-
let onInteractOutside = (e: SyntheticEvent<
|
|
102
|
-
if (!shouldCloseOnInteractOutside || shouldCloseOnInteractOutside(e.target as
|
|
102
|
+
let onInteractOutside = (e: SyntheticEvent<Element>) => {
|
|
103
|
+
if (!shouldCloseOnInteractOutside || shouldCloseOnInteractOutside(e.target as Element)) {
|
|
103
104
|
if (visibleOverlays[visibleOverlays.length - 1] === ref) {
|
|
104
105
|
e.stopPropagation();
|
|
105
106
|
e.preventDefault();
|
|
@@ -123,7 +124,7 @@ export function useOverlay(props: OverlayProps, ref: RefObject<HTMLElement>): Ov
|
|
|
123
124
|
let {focusWithinProps} = useFocusWithin({
|
|
124
125
|
isDisabled: !shouldCloseOnBlur,
|
|
125
126
|
onBlurWithin: (e) => {
|
|
126
|
-
if (!shouldCloseOnInteractOutside || shouldCloseOnInteractOutside(e.relatedTarget as
|
|
127
|
+
if (!shouldCloseOnInteractOutside || shouldCloseOnInteractOutside(e.relatedTarget as Element)) {
|
|
127
128
|
onClose();
|
|
128
129
|
}
|
|
129
130
|
}
|