@sproutsocial/seeds-react-modal 2.4.8 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +28 -28
- package/CHANGELOG.md +70 -0
- package/dist/{Modal-ki8oiGbC.d.mts → Modal-DTeKLfEI.d.mts} +1 -1
- package/dist/{Modal-ki8oiGbC.d.ts → Modal-DTeKLfEI.d.ts} +1 -1
- package/dist/{ModalAction-BHG3Zbd9.d.mts → ModalExternalTrigger-BnbJk9zY.d.mts} +85 -3
- package/dist/{ModalAction-BHG3Zbd9.d.ts → ModalExternalTrigger-BnbJk9zY.d.ts} +85 -3
- package/dist/esm/{chunk-ZY6VJ7XT.js → chunk-62MRZAJV.js} +36 -10
- package/dist/esm/chunk-62MRZAJV.js.map +1 -0
- package/dist/esm/{chunk-IYDY4OPB.js → chunk-72GBDCA2.js} +17 -1
- package/dist/esm/chunk-72GBDCA2.js.map +1 -0
- package/dist/esm/index.js +10 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v1/index.js +1 -1
- package/dist/esm/v2/index.js +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +85 -11
- package/dist/index.js.map +1 -1
- package/dist/v1/index.d.mts +2 -2
- package/dist/v1/index.d.ts +2 -2
- package/dist/v1/index.js +16 -0
- package/dist/v1/index.js.map +1 -1
- package/dist/v2/index.d.mts +4 -77
- package/dist/v2/index.d.ts +4 -77
- package/dist/v2/index.js +35 -9
- package/dist/v2/index.js.map +1 -1
- package/package.json +7 -7
- package/src/Modal.stories.tsx +64 -0
- package/src/__tests__/v1/Modal.test.tsx +146 -1
- package/src/__tests__/v2/Modal.test.tsx +182 -0
- package/src/index.ts +4 -0
- package/src/v1/Modal.tsx +30 -0
- package/src/v2/Modal.tsx +8 -0
- package/src/v2/ModalTypes.ts +9 -2
- package/src/v2/ModalV2.stories.tsx +476 -49
- package/src/v2/components/ModalFooter.tsx +15 -4
- package/dist/esm/chunk-IYDY4OPB.js.map +0 -1
- package/dist/esm/chunk-ZY6VJ7XT.js.map +0 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -3,39 +3,39 @@ $ tsup --dts
|
|
|
3
3
|
[34mCLI[39m Building entry: {"index":"src/index.ts","v1/index":"src/v1/index.ts","v2/index":"src/v2/index.ts"}
|
|
4
4
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
5
5
|
[34mCLI[39m tsup v8.5.0
|
|
6
|
-
[34mCLI[39m Using tsup config: /home/runner/
|
|
6
|
+
[34mCLI[39m Using tsup config: /home/runner/_work/seeds/seeds/seeds-react/seeds-react-modal/tsup.config.ts
|
|
7
7
|
[34mCLI[39m Target: es2022
|
|
8
8
|
[34mCLI[39m Cleaning output folder
|
|
9
9
|
[34mCJS[39m Build start
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m41.30 KB[39m
|
|
12
|
+
[32mCJS[39m [1mdist/v1/index.js [22m[32m10.31 KB[39m
|
|
13
|
+
[32mCJS[39m [1mdist/v2/index.js [22m[32m32.84 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m81.32 KB[39m
|
|
15
|
+
[32mCJS[39m [1mdist/v1/index.js.map [22m[32m14.56 KB[39m
|
|
16
|
+
[32mCJS[39m [1mdist/v2/index.js.map [22m[32m66.44 KB[39m
|
|
17
|
+
[32mCJS[39m ⚡️ Build success in 57ms
|
|
11
18
|
[32mESM[39m [1mdist/esm/v1/index.js [22m[32m165.00 B[39m
|
|
12
|
-
[32mESM[39m [1mdist/esm/index.js [22m[32m583.00 B[39m
|
|
13
19
|
[32mESM[39m [1mdist/esm/v2/index.js [22m[32m746.00 B[39m
|
|
14
|
-
[32mESM[39m [1mdist/esm/
|
|
15
|
-
[32mESM[39m [1mdist/esm/chunk-
|
|
16
|
-
[32mESM[39m [1mdist/esm/
|
|
17
|
-
[32mESM[39m [1mdist/esm/index.js.map [22m[32m1.05 KB[39m
|
|
20
|
+
[32mESM[39m [1mdist/esm/index.js [22m[32m733.00 B[39m
|
|
21
|
+
[32mESM[39m [1mdist/esm/chunk-72GBDCA2.js [22m[32m7.57 KB[39m
|
|
22
|
+
[32mESM[39m [1mdist/esm/chunk-62MRZAJV.js [22m[32m27.81 KB[39m
|
|
18
23
|
[32mESM[39m [1mdist/esm/v2/index.js.map [22m[32m71.00 B[39m
|
|
19
|
-
[32mESM[39m [1mdist/esm/
|
|
20
|
-
[32mESM[39m [1mdist/esm/
|
|
21
|
-
[32mESM[39m
|
|
22
|
-
[
|
|
23
|
-
[
|
|
24
|
-
[32mCJS[39m [1mdist/index.js [22m[32m39.21 KB[39m
|
|
25
|
-
[32mCJS[39m [1mdist/v1/index.js.map [22m[32m13.03 KB[39m
|
|
26
|
-
[32mCJS[39m [1mdist/v2/index.js.map [22m[32m64.79 KB[39m
|
|
27
|
-
[32mCJS[39m [1mdist/index.js.map [22m[32m77.51 KB[39m
|
|
28
|
-
[32mCJS[39m ⚡️ Build success in 263ms
|
|
24
|
+
[32mESM[39m [1mdist/esm/v1/index.js.map [22m[32m71.00 B[39m
|
|
25
|
+
[32mESM[39m [1mdist/esm/index.js.map [22m[32m1.16 KB[39m
|
|
26
|
+
[32mESM[39m [1mdist/esm/chunk-72GBDCA2.js.map [22m[32m14.38 KB[39m
|
|
27
|
+
[32mESM[39m [1mdist/esm/chunk-62MRZAJV.js.map [22m[32m65.36 KB[39m
|
|
28
|
+
[32mESM[39m ⚡️ Build success in 58ms
|
|
29
29
|
[34mDTS[39m Build start
|
|
30
|
-
[32mDTS[39m ⚡️ Build success in
|
|
31
|
-
[32mDTS[39m [1mdist/index.d.ts
|
|
32
|
-
[32mDTS[39m [1mdist/v1/index.d.ts
|
|
33
|
-
[32mDTS[39m [1mdist/v2/index.d.ts
|
|
34
|
-
[32mDTS[39m [1mdist/Modal-
|
|
35
|
-
[32mDTS[39m [1mdist/
|
|
36
|
-
[32mDTS[39m [1mdist/index.d.mts
|
|
37
|
-
[32mDTS[39m [1mdist/v1/index.d.mts
|
|
38
|
-
[32mDTS[39m [1mdist/v2/index.d.mts
|
|
39
|
-
[32mDTS[39m [1mdist/Modal-
|
|
40
|
-
[32mDTS[39m [1mdist/
|
|
41
|
-
Done in
|
|
30
|
+
[32mDTS[39m ⚡️ Build success in 4510ms
|
|
31
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.07 KB[39m
|
|
32
|
+
[32mDTS[39m [1mdist/v1/index.d.ts [22m[32m413.00 B[39m
|
|
33
|
+
[32mDTS[39m [1mdist/v2/index.d.ts [22m[32m1.16 KB[39m
|
|
34
|
+
[32mDTS[39m [1mdist/Modal-DTeKLfEI.d.ts [22m[32m2.52 KB[39m
|
|
35
|
+
[32mDTS[39m [1mdist/ModalExternalTrigger-BnbJk9zY.d.ts [22m[32m23.41 KB[39m
|
|
36
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m1.08 KB[39m
|
|
37
|
+
[32mDTS[39m [1mdist/v1/index.d.mts [22m[32m415.00 B[39m
|
|
38
|
+
[32mDTS[39m [1mdist/v2/index.d.mts [22m[32m1.16 KB[39m
|
|
39
|
+
[32mDTS[39m [1mdist/Modal-DTeKLfEI.d.mts [22m[32m2.52 KB[39m
|
|
40
|
+
[32mDTS[39m [1mdist/ModalExternalTrigger-BnbJk9zY.d.mts [22m[32m23.41 KB[39m
|
|
41
|
+
Done in 5.41s.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,75 @@
|
|
|
1
1
|
# @sproutsocial/seeds-react-modal
|
|
2
2
|
|
|
3
|
+
## 2.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- badefd7: Add `closeOnPrimaryAction` prop to ModalFooter to support async primary actions without auto-closing. Document all Modal V2 close event handlers (`onEscapeKeyDown`, `onInteractOutside`, `closeButtonProps.onClick`, etc.) and convenience props (`disableEscapeKeyClose`, `disableOutsideClickClose`) on the reference site and PropTable.
|
|
8
|
+
|
|
9
|
+
## 2.4.13
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 62285b4: Title: Export useModalTriggerProps, useModalExternalTrigger, and ModalExternalTrigger from top-level package; add controlled modal and accessible trigger documentation
|
|
14
|
+
|
|
15
|
+
Description:
|
|
16
|
+
|
|
17
|
+
Exports `useModalTriggerProps`, `useModalExternalTrigger`, `ModalExternalTrigger`, and `ModalExternalTriggerProps` from the main `seeds-react-modal` package entry point so consumers can import them from `@sproutsocial/racine` without reaching into the `/v2` subpath.
|
|
18
|
+
|
|
19
|
+
Updates reference site and Storybook documentation to cover:
|
|
20
|
+
|
|
21
|
+
- Uncontrolled vs controlled modal patterns with clear recommendations
|
|
22
|
+
- `useModalExternalTrigger`, `ModalExternalTrigger`, and `useModalTriggerProps` usage for controlled modals
|
|
23
|
+
- Accessible triggers for Modal V1 using `useModalTriggerProps` as a stopgap before migration
|
|
24
|
+
- Nested Modal V2 stacking with `zIndex` prop
|
|
25
|
+
- Fixes "can not" → "can't" in destructive confirmation example (issue #1973)
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [7d54d67]
|
|
28
|
+
- @sproutsocial/seeds-react-button@1.4.0
|
|
29
|
+
|
|
30
|
+
## 2.4.12
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- Updated dependencies [17d4f12]
|
|
35
|
+
- @sproutsocial/seeds-react-theme@3.6.0
|
|
36
|
+
- @sproutsocial/seeds-react-box@1.1.14
|
|
37
|
+
- @sproutsocial/seeds-react-icon@2.2.5
|
|
38
|
+
- @sproutsocial/seeds-react-button@1.3.20
|
|
39
|
+
|
|
40
|
+
## 2.4.11
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- 2689788: Fix Toast and Modal V1 being unclickable when Modal V2 is open
|
|
45
|
+
|
|
46
|
+
When a Radix Dialog (Modal V2) is open, it sets `pointer-events: none` on `document.body`
|
|
47
|
+
and listens for `pointerdown` on the document to detect outside clicks. This breaks non-Radix
|
|
48
|
+
overlays that portal to body (Toast, Modal V1) — making them unclickable and causing Modal V2
|
|
49
|
+
to dismiss when interacting with them.
|
|
50
|
+
|
|
51
|
+
**Toast**: Wrap `ToastRoot` in Radix `DismissableLayerBranch` with `pointer-events: auto`.
|
|
52
|
+
This registers the toast container as a branch of the dismissable layer system, preventing
|
|
53
|
+
Modal V2 from closing on toast interaction.
|
|
54
|
+
|
|
55
|
+
**Modal V1**: Use react-modal's `contentRef` to set `pointer-events: auto` on the portal node
|
|
56
|
+
and stop `pointerdown` propagation. `DismissableLayerBranch` can't be used here because
|
|
57
|
+
react-modal portals to `document.body`, and Modal V2's `transform` creates a containing block
|
|
58
|
+
that would break V1's `position: fixed` overlay if portaled inside V2.
|
|
59
|
+
|
|
60
|
+
## 2.4.10
|
|
61
|
+
|
|
62
|
+
### Patch Changes
|
|
63
|
+
|
|
64
|
+
- @sproutsocial/seeds-react-button@1.3.19
|
|
65
|
+
|
|
66
|
+
## 2.4.9
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- 6f71236: fix(menu): add `type="button"` to MenuItem to prevent form auto-submit inside Modal V2
|
|
71
|
+
fix(modal): prevent Escape key from closing modal when a V1 Popout is open
|
|
72
|
+
|
|
3
73
|
## 2.4.8
|
|
4
74
|
|
|
5
75
|
### Patch Changes
|
|
@@ -66,4 +66,4 @@ declare const Modal: {
|
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
export { Modal as M, type
|
|
69
|
+
export { Modal as M, type TypeModalCloseButtonProps as T, type TypeModalContentProps as a, type TypeModalFooterProps as b, type TypeModalHeaderProps as c, type TypeModalProps as d };
|
|
@@ -66,4 +66,4 @@ declare const Modal: {
|
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
export { Modal as M, type
|
|
69
|
+
export { Modal as M, type TypeModalCloseButtonProps as T, type TypeModalContentProps as a, type TypeModalFooterProps as b, type TypeModalHeaderProps as c, type TypeModalProps as d };
|
|
@@ -2,9 +2,10 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import * as styled_components from 'styled-components';
|
|
4
4
|
import * as _sproutsocial_seeds_react_box from '@sproutsocial/seeds-react-box';
|
|
5
|
-
import {
|
|
5
|
+
import { TypeBoxProps, TypeContainerProps } from '@sproutsocial/seeds-react-box';
|
|
6
6
|
import * as Dialog from '@radix-ui/react-dialog';
|
|
7
7
|
import { TypeIconName } from '@sproutsocial/seeds-react-icon';
|
|
8
|
+
import { TypeButtonProps } from '@sproutsocial/seeds-react-button';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Props for ModalHeader component.
|
|
@@ -57,7 +58,15 @@ interface TypeModalDescriptionProps extends TypeBoxProps {
|
|
|
57
58
|
* Note: This component only supports slots (button props).
|
|
58
59
|
* For custom footers, use ModalCustomFooter instead.
|
|
59
60
|
*/
|
|
60
|
-
type TypeModalFooterProps = TypeBoxProps &
|
|
61
|
+
type TypeModalFooterProps = TypeBoxProps & {
|
|
62
|
+
/**
|
|
63
|
+
* Whether clicking the primary button automatically closes the modal.
|
|
64
|
+
* Set to `false` when the primary action is async (e.g., saving data)
|
|
65
|
+
* and the modal should stay open until the operation completes.
|
|
66
|
+
* @default true
|
|
67
|
+
*/
|
|
68
|
+
closeOnPrimaryAction?: boolean;
|
|
69
|
+
} & ({
|
|
61
70
|
/** Primary action button - automatically wrapped in ModalCloseWrapper */
|
|
62
71
|
primaryButton: React.ReactNode;
|
|
63
72
|
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper */
|
|
@@ -561,4 +570,77 @@ declare const ModalRail: React.FC<TypeModalRailProps>;
|
|
|
561
570
|
|
|
562
571
|
declare const ModalAction: React.FC<TypeModalActionProps>;
|
|
563
572
|
|
|
564
|
-
|
|
573
|
+
/**
|
|
574
|
+
* Props for ModalExternalTrigger component.
|
|
575
|
+
*/
|
|
576
|
+
interface ModalExternalTriggerProps extends Omit<TypeButtonProps, "onClick"> {
|
|
577
|
+
/** Callback when button is clicked to trigger modal open */
|
|
578
|
+
onTrigger: () => void;
|
|
579
|
+
/** Whether the modal is currently open (for ARIA expanded state) */
|
|
580
|
+
isOpen: boolean;
|
|
581
|
+
/** Optional modal ID for aria-controls attribute */
|
|
582
|
+
modalId?: string;
|
|
583
|
+
/** Optional onClick handler (called before onTrigger) */
|
|
584
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* A Button component pre-configured for triggering modals from outside the Modal component tree.
|
|
588
|
+
*
|
|
589
|
+
* ⚠️ **NOT RECOMMENDED** - Prefer using modalTrigger prop or ModalTrigger component.
|
|
590
|
+
* Use this component ONLY as a last resort when architectural constraints prevent keeping
|
|
591
|
+
* the trigger inside the Modal component tree.
|
|
592
|
+
*
|
|
593
|
+
* This component wraps the Seeds Button with automatic ARIA attributes for modal triggers.
|
|
594
|
+
* However, focus restoration still requires manual handling via onCloseAutoFocus callback
|
|
595
|
+
* due to Radix UI's architectural limitations with external triggers.
|
|
596
|
+
*
|
|
597
|
+
* **Why modalTrigger prop is better:**
|
|
598
|
+
* - Automatic ARIA attributes
|
|
599
|
+
* - Automatic focus restoration (no onCloseAutoFocus needed)
|
|
600
|
+
* - Better touch device support
|
|
601
|
+
* - Follows WAI-ARIA Dialog best practices
|
|
602
|
+
*
|
|
603
|
+
* **When to use ModalExternalTrigger:**
|
|
604
|
+
* - Trigger must live outside Modal component tree (e.g., in a page header)
|
|
605
|
+
* - Using Seeds Button as the trigger
|
|
606
|
+
* - Want automatic ARIA attributes without manual hook usage
|
|
607
|
+
*
|
|
608
|
+
* **Usage pattern with focus restoration:**
|
|
609
|
+
* You must still handle focus restoration manually by passing a ref and implementing
|
|
610
|
+
* onCloseAutoFocus on the Modal component.
|
|
611
|
+
*
|
|
612
|
+
* @example
|
|
613
|
+
* ```tsx
|
|
614
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
615
|
+
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
616
|
+
*
|
|
617
|
+
* return (
|
|
618
|
+
* <>
|
|
619
|
+
* <ModalExternalTrigger
|
|
620
|
+
* ref={triggerRef}
|
|
621
|
+
* isOpen={isOpen}
|
|
622
|
+
* onTrigger={() => setIsOpen(true)}
|
|
623
|
+
* appearance="primary"
|
|
624
|
+
* >
|
|
625
|
+
* Open Modal
|
|
626
|
+
* </ModalExternalTrigger>
|
|
627
|
+
*
|
|
628
|
+
* <Modal
|
|
629
|
+
* open={isOpen}
|
|
630
|
+
* onOpenChange={setIsOpen}
|
|
631
|
+
* onCloseAutoFocus={(e) => {
|
|
632
|
+
* e.preventDefault();
|
|
633
|
+
* triggerRef.current?.focus();
|
|
634
|
+
* }}
|
|
635
|
+
* >
|
|
636
|
+
* <ModalBody>Content</ModalBody>
|
|
637
|
+
* </Modal>
|
|
638
|
+
* </>
|
|
639
|
+
* );
|
|
640
|
+
* ```
|
|
641
|
+
*
|
|
642
|
+
* @see useModalExternalTrigger - Hook alternative for non-Button triggers
|
|
643
|
+
*/
|
|
644
|
+
declare const ModalExternalTrigger: React.ForwardRefExoticComponent<Omit<ModalExternalTriggerProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
645
|
+
|
|
646
|
+
export { ModalAction as M, type TypeModalActionProps as T, ModalBody as a, ModalCloseWrapper as b, type ModalCloseWrapperProps as c, ModalCustomFooter as d, ModalCustomHeader as e, ModalDescription as f, ModalExternalTrigger as g, type ModalExternalTriggerProps as h, ModalFooter as i, ModalHeader as j, ModalRail as k, Modal as l, type TypeModalRailProps as m, type TypeModalBodyProps as n, type TypeModalDescriptionProps as o, type TypeModalFooterProps as p, type TypeModalHeaderProps as q, type TypeModalProps as r, useModalTriggerProps as s, useModalExternalTrigger as u };
|
|
@@ -2,9 +2,10 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import * as styled_components from 'styled-components';
|
|
4
4
|
import * as _sproutsocial_seeds_react_box from '@sproutsocial/seeds-react-box';
|
|
5
|
-
import {
|
|
5
|
+
import { TypeBoxProps, TypeContainerProps } from '@sproutsocial/seeds-react-box';
|
|
6
6
|
import * as Dialog from '@radix-ui/react-dialog';
|
|
7
7
|
import { TypeIconName } from '@sproutsocial/seeds-react-icon';
|
|
8
|
+
import { TypeButtonProps } from '@sproutsocial/seeds-react-button';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Props for ModalHeader component.
|
|
@@ -57,7 +58,15 @@ interface TypeModalDescriptionProps extends TypeBoxProps {
|
|
|
57
58
|
* Note: This component only supports slots (button props).
|
|
58
59
|
* For custom footers, use ModalCustomFooter instead.
|
|
59
60
|
*/
|
|
60
|
-
type TypeModalFooterProps = TypeBoxProps &
|
|
61
|
+
type TypeModalFooterProps = TypeBoxProps & {
|
|
62
|
+
/**
|
|
63
|
+
* Whether clicking the primary button automatically closes the modal.
|
|
64
|
+
* Set to `false` when the primary action is async (e.g., saving data)
|
|
65
|
+
* and the modal should stay open until the operation completes.
|
|
66
|
+
* @default true
|
|
67
|
+
*/
|
|
68
|
+
closeOnPrimaryAction?: boolean;
|
|
69
|
+
} & ({
|
|
61
70
|
/** Primary action button - automatically wrapped in ModalCloseWrapper */
|
|
62
71
|
primaryButton: React.ReactNode;
|
|
63
72
|
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper */
|
|
@@ -561,4 +570,77 @@ declare const ModalRail: React.FC<TypeModalRailProps>;
|
|
|
561
570
|
|
|
562
571
|
declare const ModalAction: React.FC<TypeModalActionProps>;
|
|
563
572
|
|
|
564
|
-
|
|
573
|
+
/**
|
|
574
|
+
* Props for ModalExternalTrigger component.
|
|
575
|
+
*/
|
|
576
|
+
interface ModalExternalTriggerProps extends Omit<TypeButtonProps, "onClick"> {
|
|
577
|
+
/** Callback when button is clicked to trigger modal open */
|
|
578
|
+
onTrigger: () => void;
|
|
579
|
+
/** Whether the modal is currently open (for ARIA expanded state) */
|
|
580
|
+
isOpen: boolean;
|
|
581
|
+
/** Optional modal ID for aria-controls attribute */
|
|
582
|
+
modalId?: string;
|
|
583
|
+
/** Optional onClick handler (called before onTrigger) */
|
|
584
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* A Button component pre-configured for triggering modals from outside the Modal component tree.
|
|
588
|
+
*
|
|
589
|
+
* ⚠️ **NOT RECOMMENDED** - Prefer using modalTrigger prop or ModalTrigger component.
|
|
590
|
+
* Use this component ONLY as a last resort when architectural constraints prevent keeping
|
|
591
|
+
* the trigger inside the Modal component tree.
|
|
592
|
+
*
|
|
593
|
+
* This component wraps the Seeds Button with automatic ARIA attributes for modal triggers.
|
|
594
|
+
* However, focus restoration still requires manual handling via onCloseAutoFocus callback
|
|
595
|
+
* due to Radix UI's architectural limitations with external triggers.
|
|
596
|
+
*
|
|
597
|
+
* **Why modalTrigger prop is better:**
|
|
598
|
+
* - Automatic ARIA attributes
|
|
599
|
+
* - Automatic focus restoration (no onCloseAutoFocus needed)
|
|
600
|
+
* - Better touch device support
|
|
601
|
+
* - Follows WAI-ARIA Dialog best practices
|
|
602
|
+
*
|
|
603
|
+
* **When to use ModalExternalTrigger:**
|
|
604
|
+
* - Trigger must live outside Modal component tree (e.g., in a page header)
|
|
605
|
+
* - Using Seeds Button as the trigger
|
|
606
|
+
* - Want automatic ARIA attributes without manual hook usage
|
|
607
|
+
*
|
|
608
|
+
* **Usage pattern with focus restoration:**
|
|
609
|
+
* You must still handle focus restoration manually by passing a ref and implementing
|
|
610
|
+
* onCloseAutoFocus on the Modal component.
|
|
611
|
+
*
|
|
612
|
+
* @example
|
|
613
|
+
* ```tsx
|
|
614
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
615
|
+
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
616
|
+
*
|
|
617
|
+
* return (
|
|
618
|
+
* <>
|
|
619
|
+
* <ModalExternalTrigger
|
|
620
|
+
* ref={triggerRef}
|
|
621
|
+
* isOpen={isOpen}
|
|
622
|
+
* onTrigger={() => setIsOpen(true)}
|
|
623
|
+
* appearance="primary"
|
|
624
|
+
* >
|
|
625
|
+
* Open Modal
|
|
626
|
+
* </ModalExternalTrigger>
|
|
627
|
+
*
|
|
628
|
+
* <Modal
|
|
629
|
+
* open={isOpen}
|
|
630
|
+
* onOpenChange={setIsOpen}
|
|
631
|
+
* onCloseAutoFocus={(e) => {
|
|
632
|
+
* e.preventDefault();
|
|
633
|
+
* triggerRef.current?.focus();
|
|
634
|
+
* }}
|
|
635
|
+
* >
|
|
636
|
+
* <ModalBody>Content</ModalBody>
|
|
637
|
+
* </Modal>
|
|
638
|
+
* </>
|
|
639
|
+
* );
|
|
640
|
+
* ```
|
|
641
|
+
*
|
|
642
|
+
* @see useModalExternalTrigger - Hook alternative for non-Button triggers
|
|
643
|
+
*/
|
|
644
|
+
declare const ModalExternalTrigger: React.ForwardRefExoticComponent<Omit<ModalExternalTriggerProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
645
|
+
|
|
646
|
+
export { ModalAction as M, type TypeModalActionProps as T, ModalBody as a, ModalCloseWrapper as b, type ModalCloseWrapperProps as c, ModalCustomFooter as d, ModalCustomHeader as e, ModalDescription as f, ModalExternalTrigger as g, type ModalExternalTriggerProps as h, ModalFooter as i, ModalHeader as j, ModalRail as k, Modal as l, type TypeModalRailProps as m, type TypeModalBodyProps as n, type TypeModalDescriptionProps as o, type TypeModalFooterProps as p, type TypeModalHeaderProps as q, type TypeModalProps as r, useModalTriggerProps as s, useModalExternalTrigger as u };
|
|
@@ -486,15 +486,22 @@ var ModalCustomFooter = styled3(Box2)`
|
|
|
486
486
|
`;
|
|
487
487
|
ModalCustomFooter.displayName = "ModalCustomFooter";
|
|
488
488
|
var ModalFooter = (props) => {
|
|
489
|
-
const {
|
|
489
|
+
const {
|
|
490
|
+
cancelButton,
|
|
491
|
+
primaryButton,
|
|
492
|
+
leftAction,
|
|
493
|
+
closeOnPrimaryAction = true,
|
|
494
|
+
...rest
|
|
495
|
+
} = props;
|
|
490
496
|
if (!cancelButton && !primaryButton && !leftAction) {
|
|
491
497
|
return null;
|
|
492
498
|
}
|
|
499
|
+
const wrappedPrimaryButton = primaryButton && closeOnPrimaryAction ? /* @__PURE__ */ jsx4(ModalCloseWrapper, { children: primaryButton }) : primaryButton;
|
|
493
500
|
return /* @__PURE__ */ jsxs2(ModalCustomFooter, { "data-slot": "modal-footer", "data-qa-modal-footer": true, ...rest, children: [
|
|
494
501
|
leftAction ? leftAction : null,
|
|
495
502
|
/* @__PURE__ */ jsxs2(Box2, { display: "flex", gap: 300, marginLeft: "auto", children: [
|
|
496
503
|
cancelButton && /* @__PURE__ */ jsx4(ModalCloseWrapper, { children: cancelButton }),
|
|
497
|
-
|
|
504
|
+
wrappedPrimaryButton
|
|
498
505
|
] })
|
|
499
506
|
] });
|
|
500
507
|
};
|
|
@@ -607,7 +614,6 @@ import Icon from "@sproutsocial/seeds-react-icon";
|
|
|
607
614
|
|
|
608
615
|
// ../seeds-react-mixins/dist/esm/index.js
|
|
609
616
|
import { css } from "styled-components";
|
|
610
|
-
import { theme } from "@sproutsocial/seeds-react-theme";
|
|
611
617
|
var visuallyHidden = css`
|
|
612
618
|
position: absolute;
|
|
613
619
|
width: 1px;
|
|
@@ -619,11 +625,12 @@ var visuallyHidden = css`
|
|
|
619
625
|
border: 0;
|
|
620
626
|
`;
|
|
621
627
|
var focusRing = css`
|
|
622
|
-
box-shadow: 0 0 0 1px
|
|
628
|
+
box-shadow: 0 0 0 1px
|
|
629
|
+
${({ theme }) => theme.colors.button.primary.background.base},
|
|
623
630
|
0 0px 0px 4px
|
|
624
631
|
color-mix(
|
|
625
632
|
in srgb,
|
|
626
|
-
${theme.colors.button.primary.background.base},
|
|
633
|
+
${({ theme }) => theme.colors.button.primary.background.base},
|
|
627
634
|
transparent 70%
|
|
628
635
|
);
|
|
629
636
|
outline: none;
|
|
@@ -633,15 +640,30 @@ var focusRing = css`
|
|
|
633
640
|
}
|
|
634
641
|
`;
|
|
635
642
|
var pill = css`
|
|
636
|
-
min-width: ${theme.space[600]};
|
|
637
|
-
min-height: ${theme.space[600]};
|
|
638
|
-
padding: ${theme.space[300]};
|
|
639
|
-
border-radius: ${theme.radii.pill};
|
|
643
|
+
min-width: ${({ theme }) => theme.space[600]};
|
|
644
|
+
min-height: ${({ theme }) => theme.space[600]};
|
|
645
|
+
padding: ${({ theme }) => theme.space[300]};
|
|
646
|
+
border-radius: ${({ theme }) => theme.radii.pill};
|
|
640
647
|
`;
|
|
641
648
|
var disabled = css`
|
|
642
649
|
opacity: 0.4;
|
|
643
650
|
pointer-events: none;
|
|
644
651
|
`;
|
|
652
|
+
var container = css`
|
|
653
|
+
background: ${({ theme }) => theme.colors.container.background.base};
|
|
654
|
+
border: ${({ theme }) => theme.borders[500]}
|
|
655
|
+
${({ theme }) => theme.colors.container.border.base};
|
|
656
|
+
border-radius: ${({ theme }) => theme.radii.outer};
|
|
657
|
+
`;
|
|
658
|
+
var divider = css`
|
|
659
|
+
border-bottom: ${({ theme }) => theme.borderWidths[500]} solid
|
|
660
|
+
${({ theme }) => theme.colors.container.border.base};
|
|
661
|
+
`;
|
|
662
|
+
var truncate = css`
|
|
663
|
+
text-overflow: ellipsis;
|
|
664
|
+
overflow: hidden;
|
|
665
|
+
white-space: nowrap;
|
|
666
|
+
`;
|
|
645
667
|
|
|
646
668
|
// src/v2/components/ModalAction.tsx
|
|
647
669
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
@@ -837,6 +859,10 @@ var Modal = (props) => {
|
|
|
837
859
|
);
|
|
838
860
|
const wrappedOnEscapeKeyDown = React12.useCallback(
|
|
839
861
|
(e) => {
|
|
862
|
+
const hasOpenPopout = document.querySelector("[data-qa-popout]") !== null;
|
|
863
|
+
if (hasOpenPopout) {
|
|
864
|
+
e.preventDefault();
|
|
865
|
+
}
|
|
840
866
|
if (disableEscapeKeyClose) {
|
|
841
867
|
e.preventDefault();
|
|
842
868
|
}
|
|
@@ -960,4 +986,4 @@ export {
|
|
|
960
986
|
useModalExternalTrigger,
|
|
961
987
|
Modal_default
|
|
962
988
|
};
|
|
963
|
-
//# sourceMappingURL=chunk-
|
|
989
|
+
//# sourceMappingURL=chunk-62MRZAJV.js.map
|