@sproutsocial/seeds-react-modal 1.1.1 → 2.0.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 +23 -23
- package/CHANGELOG.md +175 -0
- package/dist/ModalAction-BB7qJtQj.d.mts +445 -0
- package/dist/ModalAction-BB7qJtQj.d.ts +445 -0
- package/dist/esm/chunk-ETVICNHP.js +1353 -0
- package/dist/esm/chunk-ETVICNHP.js.map +1 -0
- package/dist/esm/index.js +11 -11
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v2/index.js +12 -20
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1154 -546
- package/dist/index.js.map +1 -1
- package/dist/v2/index.d.mts +4 -11
- package/dist/v2/index.d.ts +4 -11
- package/dist/v2/index.js +1152 -545
- package/dist/v2/index.js.map +1 -1
- package/package.json +8 -7
- package/src/index.ts +11 -12
- package/src/shared/constants.ts +11 -7
- package/src/v2/Modal.tsx +169 -0
- package/src/v2/ModalTypes.ts +343 -0
- package/src/v2/ModalV2.stories.tsx +413 -128
- package/src/v2/MotionConfig.ts +185 -0
- package/src/v2/components/ModalAction.tsx +94 -0
- package/src/v2/components/ModalBody.tsx +54 -0
- package/src/v2/components/ModalCloseWrapper.tsx +35 -0
- package/src/v2/components/ModalContent.tsx +288 -11
- package/src/v2/components/ModalDescription.tsx +14 -2
- package/src/v2/components/ModalFooter.tsx +94 -13
- package/src/v2/components/ModalHeader.tsx +77 -34
- package/src/v2/components/ModalOverlay.tsx +52 -0
- package/src/v2/components/ModalRail.tsx +35 -99
- package/src/v2/components/index.ts +11 -7
- package/src/v2/index.ts +13 -16
- package/dist/ModalRail-5PeilhW7.d.mts +0 -186
- package/dist/ModalRail-5PeilhW7.d.ts +0 -186
- package/dist/esm/chunk-4ITF4DBY.js +0 -717
- package/dist/esm/chunk-4ITF4DBY.js.map +0 -1
- package/src/v2/ModalV2.tsx +0 -388
- package/src/v2/ModalV2Styles.tsx +0 -180
- package/src/v2/ModalV2Types.ts +0 -154
- package/src/v2/components/ModalClose.tsx +0 -29
- package/src/v2/components/ModalCloseButton.tsx +0 -100
- package/src/v2/components/ModalTrigger.tsx +0 -39
package/.turbo/turbo-build.log
CHANGED
|
@@ -8,34 +8,34 @@ $ tsup --dts
|
|
|
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[
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m58.46 KB[39m
|
|
12
12
|
[32mCJS[39m [1mdist/v1/index.js [22m[32m9.86 KB[39m
|
|
13
|
-
[32mCJS[39m [1mdist/v2/index.js [22m[
|
|
14
|
-
[32mCJS[39m [1mdist/index.js.map [22m[
|
|
13
|
+
[32mCJS[39m [1mdist/v2/index.js [22m[32m50.48 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m201.74 KB[39m
|
|
15
15
|
[32mCJS[39m [1mdist/v1/index.js.map [22m[32m13.03 KB[39m
|
|
16
|
-
[32mCJS[39m [1mdist/v2/index.js.map [22m[
|
|
17
|
-
[32mCJS[39m ⚡️ Build success in
|
|
18
|
-
[32mESM[39m [1mdist/esm/index.js [22m[32m567.00 B[39m
|
|
16
|
+
[32mCJS[39m [1mdist/v2/index.js.map [22m[32m188.43 KB[39m
|
|
17
|
+
[32mCJS[39m ⚡️ Build success in 345ms
|
|
19
18
|
[32mESM[39m [1mdist/esm/v1/index.js [22m[32m165.00 B[39m
|
|
20
|
-
[32mESM[39m [1mdist/esm/v2/index.js [22m[
|
|
19
|
+
[32mESM[39m [1mdist/esm/v2/index.js [22m[32m596.00 B[39m
|
|
20
|
+
[32mESM[39m [1mdist/esm/index.js [22m[32m583.00 B[39m
|
|
21
21
|
[32mESM[39m [1mdist/esm/chunk-IYDY4OPB.js [22m[32m7.12 KB[39m
|
|
22
|
-
[32mESM[39m [1mdist/esm/chunk-
|
|
23
|
-
[32mESM[39m [1mdist/esm/index.js.map [22m[32m963.00 B[39m
|
|
22
|
+
[32mESM[39m [1mdist/esm/chunk-ETVICNHP.js [22m[32m45.64 KB[39m
|
|
24
23
|
[32mESM[39m [1mdist/esm/v1/index.js.map [22m[32m71.00 B[39m
|
|
25
24
|
[32mESM[39m [1mdist/esm/v2/index.js.map [22m[32m71.00 B[39m
|
|
25
|
+
[32mESM[39m [1mdist/esm/index.js.map [22m[32m1.05 KB[39m
|
|
26
26
|
[32mESM[39m [1mdist/esm/chunk-IYDY4OPB.js.map [22m[32m12.85 KB[39m
|
|
27
|
-
[32mESM[39m [1mdist/esm/chunk-
|
|
28
|
-
[32mESM[39m ⚡️ Build success in
|
|
27
|
+
[32mESM[39m [1mdist/esm/chunk-ETVICNHP.js.map [22m[32m187.52 KB[39m
|
|
28
|
+
[32mESM[39m ⚡️ Build success in 354ms
|
|
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-ki8oiGbC.d.ts
|
|
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-ki8oiGbC.d.mts
|
|
40
|
-
[32mDTS[39m [1mdist/
|
|
41
|
-
Done in
|
|
30
|
+
[32mDTS[39m ⚡️ Build success in 31689ms
|
|
31
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m975.00 B[39m
|
|
32
|
+
[32mDTS[39m [1mdist/v1/index.d.ts [22m[32m413.00 B[39m
|
|
33
|
+
[32mDTS[39m [1mdist/v2/index.d.ts [22m[32m1021.00 B[39m
|
|
34
|
+
[32mDTS[39m [1mdist/Modal-ki8oiGbC.d.ts [22m[32m2.52 KB[39m
|
|
35
|
+
[32mDTS[39m [1mdist/ModalAction-BB7qJtQj.d.ts [22m[32m17.39 KB[39m
|
|
36
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m978.00 B[39m
|
|
37
|
+
[32mDTS[39m [1mdist/v1/index.d.mts [22m[32m415.00 B[39m
|
|
38
|
+
[32mDTS[39m [1mdist/v2/index.d.mts [22m[32m1022.00 B[39m
|
|
39
|
+
[32mDTS[39m [1mdist/Modal-ki8oiGbC.d.mts [22m[32m2.52 KB[39m
|
|
40
|
+
[32mDTS[39m [1mdist/ModalAction-BB7qJtQj.d.mts [22m[32m17.39 KB[39m
|
|
41
|
+
Done in 34.53s.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,180 @@
|
|
|
1
1
|
# @sproutsocial/seeds-react-modal
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- b1c3b44: ## Modal V2 Complete Rewrite
|
|
8
|
+
|
|
9
|
+
Complete architectural overhaul of Modal V2 with improved API, accessibility, animations, and mobile responsiveness.
|
|
10
|
+
|
|
11
|
+
### Breaking Changes
|
|
12
|
+
|
|
13
|
+
#### Component Name Changes
|
|
14
|
+
|
|
15
|
+
- **Root component**: `ModalV2` renamed to `Modal`
|
|
16
|
+
- **Removed components**: `ModalClose`, `ModalCloseButton`, `ModalTrigger`
|
|
17
|
+
- **New components**: `ModalBody`, `ModalCloseWrapper`, `ModalAction`, `ModalCustomHeader`, `ModalCustomFooter`
|
|
18
|
+
|
|
19
|
+
#### Removed Exports
|
|
20
|
+
|
|
21
|
+
- **Removed z-index constants**: `DEFAULT_MODAL_Z_INDEX`, `DEFAULT_OVERLAY_Z_INDEX_OFFSET`, `MODAL_PRIORITY_Z_INDEX`
|
|
22
|
+
- These are no longer needed as Radix UI Dialog handles stacking automatically via portal DOM order
|
|
23
|
+
- If you were using these constants, remove them from your code
|
|
24
|
+
- Stacking is now managed by the order modals are opened (last opened appears on top)
|
|
25
|
+
|
|
26
|
+
#### API Changes
|
|
27
|
+
|
|
28
|
+
- **Modal root**: Now built on Radix UI Dialog primitives with simplified props
|
|
29
|
+
|
|
30
|
+
- Removed children-based header composition
|
|
31
|
+
- Added slot-based API: `title`, `subtitle`, `description` props for common use cases
|
|
32
|
+
- Added `modalTrigger` prop for trigger element
|
|
33
|
+
- Added `draggable` prop for draggable modals
|
|
34
|
+
- Added `showOverlay` prop (defaults to `true`)
|
|
35
|
+
- Added `actions` prop for floating action rail
|
|
36
|
+
- **Removed `priority` prop**: z-index management is no longer needed
|
|
37
|
+
- Added `closeButtonAriaLabel` prop (defaults to "Close")
|
|
38
|
+
|
|
39
|
+
- **ModalHeader**: Converted to slot-based API
|
|
40
|
+
|
|
41
|
+
- Now only supports `title` and `subtitle` props
|
|
42
|
+
- Removed `children` prop
|
|
43
|
+
- For custom headers, use new `ModalCustomHeader` component
|
|
44
|
+
- Automatically becomes draggable handle when `<Modal draggable={true} />`
|
|
45
|
+
|
|
46
|
+
- **ModalFooter**: Converted to slot-based API with automatic button wrapping
|
|
47
|
+
|
|
48
|
+
- `primaryButton`: Main action (auto-closes modal)
|
|
49
|
+
- `cancelButton`: Secondary action (auto-closes modal)
|
|
50
|
+
- `leftAction`: Optional left-aligned action (no auto-close, for destructive actions)
|
|
51
|
+
- For custom footers, use new `ModalCustomFooter` component
|
|
52
|
+
- At least one action prop is required (TypeScript enforced)
|
|
53
|
+
|
|
54
|
+
- **ModalBody**: New component for modal content area
|
|
55
|
+
- Replaces direct content in Modal children
|
|
56
|
+
- Provides proper scrolling behavior and padding
|
|
57
|
+
|
|
58
|
+
#### Type Changes
|
|
59
|
+
|
|
60
|
+
- All types renamed from `TypeModalV2*` to `TypeModal*`
|
|
61
|
+
- `TypeModalV2Props` → `TypeModalProps`
|
|
62
|
+
- `TypeModalV2HeaderProps` → `TypeModalHeaderProps`
|
|
63
|
+
- `TypeModalV2FooterProps` → `TypeModalFooterProps`
|
|
64
|
+
- New types: `TypeModalBodyProps`, `TypeModalDescriptionProps`, `TypeModalRailProps`, `TypeModalActionProps`
|
|
65
|
+
|
|
66
|
+
### New Features
|
|
67
|
+
|
|
68
|
+
#### Draggable Modals
|
|
69
|
+
|
|
70
|
+
- Enable with `draggable={true}` prop
|
|
71
|
+
- Drag from header to reposition modal
|
|
72
|
+
- Constrained to viewport boundaries
|
|
73
|
+
- TypeScript enforces `showOverlay={false}` when draggable (overlay would block interaction)
|
|
74
|
+
- Automatically sets Radix `modal={false}` to allow background interaction
|
|
75
|
+
|
|
76
|
+
#### Floating Action Rail
|
|
77
|
+
|
|
78
|
+
- Always-visible floating close button
|
|
79
|
+
- Support for additional custom actions via `actions` prop
|
|
80
|
+
- Positioned on right side (desktop) or above modal (mobile)
|
|
81
|
+
- Actions defined with `iconName`, `onClick`, `aria-label`
|
|
82
|
+
|
|
83
|
+
#### Mobile Responsiveness (≤780px)
|
|
84
|
+
|
|
85
|
+
- Bottom sheet layout anchored to screen bottom
|
|
86
|
+
- Rounded top corners, flat bottom corners
|
|
87
|
+
- Rail positioned above modal
|
|
88
|
+
- Content height hugs content with scrolling
|
|
89
|
+
- Smooth slide-up animation
|
|
90
|
+
|
|
91
|
+
#### Animation System
|
|
92
|
+
|
|
93
|
+
- Built with Framer Motion `AnimatePresence`
|
|
94
|
+
- Smooth fade + scale animation (desktop)
|
|
95
|
+
- Slide-up animation (mobile)
|
|
96
|
+
- Separate animations for overlay and content
|
|
97
|
+
- Draggable modals use opacity-only animation (no transform conflict)
|
|
98
|
+
|
|
99
|
+
#### Accessibility Improvements
|
|
100
|
+
|
|
101
|
+
- Built on Radix UI Dialog primitives
|
|
102
|
+
- Automatic ARIA attributes and focus management
|
|
103
|
+
- ESC key and outside click to close (when not draggable)
|
|
104
|
+
- Required `aria-label` when no title/subtitle provided (TypeScript enforced)
|
|
105
|
+
- Subtitle automatically wrapped in `Dialog.Description`
|
|
106
|
+
|
|
107
|
+
### Component Details
|
|
108
|
+
|
|
109
|
+
#### ModalCloseWrapper
|
|
110
|
+
|
|
111
|
+
New utility component that wraps any element and makes it close the modal when clicked. Used internally by `ModalFooter` for automatic close behavior.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<ModalCloseWrapper>
|
|
115
|
+
<Button>Close</Button>
|
|
116
|
+
</ModalCloseWrapper>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### ModalAction
|
|
120
|
+
|
|
121
|
+
Action button component for the floating rail. Supports two types:
|
|
122
|
+
|
|
123
|
+
- `actionType="close"`: Closes modal on click
|
|
124
|
+
- `actionType="button"`: Custom action with onClick handler
|
|
125
|
+
|
|
126
|
+
#### ModalCustomHeader & ModalCustomFooter
|
|
127
|
+
|
|
128
|
+
Base styled components for custom header/footer layouts when slot-based API isn't sufficient. Provides styling and system props support.
|
|
129
|
+
|
|
130
|
+
### Technical Improvements
|
|
131
|
+
|
|
132
|
+
#### Improved Stacking Behavior
|
|
133
|
+
|
|
134
|
+
Modal V2 no longer uses explicit z-index values, relying instead on Radix UI Dialog's portal-based stacking:
|
|
135
|
+
|
|
136
|
+
- **Automatic stacking**: Modal elements are portaled to `<body>` and stack naturally via DOM order
|
|
137
|
+
- **Simpler integration**: No z-index conflicts with other portal-based components (tooltips, popovers, etc.)
|
|
138
|
+
- **Better composability**: Works seamlessly with new popout components and other overlays
|
|
139
|
+
- **Predictable behavior**: Last opened modal always appears on top, regardless of configuration
|
|
140
|
+
|
|
141
|
+
**Migration Note**: If you were using the `priority` prop to control modal stacking, remove it. Modals now stack in the order they're opened, which provides more predictable and intuitive behavior.
|
|
142
|
+
|
|
143
|
+
#### Performance Optimizations
|
|
144
|
+
|
|
145
|
+
- **Split rendering paths**: Non-draggable modals now use lightweight `StaticModalContent` component, avoiding unnecessary drag logic, event listeners, and boundary calculations
|
|
146
|
+
- **Conditional component loading**: Draggable functionality only loads when `draggable={true}`, reducing runtime overhead for 99% of use cases
|
|
147
|
+
- **Optimized re-renders**: Removed drag context overhead from static modals entirely
|
|
148
|
+
|
|
149
|
+
#### Type Safety Enhancements
|
|
150
|
+
|
|
151
|
+
- **Discriminated unions for prop relationships**: TypeScript enforces `showOverlay={false}` when `draggable={true}`, preventing invalid configurations at compile time
|
|
152
|
+
- **Required footer actions**: Footer type system ensures at least one action button is provided, eliminating empty footer states
|
|
153
|
+
- **Removed ambiguous APIs**: Eliminated `children` override props from `ModalHeader` and `ModalFooter`, guiding developers toward the slot-based API while providing explicit `ModalCustomHeader`/`ModalCustomFooter` components for advanced use cases
|
|
154
|
+
|
|
155
|
+
#### Code Quality
|
|
156
|
+
|
|
157
|
+
- Removed redundant `width` styled-system import (already included in LAYOUT)
|
|
158
|
+
- Added POSITION system props to ModalOverlay for better positioning control
|
|
159
|
+
- Created `MotionConfig.ts` for centralized animation variants
|
|
160
|
+
- Split styles into component-specific files for better organization
|
|
161
|
+
- Consistent component naming and structure
|
|
162
|
+
- Updated Storybook stories to use semantic theme tokens instead of raw color scale values
|
|
163
|
+
|
|
164
|
+
### Racine Updates
|
|
165
|
+
|
|
166
|
+
- Export name corrected: `Modal` instead of `ModalV2`
|
|
167
|
+
- All type exports updated to match new names
|
|
168
|
+
- Removed z-index constant exports to match Modal V2 changes
|
|
169
|
+
|
|
170
|
+
### Patch Changes
|
|
171
|
+
|
|
172
|
+
- Updated dependencies [b1c3b44]
|
|
173
|
+
- @sproutsocial/seeds-react-theme@3.1.1
|
|
174
|
+
- @sproutsocial/seeds-react-box@1.1.5
|
|
175
|
+
- @sproutsocial/seeds-react-icon@1.1.5
|
|
176
|
+
- @sproutsocial/seeds-react-button@1.3.1
|
|
177
|
+
|
|
3
178
|
## 1.1.1
|
|
4
179
|
|
|
5
180
|
### Patch Changes
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as styled_components from 'styled-components';
|
|
3
|
+
import * as _sproutsocial_seeds_react_box from '@sproutsocial/seeds-react-box';
|
|
4
|
+
import { TypeContainerProps, TypeBoxProps } from '@sproutsocial/seeds-react-box';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
7
|
+
import { TypeIconName } from '@sproutsocial/seeds-react-icon';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Props for ModalHeader component.
|
|
11
|
+
*
|
|
12
|
+
* Renders the modal's header with title and optional subtitle. Supports draggable functionality
|
|
13
|
+
* when the modal has draggable enabled.
|
|
14
|
+
*
|
|
15
|
+
* Note: This component only supports slots (title/subtitle props). For custom headers,
|
|
16
|
+
* use ModalCustomHeader instead.
|
|
17
|
+
*/
|
|
18
|
+
interface TypeModalHeaderProps extends TypeBoxProps {
|
|
19
|
+
/** Modal title text displayed as a headline */
|
|
20
|
+
title?: string;
|
|
21
|
+
/**
|
|
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).
|
|
29
|
+
*/
|
|
30
|
+
subtitle?: string;
|
|
31
|
+
/** Additional props for the Dialog.Title when title is provided */
|
|
32
|
+
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
|
+
*/
|
|
41
|
+
subtitleProps?: Omit<React.ComponentPropsWithoutRef<typeof Dialog.Description>, "asChild" | "children">;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Props for ModalFooter component.
|
|
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.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* // ✅ Valid - has primary button
|
|
54
|
+
* <ModalFooter primaryButton={<Button>Save</Button>} />
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // ✅ Valid - has cancel and primary
|
|
58
|
+
* <ModalFooter
|
|
59
|
+
* cancelButton={<Button>Cancel</Button>}
|
|
60
|
+
* primaryButton={<Button>Save</Button>}
|
|
61
|
+
* />
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // ✅ Valid - left action only
|
|
65
|
+
* <ModalFooter leftAction={<Button>Delete</Button>} />
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // ❌ TypeScript Error - no actions provided
|
|
69
|
+
* <ModalFooter />
|
|
70
|
+
*/
|
|
71
|
+
type TypeModalFooterProps = TypeBoxProps & ({
|
|
72
|
+
/** Primary action button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
73
|
+
primaryButton: React.ReactNode;
|
|
74
|
+
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
75
|
+
cancelButton?: React.ReactNode;
|
|
76
|
+
/** Optional action on the far left (e.g., Delete button) - NOT automatically wrapped */
|
|
77
|
+
leftAction?: React.ReactNode;
|
|
78
|
+
} | {
|
|
79
|
+
/** Primary action button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
80
|
+
primaryButton?: React.ReactNode;
|
|
81
|
+
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
82
|
+
cancelButton: React.ReactNode;
|
|
83
|
+
/** Optional action on the far left (e.g., Delete button) - NOT automatically wrapped */
|
|
84
|
+
leftAction?: React.ReactNode;
|
|
85
|
+
} | {
|
|
86
|
+
/** Primary action button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
87
|
+
primaryButton?: React.ReactNode;
|
|
88
|
+
/** Cancel/secondary button - automatically wrapped in ModalCloseWrapper to close the modal */
|
|
89
|
+
cancelButton?: React.ReactNode;
|
|
90
|
+
/** Optional action on the far left (e.g., Delete button) - NOT automatically wrapped */
|
|
91
|
+
leftAction: React.ReactNode;
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* Props for ModalBody component.
|
|
95
|
+
*
|
|
96
|
+
* Renders the scrollable main content area of the modal between the header and footer.
|
|
97
|
+
*/
|
|
98
|
+
interface TypeModalBodyProps extends TypeBoxProps {
|
|
99
|
+
/** The main content of the modal body */
|
|
100
|
+
children?: React.ReactNode;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Props for ModalDescription component.
|
|
104
|
+
*
|
|
105
|
+
* Wraps content with Radix UI's Dialog.Description for accessible modal descriptions
|
|
106
|
+
* that are announced by screen readers.
|
|
107
|
+
*/
|
|
108
|
+
interface TypeModalDescriptionProps extends TypeBoxProps {
|
|
109
|
+
/** The description text content */
|
|
110
|
+
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
|
+
/** Controls whether the modal is open (controlled mode) */
|
|
117
|
+
open?: boolean;
|
|
118
|
+
/** Default open state for uncontrolled mode */
|
|
119
|
+
defaultOpen?: boolean;
|
|
120
|
+
/** body content of the modal */
|
|
121
|
+
children: React.ReactNode;
|
|
122
|
+
/** Callback when open state changes */
|
|
123
|
+
onOpenChange?: (open: boolean) => void;
|
|
124
|
+
/** The element that will trigger the modal when clicked.
|
|
125
|
+
* Can be any React element like a button, link, or custom component. */
|
|
126
|
+
modalTrigger?: React.ReactElement<any>;
|
|
127
|
+
/** Simplified API: Modal description (automatically wrapped in Dialog.Description) */
|
|
128
|
+
description?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Custom attributes to be added to the modals container
|
|
131
|
+
* Each key will be prepended with "data-" when rendered in the DOM
|
|
132
|
+
*/
|
|
133
|
+
data?: Record<string, string | boolean | number>;
|
|
134
|
+
/** Optional quick actions to render on a modal side rail */
|
|
135
|
+
actions?: TypeModalActionProps[];
|
|
136
|
+
/** Accessible label for the close button in the rail (defaults to "Close") */
|
|
137
|
+
closeButtonAriaLabel?: string;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Base props with draggable and showOverlay relationship enforced.
|
|
141
|
+
*
|
|
142
|
+
* When draggable is true, showOverlay must be false or undefined because
|
|
143
|
+
* the overlay would block interaction with content behind the modal,
|
|
144
|
+
* defeating the purpose of being able to drag the modal aside.
|
|
145
|
+
*/
|
|
146
|
+
type TypeModalBaseProps = (TypeModalCommonProps & {
|
|
147
|
+
/** Enable draggable functionality */
|
|
148
|
+
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
|
+
showOverlay?: false;
|
|
154
|
+
}) | (TypeModalCommonProps & {
|
|
155
|
+
/** Enable draggable functionality */
|
|
156
|
+
draggable?: false;
|
|
157
|
+
/** Whether to show the background overlay (defaults to true) */
|
|
158
|
+
showOverlay?: boolean;
|
|
159
|
+
});
|
|
160
|
+
/**
|
|
161
|
+
* Modal props with title provided.
|
|
162
|
+
* aria-label is optional since Dialog.Title can serve as the accessible name.
|
|
163
|
+
*/
|
|
164
|
+
type TypeModalPropsWithTitle = TypeModalBaseProps & {
|
|
165
|
+
/** Simplified API: Modal title (creates ModalHeader automatically) */
|
|
166
|
+
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
|
+
*/
|
|
175
|
+
subtitle?: string;
|
|
176
|
+
/** Accessible label for the modal dialog (optional when title or subtitle is provided) */
|
|
177
|
+
"aria-label"?: string;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Modal props with subtitle provided but no title.
|
|
181
|
+
* aria-label is optional since Dialog.Description can help identify the modal.
|
|
182
|
+
*/
|
|
183
|
+
type TypeModalPropsWithSubtitleOnly = TypeModalBaseProps & {
|
|
184
|
+
/** Simplified API: Modal title (creates ModalHeader automatically) */
|
|
185
|
+
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
|
+
*/
|
|
194
|
+
subtitle: string;
|
|
195
|
+
/** Accessible label for the modal dialog (optional when title or subtitle is provided) */
|
|
196
|
+
"aria-label"?: string;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Modal props without title or subtitle.
|
|
200
|
+
*
|
|
201
|
+
* **IMPORTANT**: When no header (title or subtitle) is provided,
|
|
202
|
+
* `aria-label` is REQUIRED for accessibility compliance.
|
|
203
|
+
*
|
|
204
|
+
* Without a visible header, screen readers need `aria-label` to identify
|
|
205
|
+
* what the modal dialog is about.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
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>
|
|
218
|
+
*/
|
|
219
|
+
type TypeModalPropsWithoutHeader = TypeModalBaseProps & {
|
|
220
|
+
/** Simplified API: Modal title (creates ModalHeader automatically) - not allowed when no header */
|
|
221
|
+
title?: never;
|
|
222
|
+
/** Simplified API: Modal subtitle (creates ModalHeader automatically) - not allowed when no header */
|
|
223
|
+
subtitle?: never;
|
|
224
|
+
/**
|
|
225
|
+
* **REQUIRED: aria-label must be provided when no title or subtitle is given**
|
|
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.
|
|
237
|
+
*/
|
|
238
|
+
"aria-label": string;
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* Modal component props with discriminated union based on header presence.
|
|
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**
|
|
246
|
+
*
|
|
247
|
+
* TypeScript will error if you forget to provide `aria-label` when no header is present.
|
|
248
|
+
* This ensures accessibility compliance and better screen reader support.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* // ✅ Valid - has title, aria-label optional
|
|
252
|
+
* <Modal title="Delete Item" />
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* // ✅ Valid - has subtitle only, aria-label optional
|
|
256
|
+
* <Modal subtitle="Confirmation" />
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* // ✅ Valid - no header, aria-label provided
|
|
260
|
+
* <Modal aria-label="Delete confirmation dialog" />
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* // ❌ TypeScript Error - no header and missing required aria-label
|
|
264
|
+
* <Modal /> // Error: Property 'aria-label' is missing
|
|
265
|
+
*/
|
|
266
|
+
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
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Accessible modal dialog component built on Radix UI Dialog primitives.
|
|
304
|
+
*
|
|
305
|
+
* This component provides a flexible modal implementation with comprehensive accessibility
|
|
306
|
+
* features, keyboard navigation, and focus management built in.
|
|
307
|
+
*
|
|
308
|
+
* Key capabilities:
|
|
309
|
+
* - Automatic ARIA attributes and focus trapping
|
|
310
|
+
* - ESC key and outside click to close
|
|
311
|
+
* - Simplified API with title/subtitle props for common use cases
|
|
312
|
+
* - Controlled and uncontrolled state modes
|
|
313
|
+
* - Optional draggable behavior for side-by-side interaction
|
|
314
|
+
* - Floating action rail for quick actions like close, expand, etc.
|
|
315
|
+
* - Responsive bottom sheet layout on mobile
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* // Simple uncontrolled modal
|
|
319
|
+
* <Modal
|
|
320
|
+
* title="Delete Item"
|
|
321
|
+
* subtitle="This action cannot be undone"
|
|
322
|
+
* modalTrigger={<Button>Delete</Button>}
|
|
323
|
+
* >
|
|
324
|
+
* <ModalBody>Are you sure you want to delete this item?</ModalBody>
|
|
325
|
+
* <ModalFooter
|
|
326
|
+
* cancelButton={<Button>Cancel</Button>}
|
|
327
|
+
* primaryButton={<Button appearance="destructive">Delete</Button>}
|
|
328
|
+
* />
|
|
329
|
+
* </Modal>
|
|
330
|
+
*/
|
|
331
|
+
declare const Modal: (props: TypeModalProps) => react_jsx_runtime.JSX.Element;
|
|
332
|
+
|
|
333
|
+
interface HeaderProps {
|
|
334
|
+
draggable?: boolean;
|
|
335
|
+
isDragging?: boolean;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Base styled header component for custom modal headers.
|
|
339
|
+
*
|
|
340
|
+
* Use this component when you need complete control over the header layout
|
|
341
|
+
* and don't want to use the slot-based ModalHeader component.
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* <ModalCustomHeader>
|
|
345
|
+
* <YourCustomHeaderContent />
|
|
346
|
+
* </ModalCustomHeader>
|
|
347
|
+
*/
|
|
348
|
+
declare const ModalCustomHeader: styled_components.StyledComponent<React.ForwardRefExoticComponent<Omit<_sproutsocial_seeds_react_box.TypeBoxProps, "ref"> & React.RefAttributes<HTMLDivElement>>, styled_components.DefaultTheme, HeaderProps, never>;
|
|
349
|
+
/**
|
|
350
|
+
* Modal header component with title and subtitle slots.
|
|
351
|
+
*
|
|
352
|
+
* This component only supports slot-based rendering via title and subtitle props.
|
|
353
|
+
* For custom header layouts, use ModalCustomHeader instead.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* <ModalHeader title="Delete Item" subtitle="This action cannot be undone" />
|
|
357
|
+
*/
|
|
358
|
+
declare const ModalHeader: {
|
|
359
|
+
(props: TypeModalHeaderProps): react_jsx_runtime.JSX.Element;
|
|
360
|
+
displayName: string;
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Base styled footer component for custom modal footers.
|
|
365
|
+
*
|
|
366
|
+
* Use this component when you need complete control over the footer layout
|
|
367
|
+
* and don't want to use the slot-based ModalFooter component.
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* <ModalCustomFooter>
|
|
371
|
+
* <YourCustomFooterContent />
|
|
372
|
+
* </ModalCustomFooter>
|
|
373
|
+
*/
|
|
374
|
+
declare const ModalCustomFooter: styled_components.StyledComponent<React.ForwardRefExoticComponent<Omit<_sproutsocial_seeds_react_box.TypeBoxProps, "ref"> & React.RefAttributes<HTMLDivElement>>, styled_components.DefaultTheme, {}, never>;
|
|
375
|
+
/**
|
|
376
|
+
* Modal footer component for action buttons.
|
|
377
|
+
*
|
|
378
|
+
* This component only supports slot-based rendering with button props.
|
|
379
|
+
* For custom footer layouts, use ModalCustomFooter instead.
|
|
380
|
+
*
|
|
381
|
+
* Provides automatic button wrapping and layout management. Supports three button positions:
|
|
382
|
+
* - primaryButton: Main action button on the right (auto-closes modal)
|
|
383
|
+
* - cancelButton: Secondary action on the right (auto-closes modal)
|
|
384
|
+
* - leftAction: Optional action on the left (no auto-close, for destructive actions)
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* <ModalFooter
|
|
388
|
+
* cancelButton={<Button>Cancel</Button>}
|
|
389
|
+
* primaryButton={<Button appearance="primary">Save</Button>}
|
|
390
|
+
* />
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* // With left action
|
|
394
|
+
* <ModalFooter
|
|
395
|
+
* leftAction={<Button appearance="destructive">Delete</Button>}
|
|
396
|
+
* cancelButton={<Button>Cancel</Button>}
|
|
397
|
+
* primaryButton={<Button appearance="primary">Save</Button>}
|
|
398
|
+
* />
|
|
399
|
+
*/
|
|
400
|
+
declare const ModalFooter: {
|
|
401
|
+
(props: TypeModalFooterProps): react_jsx_runtime.JSX.Element | null;
|
|
402
|
+
displayName: string;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
declare const ModalBody: React.ForwardRefExoticComponent<Omit<TypeModalBodyProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Modal description component that wraps content with accessible Dialog.Description.
|
|
409
|
+
*
|
|
410
|
+
* This component automatically connects description text to the modal dialog via ARIA attributes,
|
|
411
|
+
* ensuring screen readers announce the description when the modal opens. Use this for additional
|
|
412
|
+
* context beyond the title that helps users understand the modal's purpose.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* <ModalDescription>
|
|
416
|
+
* Deleting this item will permanently remove it from your account.
|
|
417
|
+
* </ModalDescription>
|
|
418
|
+
*/
|
|
419
|
+
declare const ModalDescription: React.ForwardRefExoticComponent<Omit<TypeModalDescriptionProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Props for ModalCloseWrapper component.
|
|
423
|
+
*/
|
|
424
|
+
interface ModalCloseWrapperProps {
|
|
425
|
+
/** The element to wrap with close functionality */
|
|
426
|
+
children: React.ReactNode;
|
|
427
|
+
/** Optional click handler called before closing the modal */
|
|
428
|
+
onClick?: (e: React.MouseEvent) => void;
|
|
429
|
+
/** Whether to merge props into the child element (default: true) */
|
|
430
|
+
asChild?: boolean;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* A wrapper component that closes the modal when its child is clicked.
|
|
434
|
+
* Uses asChild pattern like Radix primitives - by default asChild is true.
|
|
435
|
+
*/
|
|
436
|
+
declare const ModalCloseWrapper: {
|
|
437
|
+
(props: ModalCloseWrapperProps): react_jsx_runtime.JSX.Element;
|
|
438
|
+
displayName: string;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
declare const ModalRail: React.FC<TypeModalRailProps>;
|
|
442
|
+
|
|
443
|
+
declare const ModalAction: React.FC<TypeModalActionProps>;
|
|
444
|
+
|
|
445
|
+
export { Modal as M, type TypeModalProps as T, ModalDescription as a, ModalHeader as b, ModalFooter as c, ModalBody as d, ModalCloseWrapper as e, ModalRail as f, ModalAction as g, ModalCustomHeader as h, ModalCustomFooter as i, type TypeModalHeaderProps as j, type TypeModalFooterProps as k, type TypeModalBodyProps as l, type TypeModalDescriptionProps as m, type TypeModalRailProps as n, type TypeModalActionProps as o, type ModalCloseWrapperProps as p };
|