@easypost/easy-ui 1.0.0-alpha.120 → 1.0.0-alpha.122
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/CHANGELOG.md +19 -0
- package/Modal/Modal.d.ts +2 -0
- package/Modal/Modal.d.ts.map +1 -1
- package/Modal/Modal.nesting.test.d.ts +2 -0
- package/Modal/Modal.nesting.test.d.ts.map +1 -0
- package/Modal/Modal.stories.d.ts.map +1 -1
- package/Modal/ModalContainer.d.ts +24 -0
- package/Modal/ModalContainer.d.ts.map +1 -1
- package/Modal/ModalTrigger.d.ts +26 -0
- package/Modal/ModalTrigger.d.ts.map +1 -1
- package/Modal/ModalUnderlay.d.ts +13 -0
- package/Modal/ModalUnderlay.d.ts.map +1 -1
- package/Modal/context.d.ts +70 -3
- package/Modal/context.d.ts.map +1 -1
- package/Modal/index.js +159 -31
- package/Modal/index.mjs +161 -33
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @easypost/easy-ui
|
|
2
2
|
|
|
3
|
+
## 1.0.0-alpha.122
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f17a7b7: Add `childNestingBehavior` and `selfNestingBehavior` props to `Modal.Trigger` and `ModalContainer` to control how modals stack when nested. The connection between a parent and a nested child can resolve to `stack` (both keep their backdrops — the default) or `replace` (the nested modal hides the modal beneath it).
|
|
8
|
+
|
|
9
|
+
Configure it from either end: `childNestingBehavior` is set on the parent, applies to its children, and cascades down the tree; `selfNestingBehavior` is set on the child, applies only to its own connection to its parent, does not cascade, and overrides the parent's `childNestingBehavior` for that connection. `selfNestingBehavior` is useful for surgically changing one nested modal in a large tree without touching its parent.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- f17a7b7: Fix third-party overlays (e.g. Stripe Link/autofill) locking up when their modal (`allowsThirdPartyOverlays`) is nested inside another modal. A surrounding focus-trapping modal kept hiding the page (`inert`) and containing focus, which re-broke the injected overlay. A modal now automatically relaxes its focus trap and background hiding while it has an open `allowsThirdPartyOverlays` descendant, then restores them when that descendant closes. Modals without such a descendant are unaffected.
|
|
14
|
+
- f17a7b7: Fix react-aria overlays (e.g. `Select`, `Menu`) not closing on outside click when rendered inside a `Modal` that uses `allowsThirdPartyOverlays`. The modal box was tagged `data-react-aria-top-layer`, which made react-aria treat every click inside the modal as "not outside" for all overlays. Modals now keep nested overlays dismissable while preserving the third-party overlay behavior: the modal stays visible under a surrounding modal, clicking a nested modal no longer dismisses the one beneath it, and genuine third-party overlays (e.g. Stripe) still don't dismiss the modal.
|
|
15
|
+
|
|
16
|
+
## 1.0.0-alpha.121
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- e47ec8f: Add `allowsThirdPartyOverlays` to `Modal.Trigger` and `ModalContainer`. When enabled, the modal stops trapping focus and stops applying `aria-hidden`/`inert` to the rest of the page, so third-party overlays that render outside the modal (e.g. Stripe Link/autofill, reCAPTCHA) remain focusable and clickable instead of locking up.
|
|
21
|
+
|
|
3
22
|
## 1.0.0-alpha.120
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/Modal/Modal.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { ModalHeader } from "./ModalHeader";
|
|
|
5
5
|
import { ModalTrigger } from "./ModalTrigger";
|
|
6
6
|
import { ModalContainer } from "./ModalContainer";
|
|
7
7
|
import { useModalTrigger } from "./context";
|
|
8
|
+
import type { ModalNestingBehavior } from "./context";
|
|
8
9
|
type ModalSize = "sm" | "md" | "lg" | "xl";
|
|
9
10
|
export type ModalProps = {
|
|
10
11
|
/**
|
|
@@ -49,4 +50,5 @@ export declare namespace Modal {
|
|
|
49
50
|
var Footer: typeof ModalFooter;
|
|
50
51
|
}
|
|
51
52
|
export { ModalContainer, useModalTrigger };
|
|
53
|
+
export type { ModalNestingBehavior };
|
|
52
54
|
//# sourceMappingURL=Modal.d.ts.map
|
package/Modal/Modal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../src/Modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAc,SAAS,EAAmB,MAAM,OAAO,CAAC;AAGtE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../src/Modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAc,SAAS,EAAmB,MAAM,OAAO,CAAC;AAGtE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAItD,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG;IACvB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,qBAqCtC;yBArCe,KAAK;;;;;;AAsErB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAC3C,YAAY,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.nesting.test.d.ts","sourceRoot":"","sources":["../../src/Modal/Modal.nesting.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.stories.d.ts","sourceRoot":"","sources":["../../src/Modal/Modal.stories.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Modal.stories.d.ts","sourceRoot":"","sources":["../../src/Modal/Modal.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAcvD,OAAO,EAAE,KAAK,EAAmC,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,KAAK,UAAU,GAAG,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC;AACzC,KAAK,iBAAiB,GAAG,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC;AAEvD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,KAAK,CAQ5B,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,eAAO,MAAM,MAAM,EAAE,UAkBpB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,UA6CtB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,iBA6B5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,UAwBlB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,iBAwBzB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,iBAwBxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,iBAyBzB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,iBAgKpB,CAAC;AA8EF,eAAO,MAAM,UAAU,EAAE,UAqBxB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,UA0B5B,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { ReactNode } from "react";
|
|
2
|
+
import { ModalNestingBehavior } from "./context";
|
|
2
3
|
type ModalContainerProps = {
|
|
3
4
|
/**
|
|
4
5
|
* Modal wrap content.
|
|
@@ -8,6 +9,29 @@ type ModalContainerProps = {
|
|
|
8
9
|
* Whether or not the modal is dismissable.
|
|
9
10
|
*/
|
|
10
11
|
isDismissable?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Disables focus trapping and background aria-hiding so the modal can host
|
|
14
|
+
* third-party overlays (e.g. Stripe Link/autofill, reCAPTCHA) that render
|
|
15
|
+
* outside the modal. Use sparingly — see `ModalUnderlay` for the tradeoffs.
|
|
16
|
+
*
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
allowsThirdPartyOverlays?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Controls how this modal's nested children stack relative to it, and cascades
|
|
22
|
+
* to descendant modals. `stack` gives each child its own backdrop, and
|
|
23
|
+
* `replace` hides this modal while a child is open. When unset, it inherits the
|
|
24
|
+
* nearest ancestor modal's value (or `stack` at the root).
|
|
25
|
+
*/
|
|
26
|
+
childNestingBehavior?: ModalNestingBehavior;
|
|
27
|
+
/**
|
|
28
|
+
* Controls how this modal stacks relative to its parent, overriding the
|
|
29
|
+
* parent's `childNestingBehavior` for just this modal. `stack` keeps both
|
|
30
|
+
* backdrops, and `replace` hides the parent while this modal is open. Local to
|
|
31
|
+
* this modal — it does not cascade. Useful for surgically changing one nested
|
|
32
|
+
* modal in a larger tree without touching its parent.
|
|
33
|
+
*/
|
|
34
|
+
selfNestingBehavior?: ModalNestingBehavior;
|
|
11
35
|
/**
|
|
12
36
|
* Handler that is called when the overlay is closed.
|
|
13
37
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalContainer.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalContainer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAgB,SAAS,EAA0B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ModalContainer.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalContainer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAgB,SAAS,EAA0B,MAAM,OAAO,CAAC;AAI/E,OAAO,EAAE,oBAAoB,EAAwB,MAAM,WAAW,CAAC;AAEvE,KAAK,mBAAmB,GAAG;IACzB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAE5C;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAE3C;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,qBA2DxD"}
|
package/Modal/ModalTrigger.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { ReactElement } from "react";
|
|
2
|
+
import { ModalNestingBehavior } from "./context";
|
|
2
3
|
export type CloseableModalElement = (close: () => void) => ReactElement;
|
|
3
4
|
export type ModalTriggerProps = {
|
|
4
5
|
/**
|
|
@@ -11,8 +12,33 @@ export type ModalTriggerProps = {
|
|
|
11
12
|
defaultOpen?: boolean;
|
|
12
13
|
/**
|
|
13
14
|
* Whether or not the modal can be dismissed.
|
|
15
|
+
*
|
|
16
|
+
* @default true
|
|
14
17
|
*/
|
|
15
18
|
isDismissable?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Disables focus trapping and background aria-hiding so the modal can host
|
|
21
|
+
* third-party overlays (e.g. Stripe Link/autofill, reCAPTCHA) that render
|
|
22
|
+
* outside the modal. Use sparingly — see `ModalUnderlay` for the tradeoffs.
|
|
23
|
+
*
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
allowsThirdPartyOverlays?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Controls how this modal's nested children stack relative to it, and cascades
|
|
29
|
+
* to descendant modals. `stack` gives each child its own backdrop, and
|
|
30
|
+
* `replace` hides this modal while a child is open. When unset, it inherits the
|
|
31
|
+
* nearest ancestor modal's value (or `stack` at the root).
|
|
32
|
+
*/
|
|
33
|
+
childNestingBehavior?: ModalNestingBehavior;
|
|
34
|
+
/**
|
|
35
|
+
* Controls how this modal stacks relative to its parent, overriding the
|
|
36
|
+
* parent's `childNestingBehavior` for just this modal. `stack` keeps both
|
|
37
|
+
* backdrops, and `replace` hides the parent while this modal is open. Local to
|
|
38
|
+
* this modal — it does not cascade. Useful for surgically changing one nested
|
|
39
|
+
* modal in a larger tree without touching its parent.
|
|
40
|
+
*/
|
|
41
|
+
selfNestingBehavior?: ModalNestingBehavior;
|
|
16
42
|
/**
|
|
17
43
|
* Whether the modal is open by default (controlled).
|
|
18
44
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalTrigger.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalTrigger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,YAAY,EAAgB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ModalTrigger.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalTrigger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,YAAY,EAAgB,MAAM,OAAO,CAAC;AAI1D,OAAO,EAAE,oBAAoB,EAAwB,MAAM,WAAW,CAAC;AAEvE,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,YAAY,CAAC;AAExE,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,QAAQ,EAAE,CAAC,YAAY,EAAE,qBAAqB,GAAG,YAAY,CAAC,CAAC;IAE/D;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAE5C;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAE3C;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,qBA2CpD"}
|
package/Modal/ModalUnderlay.d.ts
CHANGED
|
@@ -13,6 +13,19 @@ type ModalUnderlayProps = {
|
|
|
13
13
|
* Whether or not the modal is dismissable.
|
|
14
14
|
*/
|
|
15
15
|
isDismissable?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* When `true`, the modal stops trapping focus and stops hiding the rest of
|
|
18
|
+
* the page from assistive technologies (`aria-hidden`/`inert`). Use this only
|
|
19
|
+
* for modals that intentionally host third-party overlays — e.g. Stripe
|
|
20
|
+
* Link/autofill or reCAPTCHA — which render themselves into the document
|
|
21
|
+
* *outside* the modal. react-aria's focus trap and `inert` would otherwise
|
|
22
|
+
* blur and lock up those overlays. This trades away the modal's focus
|
|
23
|
+
* containment and background hiding, so reach for it only when a third-party
|
|
24
|
+
* overlay requires it.
|
|
25
|
+
*
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
allowsThirdPartyOverlays?: boolean;
|
|
16
29
|
};
|
|
17
30
|
export declare function ModalUnderlay(props: ModalUnderlayProps): React.JSX.Element;
|
|
18
31
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalUnderlay.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalUnderlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"ModalUnderlay.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalUnderlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAgC,MAAM,OAAO,CAAC;AAMvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAgBpD,KAAK,kBAAkB,GAAG;IACxB;;OAEG;IACH,KAAK,EAAE,mBAAmB,CAAC;IAE3B;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;;;;;;OAWG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAuBF,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,qBAUtD"}
|
package/Modal/context.d.ts
CHANGED
|
@@ -2,6 +2,17 @@ import React, { ReactNode } from "react";
|
|
|
2
2
|
import { FocusableElement } from "@react-types/shared";
|
|
3
3
|
import { DOMAttributes, RefObject } from "react";
|
|
4
4
|
import { OverlayTriggerState } from "react-stately";
|
|
5
|
+
/**
|
|
6
|
+
* Controls how one modal in a nested stack presents relative to the modal it
|
|
7
|
+
* connects to. The same value describes that connection from either end —
|
|
8
|
+
* `childNestingBehavior` (set on the parent, cascades down) and
|
|
9
|
+
* `selfNestingBehavior` (set on the child, local) — and resolves to:
|
|
10
|
+
*
|
|
11
|
+
* - `stack` — both modals keep their own backdrops; modals simply stack.
|
|
12
|
+
* - `replace` — the nested modal hides the modal beneath it, so only the topmost
|
|
13
|
+
* modal is visible.
|
|
14
|
+
*/
|
|
15
|
+
export type ModalNestingBehavior = "stack" | "replace";
|
|
5
16
|
export type ModalContextType = {
|
|
6
17
|
dialogProps: DOMAttributes<FocusableElement>;
|
|
7
18
|
titleProps: DOMAttributes<FocusableElement>;
|
|
@@ -14,17 +25,73 @@ export type ModalContextType = {
|
|
|
14
25
|
type ModalTriggerContextType = {
|
|
15
26
|
isDismissable: boolean;
|
|
16
27
|
state: OverlayTriggerState;
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Whether this modal currently has one or more open nested modals whose
|
|
30
|
+
* connection resolved to `replace`. When true, this modal hides itself so the
|
|
31
|
+
* nested modal takes its place.
|
|
32
|
+
*/
|
|
33
|
+
hasReplacingChild: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The resolved behavior this modal imposes on its children's connections.
|
|
36
|
+
* Cascades: a child that sets neither `childNestingBehavior` nor
|
|
37
|
+
* `selfNestingBehavior` inherits this value.
|
|
38
|
+
*/
|
|
39
|
+
childNestingBehavior: ModalNestingBehavior;
|
|
40
|
+
/**
|
|
41
|
+
* The resolved behavior of this modal's connection to its parent. Drives this
|
|
42
|
+
* modal's own rendering — suppressing its backdrop or hiding its parent.
|
|
43
|
+
*/
|
|
44
|
+
selfNestingBehavior: ModalNestingBehavior;
|
|
45
|
+
/**
|
|
46
|
+
* Registers an open nested modal with this modal. The `replaces` argument
|
|
47
|
+
* records whether that nested modal's connection resolved to `replace`.
|
|
48
|
+
* Returns a cleanup that unregisters it. Callers invoke this from an effect
|
|
49
|
+
* tied to the nested modal's open state so the count stays accurate across
|
|
50
|
+
* open/close/unmount.
|
|
51
|
+
*/
|
|
52
|
+
registerNested: (replaces: boolean) => () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Whether an open descendant modal (at any depth) hosts third-party overlays
|
|
55
|
+
* (`allowsThirdPartyOverlays`). A focus-trapping modal reads this to stop
|
|
56
|
+
* hiding/trapping the page while such a descendant is open, so the descendant's
|
|
57
|
+
* injected overlay (e.g. Stripe Link) isn't `inert`'d or robbed of focus.
|
|
58
|
+
*/
|
|
59
|
+
hasOpenThirdPartyDescendant: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Registers that this modal's subtree contains an open third-party-overlay
|
|
62
|
+
* modal, propagating up to every ancestor. Returns a cleanup that unregisters
|
|
63
|
+
* it. Like {@link registerNested}, callers invoke this from an effect tied to
|
|
64
|
+
* open state so the count stays accurate across open/close/unmount.
|
|
65
|
+
*/
|
|
66
|
+
registerThirdPartyOverlay: () => () => void;
|
|
19
67
|
};
|
|
20
68
|
export type ModalTriggerProviderProps = Pick<ModalTriggerContextType, "state" | "isDismissable"> & {
|
|
21
69
|
children: ReactNode;
|
|
70
|
+
/**
|
|
71
|
+
* How this modal's nested children present relative to it. Cascades to
|
|
72
|
+
* descendants. Defaults to the nearest ancestor's value, or `stack` at the
|
|
73
|
+
* root.
|
|
74
|
+
*/
|
|
75
|
+
childNestingBehavior?: ModalNestingBehavior;
|
|
76
|
+
/**
|
|
77
|
+
* How this modal presents relative to its parent. Local to this modal (does
|
|
78
|
+
* not cascade) and overrides the parent's `childNestingBehavior` for this one
|
|
79
|
+
* connection. Defaults to the parent's `childNestingBehavior`.
|
|
80
|
+
*/
|
|
81
|
+
selfNestingBehavior?: ModalNestingBehavior;
|
|
82
|
+
/**
|
|
83
|
+
* Whether this modal hosts third-party overlays itself. Used to register this
|
|
84
|
+
* modal's subtree with focus-trapping ancestors so they can relax while it's
|
|
85
|
+
* open. This is the underlay's behavior; the provider only needs it to drive
|
|
86
|
+
* registration.
|
|
87
|
+
*/
|
|
88
|
+
allowsThirdPartyOverlays?: boolean;
|
|
22
89
|
};
|
|
23
90
|
export declare const ModalContext: React.Context<ModalContextType | null>;
|
|
24
91
|
export declare const useModalContext: () => ModalContextType;
|
|
25
92
|
export declare const ModalTriggerContext: React.Context<ModalTriggerContextType | null>;
|
|
26
93
|
export declare const useModalTriggerContext: () => ModalTriggerContextType;
|
|
27
94
|
export declare const useModalTrigger: () => OverlayTriggerState;
|
|
28
|
-
export declare function ModalTriggerProvider({ state, isDismissable, children, }: ModalTriggerProviderProps): React.JSX.Element;
|
|
95
|
+
export declare function ModalTriggerProvider({ state, isDismissable, childNestingBehavior, selfNestingBehavior, allowsThirdPartyOverlays, children, }: ModalTriggerProviderProps): React.JSX.Element;
|
|
29
96
|
export {};
|
|
30
97
|
//# sourceMappingURL=context.d.ts.map
|
package/Modal/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/Modal/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACL,aAAa,EACb,SAAS,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/Modal/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACL,aAAa,EACb,SAAS,EAMV,MAAM,OAAO,CAAC;AAKf,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,UAAU,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC5C,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC1C,oBAAoB,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACvD,oBAAoB,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACxD,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,mBAAmB,CAAC;IAC3B;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C;;;OAGG;IACH,mBAAmB,EAAE,oBAAoB,CAAC;IAC1C;;;;;;OAMG;IACH,cAAc,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;IAClD;;;;;OAKG;IACH,2BAA2B,EAAE,OAAO,CAAC;IACrC;;;;;OAKG;IACH,yBAAyB,EAAE,MAAM,MAAM,IAAI,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,uBAAuB,EACvB,OAAO,GAAG,eAAe,CAC1B,GAAG;IACF,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,eAAO,MAAM,YAAY,wCAA+C,CAAC;AAEzE,eAAO,MAAM,eAAe,wBAM3B,CAAC;AAEF,eAAO,MAAM,mBAAmB,+CACqB,CAAC;AAEtD,eAAO,MAAM,sBAAsB,+BAMlC,CAAC;AAEF,eAAO,MAAM,eAAe,2BAG3B,CAAC;AAiIF,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,wBAAgC,EAChC,QAAQ,GACT,EAAE,yBAAyB,qBAkB3B"}
|
package/Modal/index.js
CHANGED
|
@@ -35,14 +35,16 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
35
35
|
const React = require("react");
|
|
36
36
|
const utilities_css = require("../utilities/css.js");
|
|
37
37
|
const utilities_useScrollbar = require("../utilities/useScrollbar.js");
|
|
38
|
+
const mergeProps = require("../__chunks__/mergeProps-DLPcevok.js");
|
|
38
39
|
const Button = require("../__chunks__/Button-CQdi4TMV.js");
|
|
39
40
|
const Close = require("../__chunks__/Close-BQ2IlPyf.js");
|
|
40
41
|
const HorizontalStack = require("../__chunks__/HorizontalStack-CWdKKY8L.js");
|
|
41
42
|
const Icon = require("../__chunks__/Icon-BRlbo3RF.js");
|
|
42
43
|
const Text = require("../__chunks__/Text-DkzMEqky.js");
|
|
43
44
|
const VerticalStack = require("../__chunks__/VerticalStack-BHkiocKU.js");
|
|
44
|
-
const
|
|
45
|
+
const ariaHideOutside = require("../__chunks__/ariaHideOutside-Dl8SH3FU.js");
|
|
45
46
|
const Overlay = require("../__chunks__/Overlay-BNP_t3v4.js");
|
|
47
|
+
const FocusScope = require("../__chunks__/FocusScope-CncDnO-E.js");
|
|
46
48
|
const useOverlayTrigger = require("../__chunks__/useOverlayTrigger-DP9RbCAF.js");
|
|
47
49
|
const useIntersectionDetection = require("../__chunks__/useIntersectionDetection-DI5n4zwA.js");
|
|
48
50
|
const useDialog = require("../__chunks__/useDialog-uxNR0maK.js");
|
|
@@ -66,16 +68,75 @@ const useModalTrigger = () => {
|
|
|
66
68
|
const modalTriggerContext = useModalTriggerContext();
|
|
67
69
|
return modalTriggerContext.state;
|
|
68
70
|
};
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
function useModalNesting({ childNestingBehavior, selfNestingBehavior, allowsThirdPartyOverlays, isOpen }) {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
const parentContext = React.useContext(ModalTriggerContext);
|
|
74
|
+
const [replacingChildCount, setReplacingChildCount] = React.useState(0);
|
|
75
|
+
const [thirdPartyDescendantCount, setThirdPartyDescendantCount] = React.useState(0);
|
|
76
|
+
const childNesting = (_a = childNestingBehavior != null ? childNestingBehavior : parentContext == null ? void 0 : parentContext.childNestingBehavior) != null ? _a : "stack";
|
|
77
|
+
const selfNesting = (_b = selfNestingBehavior != null ? selfNestingBehavior : parentContext == null ? void 0 : parentContext.childNestingBehavior) != null ? _b : "stack";
|
|
78
|
+
const registerNested = React.useCallback((replaces) => {
|
|
79
|
+
if (!replaces) {
|
|
80
|
+
return () => {
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
setReplacingChildCount((count) => count + 1);
|
|
84
|
+
let released = false;
|
|
85
|
+
return () => {
|
|
86
|
+
if (released) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
released = true;
|
|
90
|
+
setReplacingChildCount((count) => Math.max(0, count - 1));
|
|
91
|
+
};
|
|
92
|
+
}, []);
|
|
93
|
+
const parentRegisterNested = parentContext == null ? void 0 : parentContext.registerNested;
|
|
94
|
+
const selfReplacesParent = selfNesting === "replace";
|
|
95
|
+
mergeProps.$f0a04ccd8dbdd83b$export$e5c5a5f917a5871c(() => {
|
|
96
|
+
if (!parentRegisterNested || !isOpen) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
return parentRegisterNested(selfReplacesParent);
|
|
100
|
+
}, [parentRegisterNested, isOpen, selfReplacesParent]);
|
|
101
|
+
const registerThirdPartyOverlay = React.useCallback(() => {
|
|
102
|
+
setThirdPartyDescendantCount((count) => count + 1);
|
|
103
|
+
let released = false;
|
|
104
|
+
return () => {
|
|
105
|
+
if (released) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
released = true;
|
|
109
|
+
setThirdPartyDescendantCount((count) => Math.max(0, count - 1));
|
|
77
110
|
};
|
|
78
|
-
}, [
|
|
111
|
+
}, []);
|
|
112
|
+
const parentRegisterThirdPartyOverlay = parentContext == null ? void 0 : parentContext.registerThirdPartyOverlay;
|
|
113
|
+
const hasThirdPartyInSubtree = allowsThirdPartyOverlays || thirdPartyDescendantCount > 0;
|
|
114
|
+
mergeProps.$f0a04ccd8dbdd83b$export$e5c5a5f917a5871c(() => {
|
|
115
|
+
if (!parentRegisterThirdPartyOverlay || !isOpen || !hasThirdPartyInSubtree) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
return parentRegisterThirdPartyOverlay();
|
|
119
|
+
}, [parentRegisterThirdPartyOverlay, isOpen, hasThirdPartyInSubtree]);
|
|
120
|
+
return React.useMemo(() => ({
|
|
121
|
+
hasReplacingChild: replacingChildCount > 0,
|
|
122
|
+
childNestingBehavior: childNesting,
|
|
123
|
+
selfNestingBehavior: selfNesting,
|
|
124
|
+
registerNested,
|
|
125
|
+
hasOpenThirdPartyDescendant: thirdPartyDescendantCount > 0,
|
|
126
|
+
registerThirdPartyOverlay
|
|
127
|
+
}), [replacingChildCount, childNesting, selfNesting, registerNested, thirdPartyDescendantCount, registerThirdPartyOverlay]);
|
|
128
|
+
}
|
|
129
|
+
function ModalTriggerProvider({ state, isDismissable, childNestingBehavior, selfNestingBehavior, allowsThirdPartyOverlays = false, children }) {
|
|
130
|
+
const nesting = useModalNesting({
|
|
131
|
+
childNestingBehavior,
|
|
132
|
+
selfNestingBehavior,
|
|
133
|
+
allowsThirdPartyOverlays,
|
|
134
|
+
isOpen: state.isOpen
|
|
135
|
+
});
|
|
136
|
+
const context = React.useMemo(() => __spreadProps(__spreadValues({}, nesting), {
|
|
137
|
+
state,
|
|
138
|
+
isDismissable
|
|
139
|
+
}), [nesting, state, isDismissable]);
|
|
79
140
|
return jsxRuntime.jsx(ModalTriggerContext.Provider, {
|
|
80
141
|
value: context,
|
|
81
142
|
children
|
|
@@ -215,34 +276,94 @@ function ModalHeader(props) {
|
|
|
215
276
|
})
|
|
216
277
|
});
|
|
217
278
|
}
|
|
279
|
+
const MODAL_BOX_ATTRIBUTE = "data-easy-ui-modal-box";
|
|
280
|
+
function shouldCloseOnInteractOutside(target) {
|
|
281
|
+
return !target.closest(`[${MODAL_BOX_ATTRIBUTE}]`);
|
|
282
|
+
}
|
|
218
283
|
function ModalUnderlay(props) {
|
|
219
|
-
|
|
220
|
-
|
|
284
|
+
return props.allowsThirdPartyOverlays ? jsxRuntime.jsx(ThirdPartyOverlayUnderlay, __spreadValues({}, props)) : jsxRuntime.jsx(FocusTrappingUnderlay, __spreadValues({}, props));
|
|
285
|
+
}
|
|
286
|
+
function FocusTrappingUnderlay(props) {
|
|
287
|
+
const { state, children, isDismissable = true } = props;
|
|
288
|
+
const { hasOpenThirdPartyDescendant } = useModalTriggerContext();
|
|
289
|
+
const shouldTrap = !hasOpenThirdPartyDescendant;
|
|
221
290
|
const ref = React.useRef(null);
|
|
222
|
-
const {
|
|
291
|
+
const { overlayProps, underlayProps } = ariaHideOutside.$a11501f3d1d39e6c$export$ea8f71083e90600f({
|
|
292
|
+
isOpen: state.isOpen,
|
|
293
|
+
onClose: state.close,
|
|
223
294
|
isDismissable,
|
|
224
|
-
isKeyboardDismissDisabled: !isDismissable
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
295
|
+
isKeyboardDismissDisabled: !isDismissable,
|
|
296
|
+
shouldCloseOnInteractOutside
|
|
297
|
+
}, ref);
|
|
298
|
+
ariaHideOutside.$49c51c25361d4cd2$export$ee0f7cc6afcd1c18({
|
|
299
|
+
isDisabled: !state.isOpen
|
|
300
|
+
});
|
|
301
|
+
React.useEffect(() => {
|
|
302
|
+
if (state.isOpen && shouldTrap && ref.current) {
|
|
303
|
+
return ariaHideOutside.$5e3802645cc19319$export$1c3ebcada18427bf([ref.current], {
|
|
304
|
+
shouldUseInert: true
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}, [state.isOpen, shouldTrap]);
|
|
308
|
+
return jsxRuntime.jsx(ModalUnderlayContent, {
|
|
309
|
+
modalProps: overlayProps,
|
|
310
|
+
underlayProps,
|
|
311
|
+
modalRef: ref,
|
|
312
|
+
shouldContainFocus: shouldTrap,
|
|
313
|
+
children
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
function ThirdPartyOverlayUnderlay(props) {
|
|
317
|
+
const { state, children, isDismissable = true } = props;
|
|
318
|
+
const ref = React.useRef(null);
|
|
319
|
+
const { overlayProps, underlayProps } = ariaHideOutside.$a11501f3d1d39e6c$export$ea8f71083e90600f({
|
|
320
|
+
isOpen: state.isOpen,
|
|
321
|
+
onClose: state.close,
|
|
322
|
+
isDismissable,
|
|
323
|
+
isKeyboardDismissDisabled: !isDismissable,
|
|
324
|
+
shouldCloseOnInteractOutside
|
|
325
|
+
}, ref);
|
|
326
|
+
ariaHideOutside.$49c51c25361d4cd2$export$ee0f7cc6afcd1c18({
|
|
327
|
+
isDisabled: !state.isOpen
|
|
328
|
+
});
|
|
329
|
+
return jsxRuntime.jsx(ModalUnderlayContent, {
|
|
330
|
+
modalProps: overlayProps,
|
|
331
|
+
underlayProps,
|
|
332
|
+
modalRef: ref,
|
|
333
|
+
keepVisibleUnderModal: true,
|
|
334
|
+
children
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
function ModalUnderlayContent({ modalProps, underlayProps, modalRef, children, keepVisibleUnderModal = false, shouldContainFocus = false }) {
|
|
338
|
+
const { hasReplacingChild } = useModalTriggerContext();
|
|
339
|
+
const className = utilities_css.classNames(styles.underlayBg, hasReplacingChild && styles.underlayBgHidden);
|
|
228
340
|
return jsxRuntime.jsx(Overlay.$337b884510726a0d$export$c6fdb837b070b4ff, {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
className
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
className: styles.
|
|
239
|
-
})
|
|
341
|
+
disableFocusManagement: true,
|
|
342
|
+
children: jsxRuntime.jsx(FocusScope.$9bf71ea28793e738$export$20e40289641fbbb6, {
|
|
343
|
+
contain: shouldContainFocus,
|
|
344
|
+
restoreFocus: true,
|
|
345
|
+
children: jsxRuntime.jsx("div", __spreadProps(__spreadValues({
|
|
346
|
+
className
|
|
347
|
+
}, underlayProps), {
|
|
348
|
+
children: jsxRuntime.jsxs("div", __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, modalProps), {
|
|
349
|
+
ref: modalRef,
|
|
350
|
+
className: styles.underlayBox
|
|
351
|
+
}), {
|
|
352
|
+
[MODAL_BOX_ATTRIBUTE]: "true"
|
|
353
|
+
}), {
|
|
354
|
+
"data-live-announcer": keepVisibleUnderModal ? "true" : void 0,
|
|
355
|
+
children: [jsxRuntime.jsx("div", {
|
|
356
|
+
className: styles.underlayEdge
|
|
357
|
+
}), children, jsxRuntime.jsx("div", {
|
|
358
|
+
className: styles.underlayEdge
|
|
359
|
+
})]
|
|
360
|
+
}))
|
|
240
361
|
}))
|
|
241
|
-
})
|
|
362
|
+
})
|
|
242
363
|
});
|
|
243
364
|
}
|
|
244
365
|
function ModalTrigger(props) {
|
|
245
|
-
const _a = props, { children, isDismissable = true } = _a, inTriggerProps = __objRest(_a, ["children", "isDismissable"]);
|
|
366
|
+
const _a = props, { children, isDismissable = true, allowsThirdPartyOverlays = false, childNestingBehavior, selfNestingBehavior } = _a, inTriggerProps = __objRest(_a, ["children", "isDismissable", "allowsThirdPartyOverlays", "childNestingBehavior", "selfNestingBehavior"]);
|
|
246
367
|
const state = Overlay.$fc909762b330b746$export$61c6a8c84e605fb6(inTriggerProps);
|
|
247
368
|
const { triggerProps, overlayProps } = useOverlayTrigger.$628037886ba31236$export$f9d5c8beee7d008d({
|
|
248
369
|
type: "dialog"
|
|
@@ -254,6 +375,9 @@ function ModalTrigger(props) {
|
|
|
254
375
|
return jsxRuntime.jsxs(ModalTriggerProvider, {
|
|
255
376
|
state,
|
|
256
377
|
isDismissable,
|
|
378
|
+
childNestingBehavior,
|
|
379
|
+
selfNestingBehavior,
|
|
380
|
+
allowsThirdPartyOverlays,
|
|
257
381
|
children: [React.cloneElement(trigger, triggerProps), state.isOpen && jsxRuntime.jsx(ModalUnderlay, __spreadProps(__spreadValues({}, props), {
|
|
258
382
|
state,
|
|
259
383
|
children: React.cloneElement(typeof modal === "function" ? modal(state.close) : modal, overlayProps)
|
|
@@ -261,7 +385,7 @@ function ModalTrigger(props) {
|
|
|
261
385
|
});
|
|
262
386
|
}
|
|
263
387
|
function ModalContainer(props) {
|
|
264
|
-
const { children, isDismissable = true, onDismiss = () => {
|
|
388
|
+
const { children, isDismissable = true, allowsThirdPartyOverlays = false, childNestingBehavior, selfNestingBehavior, onDismiss = () => {
|
|
265
389
|
} } = props;
|
|
266
390
|
const childArray = React.Children.toArray(children);
|
|
267
391
|
if (childArray.length > 1) {
|
|
@@ -291,9 +415,13 @@ function ModalContainer(props) {
|
|
|
291
415
|
return jsxRuntime.jsx(ModalTriggerProvider, {
|
|
292
416
|
state,
|
|
293
417
|
isDismissable,
|
|
418
|
+
childNestingBehavior,
|
|
419
|
+
selfNestingBehavior,
|
|
420
|
+
allowsThirdPartyOverlays,
|
|
294
421
|
children: state.isOpen && jsxRuntime.jsx(ModalUnderlay, {
|
|
295
422
|
state,
|
|
296
423
|
isDismissable,
|
|
424
|
+
allowsThirdPartyOverlays,
|
|
297
425
|
children: lastChild ? React.cloneElement(lastChild, overlayProps) : null
|
|
298
426
|
})
|
|
299
427
|
});
|
package/Modal/index.mjs
CHANGED
|
@@ -30,17 +30,19 @@ var __objRest = (source, exclude) => {
|
|
|
30
30
|
return target;
|
|
31
31
|
};
|
|
32
32
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
33
|
-
import React__default, { createContext,
|
|
33
|
+
import React__default, { createContext, useMemo, useContext, useState, useCallback, useRef, useEffect, cloneElement } from "react";
|
|
34
34
|
import { classNames, variationName } from "../utilities/css.mjs";
|
|
35
35
|
import { useScrollbar } from "../utilities/useScrollbar.mjs";
|
|
36
|
+
import { a as $f0a04ccd8dbdd83b$export$e5c5a5f917a5871c } from "../__chunks__/mergeProps-COnPag8r.mjs";
|
|
36
37
|
import { B as Button } from "../__chunks__/Button-JL1YQxJ5.mjs";
|
|
37
38
|
import { C as Close } from "../__chunks__/Close-Cq6Q6MN6.mjs";
|
|
38
39
|
import { H as HorizontalStack } from "../__chunks__/HorizontalStack-CJavrBHm.mjs";
|
|
39
40
|
import { I as Icon } from "../__chunks__/Icon-BIpaQJ_I.mjs";
|
|
40
41
|
import { T as Text } from "../__chunks__/Text-D6oT5WJQ.mjs";
|
|
41
42
|
import { V as VerticalStack } from "../__chunks__/VerticalStack-DoMqBfYD.mjs";
|
|
42
|
-
import { $ as $
|
|
43
|
+
import { $ as $a11501f3d1d39e6c$export$ea8f71083e90600f, a as $49c51c25361d4cd2$export$ee0f7cc6afcd1c18, b as $5e3802645cc19319$export$1c3ebcada18427bf } from "../__chunks__/ariaHideOutside-BYq9cUwo.mjs";
|
|
43
44
|
import { d as $337b884510726a0d$export$c6fdb837b070b4ff, a as $fc909762b330b746$export$61c6a8c84e605fb6 } from "../__chunks__/Overlay-Dkjxuk6V.mjs";
|
|
45
|
+
import { c as $9bf71ea28793e738$export$20e40289641fbbb6 } from "../__chunks__/FocusScope-B_FktBGw.mjs";
|
|
44
46
|
import { $ as $628037886ba31236$export$f9d5c8beee7d008d } from "../__chunks__/useOverlayTrigger-CIVwezu3.mjs";
|
|
45
47
|
import { u as useIntersectionDetection } from "../__chunks__/useIntersectionDetection-BvUmtDgl.mjs";
|
|
46
48
|
import { $ as $40df3f8667284809$export$d55e7ee900f34e93 } from "../__chunks__/useDialog-nKMoC_Cs.mjs";
|
|
@@ -64,16 +66,75 @@ const useModalTrigger = () => {
|
|
|
64
66
|
const modalTriggerContext = useModalTriggerContext();
|
|
65
67
|
return modalTriggerContext.state;
|
|
66
68
|
};
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
function useModalNesting({ childNestingBehavior, selfNestingBehavior, allowsThirdPartyOverlays, isOpen }) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const parentContext = useContext(ModalTriggerContext);
|
|
72
|
+
const [replacingChildCount, setReplacingChildCount] = useState(0);
|
|
73
|
+
const [thirdPartyDescendantCount, setThirdPartyDescendantCount] = useState(0);
|
|
74
|
+
const childNesting = (_a = childNestingBehavior != null ? childNestingBehavior : parentContext == null ? void 0 : parentContext.childNestingBehavior) != null ? _a : "stack";
|
|
75
|
+
const selfNesting = (_b = selfNestingBehavior != null ? selfNestingBehavior : parentContext == null ? void 0 : parentContext.childNestingBehavior) != null ? _b : "stack";
|
|
76
|
+
const registerNested = useCallback((replaces) => {
|
|
77
|
+
if (!replaces) {
|
|
78
|
+
return () => {
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
setReplacingChildCount((count) => count + 1);
|
|
82
|
+
let released = false;
|
|
83
|
+
return () => {
|
|
84
|
+
if (released) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
released = true;
|
|
88
|
+
setReplacingChildCount((count) => Math.max(0, count - 1));
|
|
89
|
+
};
|
|
90
|
+
}, []);
|
|
91
|
+
const parentRegisterNested = parentContext == null ? void 0 : parentContext.registerNested;
|
|
92
|
+
const selfReplacesParent = selfNesting === "replace";
|
|
93
|
+
$f0a04ccd8dbdd83b$export$e5c5a5f917a5871c(() => {
|
|
94
|
+
if (!parentRegisterNested || !isOpen) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
return parentRegisterNested(selfReplacesParent);
|
|
98
|
+
}, [parentRegisterNested, isOpen, selfReplacesParent]);
|
|
99
|
+
const registerThirdPartyOverlay = useCallback(() => {
|
|
100
|
+
setThirdPartyDescendantCount((count) => count + 1);
|
|
101
|
+
let released = false;
|
|
102
|
+
return () => {
|
|
103
|
+
if (released) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
released = true;
|
|
107
|
+
setThirdPartyDescendantCount((count) => Math.max(0, count - 1));
|
|
75
108
|
};
|
|
76
|
-
}, [
|
|
109
|
+
}, []);
|
|
110
|
+
const parentRegisterThirdPartyOverlay = parentContext == null ? void 0 : parentContext.registerThirdPartyOverlay;
|
|
111
|
+
const hasThirdPartyInSubtree = allowsThirdPartyOverlays || thirdPartyDescendantCount > 0;
|
|
112
|
+
$f0a04ccd8dbdd83b$export$e5c5a5f917a5871c(() => {
|
|
113
|
+
if (!parentRegisterThirdPartyOverlay || !isOpen || !hasThirdPartyInSubtree) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
return parentRegisterThirdPartyOverlay();
|
|
117
|
+
}, [parentRegisterThirdPartyOverlay, isOpen, hasThirdPartyInSubtree]);
|
|
118
|
+
return useMemo(() => ({
|
|
119
|
+
hasReplacingChild: replacingChildCount > 0,
|
|
120
|
+
childNestingBehavior: childNesting,
|
|
121
|
+
selfNestingBehavior: selfNesting,
|
|
122
|
+
registerNested,
|
|
123
|
+
hasOpenThirdPartyDescendant: thirdPartyDescendantCount > 0,
|
|
124
|
+
registerThirdPartyOverlay
|
|
125
|
+
}), [replacingChildCount, childNesting, selfNesting, registerNested, thirdPartyDescendantCount, registerThirdPartyOverlay]);
|
|
126
|
+
}
|
|
127
|
+
function ModalTriggerProvider({ state, isDismissable, childNestingBehavior, selfNestingBehavior, allowsThirdPartyOverlays = false, children }) {
|
|
128
|
+
const nesting = useModalNesting({
|
|
129
|
+
childNestingBehavior,
|
|
130
|
+
selfNestingBehavior,
|
|
131
|
+
allowsThirdPartyOverlays,
|
|
132
|
+
isOpen: state.isOpen
|
|
133
|
+
});
|
|
134
|
+
const context = useMemo(() => __spreadProps(__spreadValues({}, nesting), {
|
|
135
|
+
state,
|
|
136
|
+
isDismissable
|
|
137
|
+
}), [nesting, state, isDismissable]);
|
|
77
138
|
return jsx(ModalTriggerContext.Provider, {
|
|
78
139
|
value: context,
|
|
79
140
|
children
|
|
@@ -213,34 +274,94 @@ function ModalHeader(props) {
|
|
|
213
274
|
})
|
|
214
275
|
});
|
|
215
276
|
}
|
|
277
|
+
const MODAL_BOX_ATTRIBUTE = "data-easy-ui-modal-box";
|
|
278
|
+
function shouldCloseOnInteractOutside(target) {
|
|
279
|
+
return !target.closest(`[${MODAL_BOX_ATTRIBUTE}]`);
|
|
280
|
+
}
|
|
216
281
|
function ModalUnderlay(props) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const {
|
|
282
|
+
return props.allowsThirdPartyOverlays ? jsx(ThirdPartyOverlayUnderlay, __spreadValues({}, props)) : jsx(FocusTrappingUnderlay, __spreadValues({}, props));
|
|
283
|
+
}
|
|
284
|
+
function FocusTrappingUnderlay(props) {
|
|
285
|
+
const { state, children, isDismissable = true } = props;
|
|
286
|
+
const { hasOpenThirdPartyDescendant } = useModalTriggerContext();
|
|
287
|
+
const shouldTrap = !hasOpenThirdPartyDescendant;
|
|
288
|
+
const ref = useRef(null);
|
|
289
|
+
const { overlayProps, underlayProps } = $a11501f3d1d39e6c$export$ea8f71083e90600f({
|
|
290
|
+
isOpen: state.isOpen,
|
|
291
|
+
onClose: state.close,
|
|
221
292
|
isDismissable,
|
|
222
|
-
isKeyboardDismissDisabled: !isDismissable
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
293
|
+
isKeyboardDismissDisabled: !isDismissable,
|
|
294
|
+
shouldCloseOnInteractOutside
|
|
295
|
+
}, ref);
|
|
296
|
+
$49c51c25361d4cd2$export$ee0f7cc6afcd1c18({
|
|
297
|
+
isDisabled: !state.isOpen
|
|
298
|
+
});
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (state.isOpen && shouldTrap && ref.current) {
|
|
301
|
+
return $5e3802645cc19319$export$1c3ebcada18427bf([ref.current], {
|
|
302
|
+
shouldUseInert: true
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}, [state.isOpen, shouldTrap]);
|
|
306
|
+
return jsx(ModalUnderlayContent, {
|
|
307
|
+
modalProps: overlayProps,
|
|
308
|
+
underlayProps,
|
|
309
|
+
modalRef: ref,
|
|
310
|
+
shouldContainFocus: shouldTrap,
|
|
311
|
+
children
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
function ThirdPartyOverlayUnderlay(props) {
|
|
315
|
+
const { state, children, isDismissable = true } = props;
|
|
316
|
+
const ref = useRef(null);
|
|
317
|
+
const { overlayProps, underlayProps } = $a11501f3d1d39e6c$export$ea8f71083e90600f({
|
|
318
|
+
isOpen: state.isOpen,
|
|
319
|
+
onClose: state.close,
|
|
320
|
+
isDismissable,
|
|
321
|
+
isKeyboardDismissDisabled: !isDismissable,
|
|
322
|
+
shouldCloseOnInteractOutside
|
|
323
|
+
}, ref);
|
|
324
|
+
$49c51c25361d4cd2$export$ee0f7cc6afcd1c18({
|
|
325
|
+
isDisabled: !state.isOpen
|
|
326
|
+
});
|
|
327
|
+
return jsx(ModalUnderlayContent, {
|
|
328
|
+
modalProps: overlayProps,
|
|
329
|
+
underlayProps,
|
|
330
|
+
modalRef: ref,
|
|
331
|
+
keepVisibleUnderModal: true,
|
|
332
|
+
children
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function ModalUnderlayContent({ modalProps, underlayProps, modalRef, children, keepVisibleUnderModal = false, shouldContainFocus = false }) {
|
|
336
|
+
const { hasReplacingChild } = useModalTriggerContext();
|
|
337
|
+
const className = classNames(styles.underlayBg, hasReplacingChild && styles.underlayBgHidden);
|
|
226
338
|
return jsx($337b884510726a0d$export$c6fdb837b070b4ff, {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
className
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
className: styles.
|
|
237
|
-
})
|
|
339
|
+
disableFocusManagement: true,
|
|
340
|
+
children: jsx($9bf71ea28793e738$export$20e40289641fbbb6, {
|
|
341
|
+
contain: shouldContainFocus,
|
|
342
|
+
restoreFocus: true,
|
|
343
|
+
children: jsx("div", __spreadProps(__spreadValues({
|
|
344
|
+
className
|
|
345
|
+
}, underlayProps), {
|
|
346
|
+
children: jsxs("div", __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, modalProps), {
|
|
347
|
+
ref: modalRef,
|
|
348
|
+
className: styles.underlayBox
|
|
349
|
+
}), {
|
|
350
|
+
[MODAL_BOX_ATTRIBUTE]: "true"
|
|
351
|
+
}), {
|
|
352
|
+
"data-live-announcer": keepVisibleUnderModal ? "true" : void 0,
|
|
353
|
+
children: [jsx("div", {
|
|
354
|
+
className: styles.underlayEdge
|
|
355
|
+
}), children, jsx("div", {
|
|
356
|
+
className: styles.underlayEdge
|
|
357
|
+
})]
|
|
358
|
+
}))
|
|
238
359
|
}))
|
|
239
|
-
})
|
|
360
|
+
})
|
|
240
361
|
});
|
|
241
362
|
}
|
|
242
363
|
function ModalTrigger(props) {
|
|
243
|
-
const _a = props, { children, isDismissable = true } = _a, inTriggerProps = __objRest(_a, ["children", "isDismissable"]);
|
|
364
|
+
const _a = props, { children, isDismissable = true, allowsThirdPartyOverlays = false, childNestingBehavior, selfNestingBehavior } = _a, inTriggerProps = __objRest(_a, ["children", "isDismissable", "allowsThirdPartyOverlays", "childNestingBehavior", "selfNestingBehavior"]);
|
|
244
365
|
const state = $fc909762b330b746$export$61c6a8c84e605fb6(inTriggerProps);
|
|
245
366
|
const { triggerProps, overlayProps } = $628037886ba31236$export$f9d5c8beee7d008d({
|
|
246
367
|
type: "dialog"
|
|
@@ -252,6 +373,9 @@ function ModalTrigger(props) {
|
|
|
252
373
|
return jsxs(ModalTriggerProvider, {
|
|
253
374
|
state,
|
|
254
375
|
isDismissable,
|
|
376
|
+
childNestingBehavior,
|
|
377
|
+
selfNestingBehavior,
|
|
378
|
+
allowsThirdPartyOverlays,
|
|
255
379
|
children: [cloneElement(trigger, triggerProps), state.isOpen && jsx(ModalUnderlay, __spreadProps(__spreadValues({}, props), {
|
|
256
380
|
state,
|
|
257
381
|
children: cloneElement(typeof modal === "function" ? modal(state.close) : modal, overlayProps)
|
|
@@ -259,7 +383,7 @@ function ModalTrigger(props) {
|
|
|
259
383
|
});
|
|
260
384
|
}
|
|
261
385
|
function ModalContainer(props) {
|
|
262
|
-
const { children, isDismissable = true, onDismiss = () => {
|
|
386
|
+
const { children, isDismissable = true, allowsThirdPartyOverlays = false, childNestingBehavior, selfNestingBehavior, onDismiss = () => {
|
|
263
387
|
} } = props;
|
|
264
388
|
const childArray = React__default.Children.toArray(children);
|
|
265
389
|
if (childArray.length > 1) {
|
|
@@ -289,9 +413,13 @@ function ModalContainer(props) {
|
|
|
289
413
|
return jsx(ModalTriggerProvider, {
|
|
290
414
|
state,
|
|
291
415
|
isDismissable,
|
|
416
|
+
childNestingBehavior,
|
|
417
|
+
selfNestingBehavior,
|
|
418
|
+
allowsThirdPartyOverlays,
|
|
292
419
|
children: state.isOpen && jsx(ModalUnderlay, {
|
|
293
420
|
state,
|
|
294
421
|
isDismissable,
|
|
422
|
+
allowsThirdPartyOverlays,
|
|
295
423
|
children: lastChild ? cloneElement(lastChild, overlayProps) : null
|
|
296
424
|
})
|
|
297
425
|
});
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easypost/easy-ui",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.122",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"**/*.css"
|
|
6
6
|
],
|
|
7
7
|
"dependencies": {
|
|
8
|
+
"@react-aria/overlays": "^3.31.0",
|
|
8
9
|
"@easypost/easy-ui-icons": "1.0.0-alpha.55",
|
|
9
10
|
"@easypost/easy-ui-tokens": "1.0.0-alpha.17",
|
|
10
11
|
"@react-aria/toast": "^3.0.9",
|