@sproutsocial/seeds-react-modal 2.1.2 → 2.2.1
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 +14 -14
- package/CHANGELOG.md +29 -0
- package/dist/{ModalAction-BB7qJtQj.d.mts → ModalAction-gIgCE73I.d.mts} +163 -189
- package/dist/{ModalAction-BB7qJtQj.d.ts → ModalAction-gIgCE73I.d.ts} +163 -189
- package/dist/esm/{chunk-ETVICNHP.js → chunk-52SXX6AG.js} +65 -10
- package/dist/esm/chunk-52SXX6AG.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/v2/index.js +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +64 -9
- package/dist/index.js.map +1 -1
- package/dist/v2/index.d.mts +1 -1
- package/dist/v2/index.d.ts +1 -1
- package/dist/v2/index.js +64 -9
- package/dist/v2/index.js.map +1 -1
- package/package.json +7 -7
- package/src/v2/Modal.tsx +14 -2
- package/src/v2/ModalTypes.ts +191 -201
- package/src/v2/ModalV2.stories.tsx +106 -66
- package/src/v2/components/ModalAction.tsx +4 -0
- package/src/v2/components/ModalBody.tsx +6 -1
- package/src/v2/components/ModalCloseWrapper.tsx +7 -1
- package/src/v2/components/ModalContent.tsx +19 -4
- package/src/v2/components/ModalDescription.tsx +6 -1
- package/src/v2/components/ModalFooter.tsx +1 -1
- package/src/v2/components/ModalHeader.tsx +2 -0
- package/src/v2/components/ModalOverlay.tsx +2 -1
- package/dist/esm/chunk-ETVICNHP.js.map +0 -1
|
@@ -9,295 +9,269 @@ import { TypeIconName } from '@sproutsocial/seeds-react-icon';
|
|
|
9
9
|
/**
|
|
10
10
|
* Props for ModalHeader component.
|
|
11
11
|
*
|
|
12
|
-
* Renders the modal's header with title and optional subtitle.
|
|
13
|
-
* when the modal has draggable enabled.
|
|
12
|
+
* Renders the modal's header with title and optional subtitle.
|
|
13
|
+
* Supports draggable functionality when the modal has draggable enabled.
|
|
14
14
|
*
|
|
15
|
-
* Note: This component only supports slots (title/subtitle props).
|
|
16
|
-
* use ModalCustomHeader instead.
|
|
15
|
+
* Note: This component only supports slots (title/subtitle props).
|
|
16
|
+
* For custom headers, use ModalCustomHeader instead.
|
|
17
17
|
*/
|
|
18
18
|
interface TypeModalHeaderProps extends TypeBoxProps {
|
|
19
19
|
/** Modal title text displayed as a headline */
|
|
20
20
|
title?: string;
|
|
21
21
|
/**
|
|
22
22
|
* Modal subtitle text.
|
|
23
|
-
*
|
|
24
|
-
* This is automatically wrapped in `Dialog.Description` from Radix UI,
|
|
25
|
-
* which provides accessible description text for screen readers. The subtitle
|
|
26
|
-
* provides additional context about the modal and is announced alongside
|
|
27
|
-
* the title when the dialog opens. Radix UI automatically connects this to
|
|
28
|
-
* the dialog via ARIA attributes (typically `aria-describedby` on the dialog root).
|
|
23
|
+
* Automatically wrapped in Dialog.Description for accessibility.
|
|
29
24
|
*/
|
|
30
25
|
subtitle?: string;
|
|
31
|
-
/** Additional props for
|
|
26
|
+
/** Additional props for Dialog.Title when title is provided */
|
|
32
27
|
titleProps?: Omit<React.ComponentPropsWithoutRef<typeof Dialog.Title>, "asChild" | "children">;
|
|
33
|
-
/**
|
|
34
|
-
* Additional props for the Dialog.Description when subtitle is provided.
|
|
35
|
-
*
|
|
36
|
-
* Dialog.Description provides accessible description text for the modal that
|
|
37
|
-
* screen readers announce when the dialog opens. It complements Dialog.Title
|
|
38
|
-
* by providing additional context about the modal. Radix UI automatically
|
|
39
|
-
* connects this to the dialog via ARIA attributes.
|
|
40
|
-
*/
|
|
28
|
+
/** Additional props for Dialog.Description when subtitle is provided */
|
|
41
29
|
subtitleProps?: Omit<React.ComponentPropsWithoutRef<typeof Dialog.Description>, "asChild" | "children">;
|
|
42
30
|
}
|
|
43
31
|
/**
|
|
44
|
-
* Props for
|
|
45
|
-
*
|
|
46
|
-
* Provides automatic button wrapping and layout management. At least one action
|
|
47
|
-
* (cancelButton, primaryButton, or leftAction) must be provided.
|
|
48
|
-
*
|
|
49
|
-
* Note: This component only supports slots (button props). For custom footers,
|
|
50
|
-
* use ModalCustomFooter instead.
|
|
32
|
+
* Props for ModalBody component.
|
|
51
33
|
*
|
|
52
|
-
*
|
|
53
|
-
|
|
54
|
-
|
|
34
|
+
* Renders the scrollable main content area of the modal.
|
|
35
|
+
*/
|
|
36
|
+
interface TypeModalBodyProps extends TypeBoxProps {
|
|
37
|
+
/** The main content of the modal body */
|
|
38
|
+
children?: React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Props for ModalDescription component.
|
|
55
42
|
*
|
|
56
|
-
*
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
43
|
+
* Wraps content with Dialog.Description for accessible descriptions.
|
|
44
|
+
*/
|
|
45
|
+
interface TypeModalDescriptionProps extends TypeBoxProps {
|
|
46
|
+
/** The description text content */
|
|
47
|
+
children: React.ReactNode;
|
|
48
|
+
/** Additional props for Dialog.Description */
|
|
49
|
+
descriptionProps?: Omit<React.ComponentPropsWithoutRef<typeof Dialog.Description>, "asChild" | "children">;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Props for ModalFooter component.
|
|
62
53
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* <ModalFooter leftAction={<Button>Delete</Button>} />
|
|
54
|
+
* Provides automatic button wrapping and layout management.
|
|
55
|
+
* At least one action (cancelButton, primaryButton, or leftAction) must be provided.
|
|
66
56
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* <ModalFooter />
|
|
57
|
+
* Note: This component only supports slots (button props).
|
|
58
|
+
* For custom footers, use ModalCustomFooter instead.
|
|
70
59
|
*/
|
|
71
60
|
type TypeModalFooterProps = TypeBoxProps & ({
|
|
72
|
-
/** Primary action button - automatically wrapped in ModalCloseWrapper
|
|
61
|
+
/** Primary action button - automatically wrapped in ModalCloseWrapper */
|
|
73
62
|
primaryButton: React.ReactNode;
|
|
74
|
-
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper
|
|
63
|
+
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper */
|
|
75
64
|
cancelButton?: React.ReactNode;
|
|
76
|
-
/** Optional action on the far left (e.g., Delete
|
|
65
|
+
/** Optional action on the far left (e.g., Delete) - NOT automatically wrapped */
|
|
77
66
|
leftAction?: React.ReactNode;
|
|
78
67
|
} | {
|
|
79
|
-
/** Primary action button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
80
68
|
primaryButton?: React.ReactNode;
|
|
81
|
-
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
82
69
|
cancelButton: React.ReactNode;
|
|
83
|
-
/** Optional action on the far left (e.g., Delete button) - NOT automatically wrapped */
|
|
84
70
|
leftAction?: React.ReactNode;
|
|
85
71
|
} | {
|
|
86
|
-
/** Primary action button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
87
72
|
primaryButton?: React.ReactNode;
|
|
88
|
-
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
89
73
|
cancelButton?: React.ReactNode;
|
|
90
|
-
/** Optional action on the far left (e.g., Delete button) - NOT automatically wrapped */
|
|
91
74
|
leftAction: React.ReactNode;
|
|
92
75
|
});
|
|
93
76
|
/**
|
|
94
|
-
* Props for
|
|
77
|
+
* Props for ModalRail component.
|
|
95
78
|
*
|
|
96
|
-
*
|
|
79
|
+
* Container for floating action buttons displayed alongside the modal.
|
|
97
80
|
*/
|
|
98
|
-
|
|
99
|
-
/**
|
|
81
|
+
type TypeModalRailProps = {
|
|
82
|
+
/** ModalAction components to display in the rail */
|
|
100
83
|
children?: React.ReactNode;
|
|
101
|
-
}
|
|
84
|
+
};
|
|
102
85
|
/**
|
|
103
|
-
* Props for
|
|
86
|
+
* Props for ModalAction component.
|
|
87
|
+
*
|
|
88
|
+
* Action buttons that appear in the floating rail.
|
|
89
|
+
* Supports two action types:
|
|
90
|
+
* - "close": Automatically closes the modal (uses Dialog.Close)
|
|
91
|
+
* - "button": Custom action with user-defined onClick handler
|
|
104
92
|
*
|
|
105
|
-
*
|
|
106
|
-
* that are announced by screen readers.
|
|
93
|
+
* **IMPORTANT**: aria-label is required for accessibility.
|
|
107
94
|
*/
|
|
108
|
-
|
|
109
|
-
/**
|
|
95
|
+
type TypeModalActionProps = ({
|
|
96
|
+
/** Action type - close triggers modal close */
|
|
97
|
+
actionType: "close";
|
|
98
|
+
/** REQUIRED: Accessible label for the button */
|
|
99
|
+
"aria-label": string;
|
|
100
|
+
/** Icon name from the Seeds icon set */
|
|
101
|
+
iconName?: TypeIconName;
|
|
102
|
+
/** Optional click handler called before closing */
|
|
103
|
+
onClick?: () => void;
|
|
104
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick">) | ({
|
|
105
|
+
/** Action type - button for custom actions (default) */
|
|
106
|
+
actionType?: "button";
|
|
107
|
+
/** REQUIRED: Accessible label for the button */
|
|
108
|
+
"aria-label": string;
|
|
109
|
+
/** Icon name from the Seeds icon set */
|
|
110
|
+
iconName?: TypeIconName;
|
|
111
|
+
/** Click handler for the button */
|
|
112
|
+
onClick?: () => void;
|
|
113
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick">);
|
|
114
|
+
/**
|
|
115
|
+
* Base common props shared by all modal variants (without close button props).
|
|
116
|
+
*/
|
|
117
|
+
type TypeModalCommonPropsBase = TypeContainerProps & Omit<React.ComponentPropsWithoutRef<"div">, keyof TypeContainerProps> & {
|
|
118
|
+
/** Modal content */
|
|
110
119
|
children: React.ReactNode;
|
|
111
|
-
/** Additional props for the Dialog.Description */
|
|
112
|
-
descriptionProps?: Omit<React.ComponentPropsWithoutRef<typeof Dialog.Description>, "asChild" | "children">;
|
|
113
|
-
}
|
|
114
|
-
/** Common props shared by all modal variants */
|
|
115
|
-
type TypeModalCommonProps = TypeContainerProps & Omit<React.ComponentPropsWithoutRef<"div">, keyof TypeContainerProps> & {
|
|
116
120
|
/** Controls whether the modal is open (controlled mode) */
|
|
117
121
|
open?: boolean;
|
|
118
122
|
/** Default open state for uncontrolled mode */
|
|
119
123
|
defaultOpen?: boolean;
|
|
120
|
-
/** body content of the modal */
|
|
121
|
-
children: React.ReactNode;
|
|
122
124
|
/** Callback when open state changes */
|
|
123
125
|
onOpenChange?: (open: boolean) => void;
|
|
124
|
-
/**
|
|
125
|
-
*
|
|
126
|
+
/**
|
|
127
|
+
* Element that triggers the modal when clicked.
|
|
128
|
+
* Can be any React element like a button, link, or custom component.
|
|
129
|
+
*/
|
|
126
130
|
modalTrigger?: React.ReactElement<any>;
|
|
127
|
-
/**
|
|
131
|
+
/** Modal description (automatically wrapped in Dialog.Description) */
|
|
128
132
|
description?: string;
|
|
129
133
|
/**
|
|
130
|
-
* Custom attributes
|
|
131
|
-
* Each key will be prepended with "data-" when rendered
|
|
134
|
+
* Custom data attributes added to the modal container.
|
|
135
|
+
* Each key will be prepended with "data-" when rendered.
|
|
132
136
|
*/
|
|
133
137
|
data?: Record<string, string | boolean | number>;
|
|
134
|
-
/**
|
|
138
|
+
/** Quick actions to render on the modal side rail */
|
|
135
139
|
actions?: TypeModalActionProps[];
|
|
136
|
-
/**
|
|
137
|
-
|
|
140
|
+
/** Controls the z-index CSS property (defaults to 6 to match Modal v1) */
|
|
141
|
+
zIndex?: number;
|
|
138
142
|
};
|
|
143
|
+
/**
|
|
144
|
+
* Common props with close button accessibility enforcement.
|
|
145
|
+
*
|
|
146
|
+
* Ensures close button always has an accessible label through either:
|
|
147
|
+
* - closeButtonAriaLabel prop (required unless closeButtonProps has aria-label)
|
|
148
|
+
* - closeButtonProps with aria-label
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* // ✅ Valid - has closeButtonAriaLabel
|
|
152
|
+
* <Modal closeButtonAriaLabel="Close dialog" />
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* // ✅ Valid - has aria-label in closeButtonProps
|
|
156
|
+
* <Modal closeButtonProps={{ "aria-label": "Close dialog", onClick: handler }} />
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* // ✅ Valid - has both (closeButtonProps aria-label takes precedence)
|
|
160
|
+
* <Modal
|
|
161
|
+
* closeButtonAriaLabel="Close"
|
|
162
|
+
* closeButtonProps={{ onClick: handler }}
|
|
163
|
+
* />
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* // ❌ TypeScript Error - missing aria-label in both places
|
|
167
|
+
* <Modal closeButtonProps={{ onClick: handler }} />
|
|
168
|
+
*/
|
|
169
|
+
type TypeModalCommonProps = (TypeModalCommonPropsBase & {
|
|
170
|
+
/**
|
|
171
|
+
* Accessible label for the close button.
|
|
172
|
+
* Required unless closeButtonProps includes aria-label.
|
|
173
|
+
*/
|
|
174
|
+
closeButtonAriaLabel: string;
|
|
175
|
+
/**
|
|
176
|
+
* Props to pass to the default floating close button.
|
|
177
|
+
* Use this for advanced customization; for simple aria-label changes, use closeButtonAriaLabel instead.
|
|
178
|
+
*/
|
|
179
|
+
closeButtonProps?: Omit<TypeModalActionProps, "actionType" | "aria-label">;
|
|
180
|
+
}) | (TypeModalCommonPropsBase & {
|
|
181
|
+
/**
|
|
182
|
+
* Accessible label for the close button.
|
|
183
|
+
* Optional when closeButtonProps includes aria-label.
|
|
184
|
+
*/
|
|
185
|
+
closeButtonAriaLabel?: string;
|
|
186
|
+
/**
|
|
187
|
+
* Props to pass to the default floating close button.
|
|
188
|
+
* Must include aria-label when closeButtonAriaLabel is not provided.
|
|
189
|
+
*/
|
|
190
|
+
closeButtonProps: Omit<TypeModalActionProps, "actionType"> & {
|
|
191
|
+
"aria-label": string;
|
|
192
|
+
};
|
|
193
|
+
});
|
|
139
194
|
/**
|
|
140
195
|
* Base props with draggable and showOverlay relationship enforced.
|
|
141
196
|
*
|
|
142
|
-
* When draggable is true, showOverlay must be false
|
|
143
|
-
*
|
|
144
|
-
* defeating the purpose of being able to drag the modal aside.
|
|
197
|
+
* When draggable is true, showOverlay must be false because the overlay
|
|
198
|
+
* would block interaction with content behind the modal.
|
|
145
199
|
*/
|
|
146
200
|
type TypeModalBaseProps = (TypeModalCommonProps & {
|
|
147
|
-
/** Enable draggable functionality */
|
|
148
201
|
draggable: true;
|
|
149
|
-
/**
|
|
150
|
-
* Whether to show the background overlay.
|
|
151
|
-
* Must be false when draggable is true to allow interaction with background content.
|
|
152
|
-
*/
|
|
153
202
|
showOverlay?: false;
|
|
154
203
|
}) | (TypeModalCommonProps & {
|
|
155
|
-
/** Enable draggable functionality */
|
|
156
204
|
draggable?: false;
|
|
157
|
-
/** Whether to show the background overlay (defaults to true) */
|
|
158
205
|
showOverlay?: boolean;
|
|
159
206
|
});
|
|
160
207
|
/**
|
|
161
208
|
* Modal props with title provided.
|
|
162
|
-
* aria-label is optional since Dialog.Title can serve as the accessible name.
|
|
163
209
|
*/
|
|
164
210
|
type TypeModalPropsWithTitle = TypeModalBaseProps & {
|
|
165
|
-
/**
|
|
211
|
+
/** Modal title (creates ModalHeader automatically) */
|
|
166
212
|
title: string;
|
|
167
|
-
/**
|
|
168
|
-
* Simplified API: Modal subtitle (creates ModalHeader automatically).
|
|
169
|
-
*
|
|
170
|
-
* This is automatically wrapped in `Dialog.Description` from Radix UI,
|
|
171
|
-
* which provides accessible description text for screen readers. The subtitle
|
|
172
|
-
* provides additional context about the modal and is announced alongside
|
|
173
|
-
* the title when the dialog opens.
|
|
174
|
-
*/
|
|
213
|
+
/** Modal subtitle (creates ModalHeader automatically) */
|
|
175
214
|
subtitle?: string;
|
|
176
|
-
/** Accessible label for the modal dialog (optional when title
|
|
215
|
+
/** Accessible label for the modal dialog (optional when title is provided) */
|
|
177
216
|
"aria-label"?: string;
|
|
178
217
|
};
|
|
179
218
|
/**
|
|
180
|
-
* Modal props with subtitle
|
|
181
|
-
* aria-label is optional since Dialog.Description can help identify the modal.
|
|
219
|
+
* Modal props with subtitle only (no title).
|
|
182
220
|
*/
|
|
183
221
|
type TypeModalPropsWithSubtitleOnly = TypeModalBaseProps & {
|
|
184
|
-
/** Simplified API: Modal title (creates ModalHeader automatically) */
|
|
185
222
|
title?: never;
|
|
186
|
-
/**
|
|
187
|
-
* Simplified API: Modal subtitle (creates ModalHeader automatically).
|
|
188
|
-
*
|
|
189
|
-
* This is automatically wrapped in `Dialog.Description` from Radix UI,
|
|
190
|
-
* which provides accessible description text for screen readers. The subtitle
|
|
191
|
-
* provides additional context about the modal and is announced alongside
|
|
192
|
-
* the title when the dialog opens.
|
|
193
|
-
*/
|
|
223
|
+
/** Modal subtitle (creates ModalHeader automatically) */
|
|
194
224
|
subtitle: string;
|
|
195
|
-
/** Accessible label for the modal dialog (optional when
|
|
225
|
+
/** Accessible label for the modal dialog (optional when subtitle is provided) */
|
|
196
226
|
"aria-label"?: string;
|
|
197
227
|
};
|
|
198
228
|
/**
|
|
199
229
|
* Modal props without title or subtitle.
|
|
200
230
|
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
231
|
+
* aria-label is optional because users can provide accessible labeling through:
|
|
232
|
+
* - ModalHeader component as children
|
|
233
|
+
* - Dialog.Title or Dialog.Description components
|
|
234
|
+
* - Custom accessible content
|
|
203
235
|
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* // ✅ Valid - provides aria-label when no header
|
|
209
|
-
* <Modal aria-label="Delete confirmation dialog">
|
|
210
|
-
* <p>Are you sure you want to delete this item?</p>
|
|
211
|
-
* </Modal>
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* // ❌ Invalid - missing required aria-label
|
|
215
|
-
* <Modal>
|
|
216
|
-
* <p>Are you sure you want to delete this item?</p>
|
|
217
|
-
* </Modal>
|
|
236
|
+
* However, for best accessibility, provide one of:
|
|
237
|
+
* - `aria-label` prop
|
|
238
|
+
* - ModalHeader component with title
|
|
239
|
+
* - Dialog.Title component in children
|
|
218
240
|
*/
|
|
219
241
|
type TypeModalPropsWithoutHeader = TypeModalBaseProps & {
|
|
220
|
-
/** Simplified API: Modal title (creates ModalHeader automatically) - not allowed when no header */
|
|
221
242
|
title?: never;
|
|
222
|
-
/** Simplified API: Modal subtitle (creates ModalHeader automatically) - not allowed when no header */
|
|
223
243
|
subtitle?: never;
|
|
224
244
|
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* Accessible label for the modal dialog. This is required for accessibility
|
|
228
|
-
* when the modal has no visible header. Screen readers use this to announce
|
|
229
|
-
* what the modal is about.
|
|
230
|
-
*
|
|
231
|
-
* **Error**: If you see a TypeScript error saying this property is missing,
|
|
232
|
-
* it means you need to either:
|
|
233
|
-
* 1. Provide `aria-label` (required when no header), OR
|
|
234
|
-
* 2. Provide `title` or `subtitle` (which makes aria-label optional)
|
|
235
|
-
*
|
|
236
|
-
* If you have a title or subtitle, this prop is optional.
|
|
245
|
+
* Accessible label for the modal dialog.
|
|
246
|
+
* Optional, but recommended when no title/subtitle props are provided.
|
|
237
247
|
*/
|
|
238
|
-
"aria-label"
|
|
248
|
+
"aria-label"?: string;
|
|
239
249
|
};
|
|
240
250
|
/**
|
|
241
|
-
* Modal component props
|
|
242
|
-
*
|
|
243
|
-
* **Accessibility Requirements:**
|
|
244
|
-
* - ✅ **With header** (title or subtitle provided): `aria-label` is optional
|
|
245
|
-
* - ❌ **Without header** (no title, no subtitle): `aria-label` is **REQUIRED**
|
|
251
|
+
* Modal component props.
|
|
246
252
|
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
253
|
+
* **Accessibility Recommendations:**
|
|
254
|
+
* - With title/subtitle props: aria-label is optional (automatically accessible)
|
|
255
|
+
* - With ModalHeader as children: aria-label is optional (header provides labeling)
|
|
256
|
+
* - Without header props or components: aria-label is optional but strongly recommended
|
|
249
257
|
*
|
|
250
258
|
* @example
|
|
251
|
-
* //
|
|
259
|
+
* // With title prop
|
|
252
260
|
* <Modal title="Delete Item" />
|
|
253
261
|
*
|
|
254
262
|
* @example
|
|
255
|
-
* //
|
|
256
|
-
* <Modal
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* // ✅ Valid - no header, aria-label provided
|
|
260
|
-
* <Modal aria-label="Delete confirmation dialog" />
|
|
263
|
+
* // With ModalHeader as children
|
|
264
|
+
* <Modal>
|
|
265
|
+
* <ModalHeader title="Delete Item" />
|
|
266
|
+
* </Modal>
|
|
261
267
|
*
|
|
262
268
|
* @example
|
|
263
|
-
* //
|
|
264
|
-
* <Modal
|
|
269
|
+
* // With aria-label
|
|
270
|
+
* <Modal aria-label="Delete confirmation">
|
|
271
|
+
* <ModalBody>Are you sure?</ModalBody>
|
|
272
|
+
* </Modal>
|
|
265
273
|
*/
|
|
266
274
|
type TypeModalProps = TypeModalPropsWithTitle | TypeModalPropsWithSubtitleOnly | TypeModalPropsWithoutHeader;
|
|
267
|
-
/**
|
|
268
|
-
* Props for ModalRail component.
|
|
269
|
-
*
|
|
270
|
-
* Container for floating action buttons displayed alongside the modal.
|
|
271
|
-
*/
|
|
272
|
-
type TypeModalRailProps = {
|
|
273
|
-
/** ModalAction components to display in the rail */
|
|
274
|
-
children?: React.ReactNode;
|
|
275
|
-
};
|
|
276
|
-
/**
|
|
277
|
-
* Base props for modal action buttons.
|
|
278
|
-
*
|
|
279
|
-
* Extends standard button HTML attributes with modal-specific properties.
|
|
280
|
-
*/
|
|
281
|
-
type ModalActionBase = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> & {
|
|
282
|
-
/** Icon name from the Seeds icon set */
|
|
283
|
-
iconName?: TypeIconName;
|
|
284
|
-
/** Optional click handler; ignored for type "close" */
|
|
285
|
-
onClick?: () => void;
|
|
286
|
-
/** Accessible name for the action button */
|
|
287
|
-
"aria-label": string;
|
|
288
|
-
};
|
|
289
|
-
/**
|
|
290
|
-
* Props for ModalAction component.
|
|
291
|
-
*
|
|
292
|
-
* Discriminated union supporting two action types:
|
|
293
|
-
* - "close": Automatically closes the modal when clicked (uses Dialog.Close)
|
|
294
|
-
* - "button": Custom action with user-defined onClick handler
|
|
295
|
-
*/
|
|
296
|
-
type TypeModalActionProps = (ModalActionBase & {
|
|
297
|
-
actionType: "close";
|
|
298
|
-
}) | (ModalActionBase & {
|
|
299
|
-
actionType?: "button";
|
|
300
|
-
});
|
|
301
275
|
|
|
302
276
|
/**
|
|
303
277
|
* Accessible modal dialog component built on Radix UI Dialog primitives.
|
|
@@ -179,6 +179,7 @@ var StyledMotionWrapper = styled(motion.div)`
|
|
|
179
179
|
top: ${(props) => props.$isMobile ? "auto" : "50%"};
|
|
180
180
|
left: 50%;
|
|
181
181
|
bottom: ${(props) => props.$isMobile ? 0 : "auto"};
|
|
182
|
+
z-index: ${(props) => props.$zIndex ? props.$zIndex + 1 : 7};
|
|
182
183
|
`;
|
|
183
184
|
var StyledContent = styled.div.withConfig({
|
|
184
185
|
shouldForwardProp: (prop) => !["isDragging", "draggable"].includes(prop)
|
|
@@ -238,6 +239,7 @@ var StaticModalContent = ({
|
|
|
238
239
|
children,
|
|
239
240
|
label,
|
|
240
241
|
dataAttributes,
|
|
242
|
+
zIndex,
|
|
241
243
|
rest
|
|
242
244
|
}) => {
|
|
243
245
|
const isMobile = useIsMobile();
|
|
@@ -246,11 +248,21 @@ var StaticModalContent = ({
|
|
|
246
248
|
StyledMotionWrapper,
|
|
247
249
|
{
|
|
248
250
|
$isMobile: isMobile,
|
|
251
|
+
$zIndex: zIndex,
|
|
249
252
|
variants: contentVariants,
|
|
250
253
|
initial: "initial",
|
|
251
254
|
animate: "animate",
|
|
252
255
|
exit: "exit",
|
|
253
|
-
children: /* @__PURE__ */ jsx(
|
|
256
|
+
children: /* @__PURE__ */ jsx(
|
|
257
|
+
StyledContent,
|
|
258
|
+
{
|
|
259
|
+
"data-slot": "modal-content",
|
|
260
|
+
draggable: false,
|
|
261
|
+
...dataAttributes,
|
|
262
|
+
...rest,
|
|
263
|
+
children
|
|
264
|
+
}
|
|
265
|
+
)
|
|
254
266
|
}
|
|
255
267
|
) }) });
|
|
256
268
|
};
|
|
@@ -258,6 +270,7 @@ var DraggableModalContent = ({
|
|
|
258
270
|
children,
|
|
259
271
|
label,
|
|
260
272
|
dataAttributes,
|
|
273
|
+
zIndex,
|
|
261
274
|
rest
|
|
262
275
|
}) => {
|
|
263
276
|
const [position, setPosition] = React2.useState({ x: 0, y: 0 });
|
|
@@ -332,6 +345,7 @@ var DraggableModalContent = ({
|
|
|
332
345
|
StyledMotionWrapper,
|
|
333
346
|
{
|
|
334
347
|
$isMobile: isMobile,
|
|
348
|
+
$zIndex: zIndex,
|
|
335
349
|
variants: contentVariants,
|
|
336
350
|
initial: "initial",
|
|
337
351
|
animate: "animate",
|
|
@@ -346,6 +360,7 @@ var DraggableModalContent = ({
|
|
|
346
360
|
children: /* @__PURE__ */ jsx(
|
|
347
361
|
StyledContent,
|
|
348
362
|
{
|
|
363
|
+
"data-slot": "modal-content",
|
|
349
364
|
ref: contentRef,
|
|
350
365
|
draggable: true,
|
|
351
366
|
isDragging,
|
|
@@ -397,6 +412,8 @@ var ModalHeader = (props) => {
|
|
|
397
412
|
return /* @__PURE__ */ jsx2(
|
|
398
413
|
ModalCustomHeader,
|
|
399
414
|
{
|
|
415
|
+
"data-slot": "modal-header",
|
|
416
|
+
"data-qa-modal-header": true,
|
|
400
417
|
...rest,
|
|
401
418
|
onMouseDown: isDraggable ? dragContext?.onHeaderMouseDown : void 0,
|
|
402
419
|
draggable: isDraggable,
|
|
@@ -422,7 +439,7 @@ import {
|
|
|
422
439
|
} from "@sproutsocial/seeds-react-system-props";
|
|
423
440
|
|
|
424
441
|
// src/v2/components/ModalCloseWrapper.tsx
|
|
425
|
-
import "react";
|
|
442
|
+
import * as React4 from "react";
|
|
426
443
|
import * as Dialog3 from "@radix-ui/react-dialog";
|
|
427
444
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
428
445
|
var ModalCloseWrapper = (props) => {
|
|
@@ -430,7 +447,11 @@ var ModalCloseWrapper = (props) => {
|
|
|
430
447
|
const handleClick = (e) => {
|
|
431
448
|
onClick?.(e);
|
|
432
449
|
};
|
|
433
|
-
return /* @__PURE__ */ jsx3(Dialog3.Close, { asChild, onClick: handleClick, ...rest, children
|
|
450
|
+
return /* @__PURE__ */ jsx3(Dialog3.Close, { asChild, onClick: handleClick, ...rest, children: React4.isValidElement(children) ? React4.cloneElement(children, {
|
|
451
|
+
"data-slot": "modal-close-wrapper",
|
|
452
|
+
"data-qa-modal-close-wrapper": "",
|
|
453
|
+
...children.props || {}
|
|
454
|
+
}) : children });
|
|
434
455
|
};
|
|
435
456
|
ModalCloseWrapper.displayName = "ModalCloseWrapper";
|
|
436
457
|
|
|
@@ -465,7 +486,7 @@ var ModalFooter = (props) => {
|
|
|
465
486
|
if (!cancelButton && !primaryButton && !leftAction) {
|
|
466
487
|
return null;
|
|
467
488
|
}
|
|
468
|
-
return /* @__PURE__ */ jsxs2(ModalCustomFooter, { ...rest, children: [
|
|
489
|
+
return /* @__PURE__ */ jsxs2(ModalCustomFooter, { "data-slot": "modal-footer", "data-qa-modal-footer": true, ...rest, children: [
|
|
469
490
|
leftAction ? leftAction : null,
|
|
470
491
|
/* @__PURE__ */ jsxs2(Box2, { display: "flex", gap: 300, marginLeft: "auto", children: [
|
|
471
492
|
cancelButton && /* @__PURE__ */ jsx4(ModalCloseWrapper, { children: cancelButton }),
|
|
@@ -505,7 +526,16 @@ var StyledModalBody = styled4(Box3)`
|
|
|
505
526
|
StyledModalBody.displayName = "ModalBody";
|
|
506
527
|
var ModalBody = React6.forwardRef(
|
|
507
528
|
({ children, ...rest }, ref) => {
|
|
508
|
-
return /* @__PURE__ */ jsx5(
|
|
529
|
+
return /* @__PURE__ */ jsx5(
|
|
530
|
+
StyledModalBody,
|
|
531
|
+
{
|
|
532
|
+
"data-slot": "modal-body",
|
|
533
|
+
"data-qa-modal-body": true,
|
|
534
|
+
ref,
|
|
535
|
+
...rest,
|
|
536
|
+
children
|
|
537
|
+
}
|
|
538
|
+
);
|
|
509
539
|
}
|
|
510
540
|
);
|
|
511
541
|
ModalBody.displayName = "ModalBody";
|
|
@@ -516,7 +546,16 @@ import * as Dialog4 from "@radix-ui/react-dialog";
|
|
|
516
546
|
import Box4 from "@sproutsocial/seeds-react-box";
|
|
517
547
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
518
548
|
var ModalDescription = React7.forwardRef(({ children, descriptionProps = {}, ...rest }, ref) => {
|
|
519
|
-
return /* @__PURE__ */ jsx6(Dialog4.Description, { asChild: true, ...descriptionProps, children: /* @__PURE__ */ jsx6(
|
|
549
|
+
return /* @__PURE__ */ jsx6(Dialog4.Description, { asChild: true, ...descriptionProps, children: /* @__PURE__ */ jsx6(
|
|
550
|
+
Box4,
|
|
551
|
+
{
|
|
552
|
+
"data-slot": "modal-description",
|
|
553
|
+
"data-qa-modal-description": true,
|
|
554
|
+
ref,
|
|
555
|
+
...rest,
|
|
556
|
+
children
|
|
557
|
+
}
|
|
558
|
+
) });
|
|
520
559
|
});
|
|
521
560
|
ModalDescription.displayName = "ModalDescription";
|
|
522
561
|
|
|
@@ -1188,6 +1227,9 @@ var ModalAction = ({
|
|
|
1188
1227
|
const button = /* @__PURE__ */ jsx8(
|
|
1189
1228
|
RailButton,
|
|
1190
1229
|
{
|
|
1230
|
+
"data-slot": "modal-action",
|
|
1231
|
+
"data-qa-modal-action": true,
|
|
1232
|
+
"data-qa-modal-action-type": actionType || "button",
|
|
1191
1233
|
"aria-label": ariaLabel,
|
|
1192
1234
|
title: ariaLabel,
|
|
1193
1235
|
disabled: disabled2,
|
|
@@ -1219,6 +1261,7 @@ var StyledMotionOverlay = styled7(motion2.div)`
|
|
|
1219
1261
|
left: 0px;
|
|
1220
1262
|
right: 0px;
|
|
1221
1263
|
bottom: 0px;
|
|
1264
|
+
z-index: ${(props) => props.$zIndex ?? 6};
|
|
1222
1265
|
`;
|
|
1223
1266
|
var StyledOverlay = styled7.div.withConfig({
|
|
1224
1267
|
shouldForwardProp: (prop) => !["allowInteraction"].includes(prop)
|
|
@@ -1257,6 +1300,8 @@ var Modal = (props) => {
|
|
|
1257
1300
|
showOverlay = true,
|
|
1258
1301
|
actions,
|
|
1259
1302
|
closeButtonAriaLabel = "Close",
|
|
1303
|
+
closeButtonProps,
|
|
1304
|
+
zIndex = 6,
|
|
1260
1305
|
...rest
|
|
1261
1306
|
} = props;
|
|
1262
1307
|
const [isOpen, setIsOpen] = React11.useState(defaultOpen ?? false);
|
|
@@ -1295,11 +1340,19 @@ var Modal = (props) => {
|
|
|
1295
1340
|
showOverlay && /* @__PURE__ */ jsx9(Dialog6.Overlay, { asChild: true, children: /* @__PURE__ */ jsx9(
|
|
1296
1341
|
StyledMotionOverlay,
|
|
1297
1342
|
{
|
|
1343
|
+
$zIndex: zIndex,
|
|
1298
1344
|
variants: overlayVariants,
|
|
1299
1345
|
initial: "initial",
|
|
1300
1346
|
animate: "animate",
|
|
1301
1347
|
exit: "exit",
|
|
1302
|
-
children: /* @__PURE__ */ jsx9(
|
|
1348
|
+
children: /* @__PURE__ */ jsx9(
|
|
1349
|
+
StyledOverlay,
|
|
1350
|
+
{
|
|
1351
|
+
"data-slot": "modal-overlay",
|
|
1352
|
+
"data-qa-modal-overlay": true,
|
|
1353
|
+
allowInteraction: draggable
|
|
1354
|
+
}
|
|
1355
|
+
)
|
|
1303
1356
|
}
|
|
1304
1357
|
) }),
|
|
1305
1358
|
/* @__PURE__ */ jsxs3(
|
|
@@ -1308,6 +1361,7 @@ var Modal = (props) => {
|
|
|
1308
1361
|
label,
|
|
1309
1362
|
dataAttributes,
|
|
1310
1363
|
draggable,
|
|
1364
|
+
zIndex,
|
|
1311
1365
|
rest,
|
|
1312
1366
|
children: [
|
|
1313
1367
|
/* @__PURE__ */ jsxs3(ModalRail, { children: [
|
|
@@ -1315,8 +1369,9 @@ var Modal = (props) => {
|
|
|
1315
1369
|
ModalAction,
|
|
1316
1370
|
{
|
|
1317
1371
|
actionType: "close",
|
|
1318
|
-
"
|
|
1319
|
-
|
|
1372
|
+
iconName: "x-outline",
|
|
1373
|
+
...closeButtonProps,
|
|
1374
|
+
"aria-label": closeButtonProps?.["aria-label"] ?? closeButtonAriaLabel
|
|
1320
1375
|
}
|
|
1321
1376
|
),
|
|
1322
1377
|
actions?.map((action, idx) => /* @__PURE__ */ jsx9(ModalAction, { ...action }, idx))
|
|
@@ -1350,4 +1405,4 @@ export {
|
|
|
1350
1405
|
ModalAction,
|
|
1351
1406
|
Modal_default
|
|
1352
1407
|
};
|
|
1353
|
-
//# sourceMappingURL=chunk-
|
|
1408
|
+
//# sourceMappingURL=chunk-52SXX6AG.js.map
|