@easypost/easy-ui 1.0.0-alpha.121 → 1.0.0-alpha.123

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @easypost/easy-ui
2
2
 
3
+ ## 1.0.0-alpha.123
4
+
5
+ ### Patch Changes
6
+
7
+ - 04c7aab: Select now keeps its size after you choose a value, so medium and large fields stay the same height instead of shrinking a step
8
+ - bb3e69e: the Select now keeps its size after you choose a value when there is no secondary text. if the selected option has secondary text, it shrinks slightly to match our Figma designs
9
+
10
+ ## 1.0.0-alpha.122
11
+
12
+ ### Minor Changes
13
+
14
+ - 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).
15
+
16
+ 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.
17
+
18
+ ### Patch Changes
19
+
20
+ - 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.
21
+ - 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.
22
+
3
23
  ## 1.0.0-alpha.121
4
24
 
5
25
  ### Minor 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
@@ -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;AAI5C,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"}
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Modal.nesting.test.d.ts.map
@@ -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":"AACA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAQvD,OAAO,EAAE,KAAK,EAAmC,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM9C,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,iBA4FpB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,UAqBxB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,UA0B5B,CAAC"}
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.
@@ -16,6 +17,21 @@ type ModalContainerProps = {
16
17
  * @default false
17
18
  */
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;
19
35
  /**
20
36
  * Handler that is called when the overlay is closed.
21
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;AAM/E,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;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,qBAmDxD"}
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"}
@@ -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
  /**
@@ -23,6 +24,21 @@ export type ModalTriggerProps = {
23
24
  * @default false
24
25
  */
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;
26
42
  /**
27
43
  * Whether the modal is open by default (controlled).
28
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;AAM1D,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;;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,qBA8BpD"}
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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ModalUnderlay.d.ts","sourceRoot":"","sources":["../../src/Modal/ModalUnderlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAqB,MAAM,OAAO,CAAC;AAQ5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAMpD,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;AASF,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,qBAOtD"}
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"}
@@ -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
- hasOpenNestedModal: boolean;
18
- setHasOpenNestedModal: (hasOpenNestedModal: boolean) => void;
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
@@ -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,EAKV,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,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,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,CAAC,kBAAkB,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9D,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,uBAAuB,EACvB,OAAO,GAAG,eAAe,CAC1B,GAAG;IACF,QAAQ,EAAE,SAAS,CAAC;CACrB,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;AAEF,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,aAAa,EACb,QAAQ,GACT,EAAE,yBAAyB,qBAU3B"}
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,6 +35,7 @@ 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");
@@ -42,8 +43,8 @@ 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
45
  const ariaHideOutside = require("../__chunks__/ariaHideOutside-Dl8SH3FU.js");
45
- const useModalOverlay = require("../__chunks__/useModalOverlay-C4Gci3MA.js");
46
46
  const Overlay = require("../__chunks__/Overlay-BNP_t3v4.js");
47
+ const FocusScope = require("../__chunks__/FocusScope-CncDnO-E.js");
47
48
  const useOverlayTrigger = require("../__chunks__/useOverlayTrigger-DP9RbCAF.js");
48
49
  const useIntersectionDetection = require("../__chunks__/useIntersectionDetection-DI5n4zwA.js");
49
50
  const useDialog = require("../__chunks__/useDialog-uxNR0maK.js");
@@ -67,16 +68,75 @@ const useModalTrigger = () => {
67
68
  const modalTriggerContext = useModalTriggerContext();
68
69
  return modalTriggerContext.state;
69
70
  };
70
- function ModalTriggerProvider({ state, isDismissable, children }) {
71
- const [hasOpenNestedModal, setHasOpenNestedModal] = React.useState(false);
72
- const context = React.useMemo(() => {
73
- return {
74
- hasOpenNestedModal,
75
- setHasOpenNestedModal,
76
- state,
77
- isDismissable
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));
78
91
  };
79
- }, [hasOpenNestedModal, state, isDismissable]);
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));
110
+ };
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]);
80
140
  return jsxRuntime.jsx(ModalTriggerContext.Provider, {
81
141
  value: context,
82
142
  children
@@ -216,20 +276,40 @@ function ModalHeader(props) {
216
276
  })
217
277
  });
218
278
  }
279
+ const MODAL_BOX_ATTRIBUTE = "data-easy-ui-modal-box";
280
+ function shouldCloseOnInteractOutside(target) {
281
+ return !target.closest(`[${MODAL_BOX_ATTRIBUTE}]`);
282
+ }
219
283
  function ModalUnderlay(props) {
220
284
  return props.allowsThirdPartyOverlays ? jsxRuntime.jsx(ThirdPartyOverlayUnderlay, __spreadValues({}, props)) : jsxRuntime.jsx(FocusTrappingUnderlay, __spreadValues({}, props));
221
285
  }
222
286
  function FocusTrappingUnderlay(props) {
223
287
  const { state, children, isDismissable = true } = props;
288
+ const { hasOpenThirdPartyDescendant } = useModalTriggerContext();
289
+ const shouldTrap = !hasOpenThirdPartyDescendant;
224
290
  const ref = React.useRef(null);
225
- const { modalProps, underlayProps } = useModalOverlay.$8ac8429251c45e4b$export$dbc0f175b25fb0fb({
291
+ const { overlayProps, underlayProps } = ariaHideOutside.$a11501f3d1d39e6c$export$ea8f71083e90600f({
292
+ isOpen: state.isOpen,
293
+ onClose: state.close,
226
294
  isDismissable,
227
- isKeyboardDismissDisabled: !isDismissable
228
- }, state, ref);
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]);
229
308
  return jsxRuntime.jsx(ModalUnderlayContent, {
230
- modalProps,
309
+ modalProps: overlayProps,
231
310
  underlayProps,
232
311
  modalRef: ref,
312
+ shouldContainFocus: shouldTrap,
233
313
  children
234
314
  });
235
315
  }
@@ -240,7 +320,8 @@ function ThirdPartyOverlayUnderlay(props) {
240
320
  isOpen: state.isOpen,
241
321
  onClose: state.close,
242
322
  isDismissable,
243
- isKeyboardDismissDisabled: !isDismissable
323
+ isKeyboardDismissDisabled: !isDismissable,
324
+ shouldCloseOnInteractOutside
244
325
  }, ref);
245
326
  ariaHideOutside.$49c51c25361d4cd2$export$ee0f7cc6afcd1c18({
246
327
  isDisabled: !state.isOpen
@@ -249,30 +330,40 @@ function ThirdPartyOverlayUnderlay(props) {
249
330
  modalProps: overlayProps,
250
331
  underlayProps,
251
332
  modalRef: ref,
333
+ keepVisibleUnderModal: true,
252
334
  children
253
335
  });
254
336
  }
255
- function ModalUnderlayContent({ modalProps, underlayProps, modalRef, children }) {
256
- const { hasOpenNestedModal } = useModalTriggerContext();
257
- const className = utilities_css.classNames(styles.underlayBg, hasOpenNestedModal && styles.underlayBgHidden);
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);
258
340
  return jsxRuntime.jsx(Overlay.$337b884510726a0d$export$c6fdb837b070b4ff, {
259
- children: jsxRuntime.jsx("div", __spreadProps(__spreadValues({
260
- className
261
- }, underlayProps), {
262
- children: jsxRuntime.jsxs("div", __spreadProps(__spreadValues({}, modalProps), {
263
- ref: modalRef,
264
- className: styles.underlayBox,
265
- children: [jsxRuntime.jsx("div", {
266
- className: styles.underlayEdge
267
- }), children, jsxRuntime.jsx("div", {
268
- className: styles.underlayEdge
269
- })]
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
+ }))
270
361
  }))
271
- }))
362
+ })
272
363
  });
273
364
  }
274
365
  function ModalTrigger(props) {
275
- 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"]);
276
367
  const state = Overlay.$fc909762b330b746$export$61c6a8c84e605fb6(inTriggerProps);
277
368
  const { triggerProps, overlayProps } = useOverlayTrigger.$628037886ba31236$export$f9d5c8beee7d008d({
278
369
  type: "dialog"
@@ -284,6 +375,9 @@ function ModalTrigger(props) {
284
375
  return jsxRuntime.jsxs(ModalTriggerProvider, {
285
376
  state,
286
377
  isDismissable,
378
+ childNestingBehavior,
379
+ selfNestingBehavior,
380
+ allowsThirdPartyOverlays,
287
381
  children: [React.cloneElement(trigger, triggerProps), state.isOpen && jsxRuntime.jsx(ModalUnderlay, __spreadProps(__spreadValues({}, props), {
288
382
  state,
289
383
  children: React.cloneElement(typeof modal === "function" ? modal(state.close) : modal, overlayProps)
@@ -291,7 +385,7 @@ function ModalTrigger(props) {
291
385
  });
292
386
  }
293
387
  function ModalContainer(props) {
294
- const { children, isDismissable = true, allowsThirdPartyOverlays = false, onDismiss = () => {
388
+ const { children, isDismissable = true, allowsThirdPartyOverlays = false, childNestingBehavior, selfNestingBehavior, onDismiss = () => {
295
389
  } } = props;
296
390
  const childArray = React.Children.toArray(children);
297
391
  if (childArray.length > 1) {
@@ -321,6 +415,9 @@ function ModalContainer(props) {
321
415
  return jsxRuntime.jsx(ModalTriggerProvider, {
322
416
  state,
323
417
  isDismissable,
418
+ childNestingBehavior,
419
+ selfNestingBehavior,
420
+ allowsThirdPartyOverlays,
324
421
  children: state.isOpen && jsxRuntime.jsx(ModalUnderlay, {
325
422
  state,
326
423
  isDismissable,
package/Modal/index.mjs CHANGED
@@ -30,18 +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, useState, useMemo, useContext, useRef, cloneElement } from "react";
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 $a11501f3d1d39e6c$export$ea8f71083e90600f, a as $49c51c25361d4cd2$export$ee0f7cc6afcd1c18 } from "../__chunks__/ariaHideOutside-BYq9cUwo.mjs";
43
- import { $ as $8ac8429251c45e4b$export$dbc0f175b25fb0fb } from "../__chunks__/useModalOverlay-BmYXH7rq.mjs";
43
+ import { $ as $a11501f3d1d39e6c$export$ea8f71083e90600f, a as $49c51c25361d4cd2$export$ee0f7cc6afcd1c18, b as $5e3802645cc19319$export$1c3ebcada18427bf } from "../__chunks__/ariaHideOutside-BYq9cUwo.mjs";
44
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";
45
46
  import { $ as $628037886ba31236$export$f9d5c8beee7d008d } from "../__chunks__/useOverlayTrigger-CIVwezu3.mjs";
46
47
  import { u as useIntersectionDetection } from "../__chunks__/useIntersectionDetection-BvUmtDgl.mjs";
47
48
  import { $ as $40df3f8667284809$export$d55e7ee900f34e93 } from "../__chunks__/useDialog-nKMoC_Cs.mjs";
@@ -65,16 +66,75 @@ const useModalTrigger = () => {
65
66
  const modalTriggerContext = useModalTriggerContext();
66
67
  return modalTriggerContext.state;
67
68
  };
68
- function ModalTriggerProvider({ state, isDismissable, children }) {
69
- const [hasOpenNestedModal, setHasOpenNestedModal] = useState(false);
70
- const context = useMemo(() => {
71
- return {
72
- hasOpenNestedModal,
73
- setHasOpenNestedModal,
74
- state,
75
- isDismissable
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));
76
89
  };
77
- }, [hasOpenNestedModal, state, isDismissable]);
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));
108
+ };
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]);
78
138
  return jsx(ModalTriggerContext.Provider, {
79
139
  value: context,
80
140
  children
@@ -214,20 +274,40 @@ function ModalHeader(props) {
214
274
  })
215
275
  });
216
276
  }
277
+ const MODAL_BOX_ATTRIBUTE = "data-easy-ui-modal-box";
278
+ function shouldCloseOnInteractOutside(target) {
279
+ return !target.closest(`[${MODAL_BOX_ATTRIBUTE}]`);
280
+ }
217
281
  function ModalUnderlay(props) {
218
282
  return props.allowsThirdPartyOverlays ? jsx(ThirdPartyOverlayUnderlay, __spreadValues({}, props)) : jsx(FocusTrappingUnderlay, __spreadValues({}, props));
219
283
  }
220
284
  function FocusTrappingUnderlay(props) {
221
285
  const { state, children, isDismissable = true } = props;
286
+ const { hasOpenThirdPartyDescendant } = useModalTriggerContext();
287
+ const shouldTrap = !hasOpenThirdPartyDescendant;
222
288
  const ref = useRef(null);
223
- const { modalProps, underlayProps } = $8ac8429251c45e4b$export$dbc0f175b25fb0fb({
289
+ const { overlayProps, underlayProps } = $a11501f3d1d39e6c$export$ea8f71083e90600f({
290
+ isOpen: state.isOpen,
291
+ onClose: state.close,
224
292
  isDismissable,
225
- isKeyboardDismissDisabled: !isDismissable
226
- }, state, ref);
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]);
227
306
  return jsx(ModalUnderlayContent, {
228
- modalProps,
307
+ modalProps: overlayProps,
229
308
  underlayProps,
230
309
  modalRef: ref,
310
+ shouldContainFocus: shouldTrap,
231
311
  children
232
312
  });
233
313
  }
@@ -238,7 +318,8 @@ function ThirdPartyOverlayUnderlay(props) {
238
318
  isOpen: state.isOpen,
239
319
  onClose: state.close,
240
320
  isDismissable,
241
- isKeyboardDismissDisabled: !isDismissable
321
+ isKeyboardDismissDisabled: !isDismissable,
322
+ shouldCloseOnInteractOutside
242
323
  }, ref);
243
324
  $49c51c25361d4cd2$export$ee0f7cc6afcd1c18({
244
325
  isDisabled: !state.isOpen
@@ -247,30 +328,40 @@ function ThirdPartyOverlayUnderlay(props) {
247
328
  modalProps: overlayProps,
248
329
  underlayProps,
249
330
  modalRef: ref,
331
+ keepVisibleUnderModal: true,
250
332
  children
251
333
  });
252
334
  }
253
- function ModalUnderlayContent({ modalProps, underlayProps, modalRef, children }) {
254
- const { hasOpenNestedModal } = useModalTriggerContext();
255
- const className = classNames(styles.underlayBg, hasOpenNestedModal && styles.underlayBgHidden);
335
+ function ModalUnderlayContent({ modalProps, underlayProps, modalRef, children, keepVisibleUnderModal = false, shouldContainFocus = false }) {
336
+ const { hasReplacingChild } = useModalTriggerContext();
337
+ const className = classNames(styles.underlayBg, hasReplacingChild && styles.underlayBgHidden);
256
338
  return jsx($337b884510726a0d$export$c6fdb837b070b4ff, {
257
- children: jsx("div", __spreadProps(__spreadValues({
258
- className
259
- }, underlayProps), {
260
- children: jsxs("div", __spreadProps(__spreadValues({}, modalProps), {
261
- ref: modalRef,
262
- className: styles.underlayBox,
263
- children: [jsx("div", {
264
- className: styles.underlayEdge
265
- }), children, jsx("div", {
266
- className: styles.underlayEdge
267
- })]
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
+ }))
268
359
  }))
269
- }))
360
+ })
270
361
  });
271
362
  }
272
363
  function ModalTrigger(props) {
273
- 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"]);
274
365
  const state = $fc909762b330b746$export$61c6a8c84e605fb6(inTriggerProps);
275
366
  const { triggerProps, overlayProps } = $628037886ba31236$export$f9d5c8beee7d008d({
276
367
  type: "dialog"
@@ -282,6 +373,9 @@ function ModalTrigger(props) {
282
373
  return jsxs(ModalTriggerProvider, {
283
374
  state,
284
375
  isDismissable,
376
+ childNestingBehavior,
377
+ selfNestingBehavior,
378
+ allowsThirdPartyOverlays,
285
379
  children: [cloneElement(trigger, triggerProps), state.isOpen && jsx(ModalUnderlay, __spreadProps(__spreadValues({}, props), {
286
380
  state,
287
381
  children: cloneElement(typeof modal === "function" ? modal(state.close) : modal, overlayProps)
@@ -289,7 +383,7 @@ function ModalTrigger(props) {
289
383
  });
290
384
  }
291
385
  function ModalContainer(props) {
292
- const { children, isDismissable = true, allowsThirdPartyOverlays = false, onDismiss = () => {
386
+ const { children, isDismissable = true, allowsThirdPartyOverlays = false, childNestingBehavior, selfNestingBehavior, onDismiss = () => {
293
387
  } } = props;
294
388
  const childArray = React__default.Children.toArray(children);
295
389
  if (childArray.length > 1) {
@@ -319,6 +413,9 @@ function ModalContainer(props) {
319
413
  return jsx(ModalTriggerProvider, {
320
414
  state,
321
415
  isDismissable,
416
+ childNestingBehavior,
417
+ selfNestingBehavior,
418
+ allowsThirdPartyOverlays,
322
419
  children: state.isOpen && jsx(ModalUnderlay, {
323
420
  state,
324
421
  isDismissable,
@@ -39,7 +39,7 @@ const Menu = require("../__chunks__/Menu-MGDv1tob.js");
39
39
  const Text = require("../__chunks__/Text-DkzMEqky.js");
40
40
  const Icon = require("../__chunks__/Icon-BRlbo3RF.js");
41
41
  const UnstyledButton = require("../__chunks__/UnstyledButton-DW8CjaXN.js");
42
- const SelectOverlay = require("../__chunks__/SelectOverlay-DpI9vNLw.js");
42
+ const SelectOverlay = require("../__chunks__/SelectOverlay-Dh126Smn.js");
43
43
  const useTriggerWidth = require("../__chunks__/useTriggerWidth-NhYqZmlX.js");
44
44
  const ExpandMore400 = require("../__chunks__/ExpandMore400-CJpvxyJm.js");
45
45
  const Close = require("../__chunks__/Close-BQ2IlPyf.js");
@@ -38,7 +38,7 @@ import { M as Menu } from "../__chunks__/Menu-Ci1FGh8B.mjs";
38
38
  import { T as Text } from "../__chunks__/Text-D6oT5WJQ.mjs";
39
39
  import { I as Icon } from "../__chunks__/Icon-BIpaQJ_I.mjs";
40
40
  import { U as UnstyledButton } from "../__chunks__/UnstyledButton-DxJLvL-G.mjs";
41
- import { u as useInternalSelectContext, $ as $bdd25dc72710631f$export$cbd84cdb2e668835, a as $2bc3a590c5373a4e$export$5159ec8b34d4ec12, b as $58aed456727eb0f3$export$e64b2f635402ca43, I as InternalSelectContext, S as SelectOverlay, d as SelectOption } from "../__chunks__/SelectOverlay-C23EXgqX.mjs";
41
+ import { u as useInternalSelectContext, $ as $bdd25dc72710631f$export$cbd84cdb2e668835, a as $2bc3a590c5373a4e$export$5159ec8b34d4ec12, b as $58aed456727eb0f3$export$e64b2f635402ca43, I as InternalSelectContext, S as SelectOverlay, d as SelectOption } from "../__chunks__/SelectOverlay-K-ZKp0JS.mjs";
42
42
  import { u as useTriggerWidth } from "../__chunks__/useTriggerWidth-CBghrvjy.mjs";
43
43
  import { E as ExpandMore400 } from "../__chunks__/ExpandMore400-CH7GNxqk.mjs";
44
44
  import { C as Close } from "../__chunks__/Close-Cq6Q6MN6.mjs";
package/Select/index.js CHANGED
@@ -21,7 +21,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
21
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
22
22
  const jsxRuntime = require("react/jsx-runtime");
23
23
  const React = require("react");
24
- const SelectOverlay = require("../__chunks__/SelectOverlay-DpI9vNLw.js");
24
+ const SelectOverlay = require("../__chunks__/SelectOverlay-Dh126Smn.js");
25
25
  const utilities_css = require("../utilities/css.js");
26
26
  const InputCaption = require("../__chunks__/InputCaption-CccF4ynE.js");
27
27
  const Text = require("../__chunks__/Text-DkzMEqky.js");
@@ -87,7 +87,7 @@ function SelectField(props) {
87
87
  size,
88
88
  children: selectState.selectedItem ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
89
89
  children: [jsxRuntime.jsx(Text.Text, {
90
- variant: "body2",
90
+ variant: selectedDescription ? "body2" : void 0,
91
91
  truncate: true,
92
92
  children: selectState.selectedItem.rendered
93
93
  }), selectedDescription && jsxRuntime.jsx("span", {
package/Select/index.mjs CHANGED
@@ -19,7 +19,7 @@ var __spreadValues = (a, b) => {
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
21
21
  import React__default, { useMemo } from "react";
22
- import { u as useInternalSelectContext, s as styles, $ as $bdd25dc72710631f$export$cbd84cdb2e668835, a as $2bc3a590c5373a4e$export$5159ec8b34d4ec12, b as $58aed456727eb0f3$export$e64b2f635402ca43, I as InternalSelectContext, S as SelectOverlay, c as SelectSection, d as SelectOption } from "../__chunks__/SelectOverlay-C23EXgqX.mjs";
22
+ import { u as useInternalSelectContext, s as styles, $ as $bdd25dc72710631f$export$cbd84cdb2e668835, a as $2bc3a590c5373a4e$export$5159ec8b34d4ec12, b as $58aed456727eb0f3$export$e64b2f635402ca43, I as InternalSelectContext, S as SelectOverlay, c as SelectSection, d as SelectOption } from "../__chunks__/SelectOverlay-K-ZKp0JS.mjs";
23
23
  import { classNames, variationName } from "../utilities/css.mjs";
24
24
  import { L as Label, I as InputCaption } from "../__chunks__/InputCaption-DoyGkWQe.mjs";
25
25
  import { T as Text } from "../__chunks__/Text-D6oT5WJQ.mjs";
@@ -85,7 +85,7 @@ function SelectField(props) {
85
85
  size,
86
86
  children: selectState.selectedItem ? jsxs(Fragment, {
87
87
  children: [jsx(Text, {
88
- variant: "body2",
88
+ variant: selectedDescription ? "body2" : void 0,
89
89
  truncate: true,
90
90
  children: selectState.selectedItem.rendered
91
91
  }), selectedDescription && jsx("span", {
@@ -464,7 +464,7 @@ function SelectOptionContent({ item, state }) {
464
464
  children: jsxRuntime.jsxs("div", {
465
465
  className: styles.optionContent,
466
466
  children: [jsxRuntime.jsx(Text.Text, {
467
- variant: "body2",
467
+ variant: description ? "body2" : "body1",
468
468
  truncate: true,
469
469
  children: item.rendered
470
470
  }), description && jsxRuntime.jsx("span", {
@@ -463,7 +463,7 @@ function SelectOptionContent({ item, state }) {
463
463
  children: jsxs("div", {
464
464
  className: styles.optionContent,
465
465
  children: [jsx(Text, {
466
- variant: "body2",
466
+ variant: description ? "body2" : "body1",
467
467
  truncate: true,
468
468
  children: item.rendered
469
469
  }), description && jsx("span", {
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@easypost/easy-ui",
3
- "version": "1.0.0-alpha.121",
3
+ "version": "1.0.0-alpha.123",
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",