entity-react-modals 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,10 +1,17 @@
1
1
  # entity-react-modals
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/entity-react-modals.svg)](https://www.npmjs.com/package/entity-react-modals)
4
+ [![npm downloads](https://img.shields.io/npm/dm/entity-react-modals.svg)](https://www.npmjs.com/package/entity-react-modals)
5
+ [![license](https://img.shields.io/npm/l/entity-react-modals.svg)](https://github.com/BazilSuhail/npm-react-modals/blob/main/LICENSE)
6
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/entity-react-modals)](https://bundlephobia.com/package/entity-react-modals)
7
+ [![typescript](https://img.shields.io/badge/typescript-ready-blue.svg)](https://www.typescriptlang.org/)
8
+
3
9
  Zero-dependency React modal library with spring physics animations powered by the Web Animations API.
4
10
 
5
- - No animation libraries required uses native WAAPI
11
+ - **7 animation variants**scale, slide, fade, none
12
+ - **5 spring presets** — default, gentle, wobbly, stiff, slow
13
+ - Zero-config — styles auto-injected, no CSS import needed
6
14
  - Compound component API for flexible composition
7
- - 5 built-in spring presets + custom spring configs
8
15
  - Controlled and uncontrolled modes
9
16
  - Portal-rendered, accessible, and tree-shakable
10
17
 
@@ -26,7 +33,6 @@ import {
26
33
  ModalFooter,
27
34
  ModalClose,
28
35
  } from 'entity-react-modals';
29
- import 'entity-react-modals/styles.css';
30
36
 
31
37
  function App() {
32
38
  return (
@@ -74,7 +80,8 @@ function App() {
74
80
  | `open` | `boolean` | — | Controlled open state. |
75
81
  | `defaultOpen` | `boolean` | `false` | Initial open state for uncontrolled mode. |
76
82
  | `onOpenChange` | `(open: boolean) => void` | — | Called when open state changes. |
77
- | `spring` | `SpringPreset \| SpringConfig` | `'default'` | Spring animation config. |
83
+ | `animation` | `AnimationVariant` | `'scale'` | Animation variant. |
84
+ | `spring` | `SpringPreset \| SpringConfig` | `'default'` | Spring physics config. |
78
85
  | `backdropColor` | `string` | `'rgba(0,0,0,0.6)'` | Backdrop background color. |
79
86
  | `backdropBlur` | `number` | `4` | Backdrop blur radius in px. |
80
87
  | `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Panel max-width preset. |
@@ -87,7 +94,9 @@ Props set on `ModalContent` override those set on `Modal` for that specific cont
87
94
  | Prop | Type | Default | Description |
88
95
  |---|---|---|---|
89
96
  | `children` | `ReactNode` | — | Modal panel content. |
97
+ | `className` | `string` | — | Additional CSS class on the panel. |
90
98
  | `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Panel max-width. |
99
+ | `animation` | `AnimationVariant` | `'scale'` | Animation variant. |
91
100
  | `closeOnBackdropClick` | `boolean` | `true` | Close when clicking the backdrop. |
92
101
  | `closeOnEscape` | `boolean` | `true` | Close on Escape key press. |
93
102
  | `backdropColor` | `string` | — | Override backdrop color. |
@@ -109,6 +118,184 @@ Props set on `ModalContent` override those set on `Modal` for that specific cont
109
118
  | `children` | `ReactNode` | Section content. |
110
119
  | `className` | `string` | Additional CSS class. |
111
120
 
121
+ ## Animation Variants
122
+
123
+ | Variant | Effect |
124
+ |---|---|
125
+ | `scale` | Scale from 0.95 to 1 (default) |
126
+ | `slide-bottom` | Slide up from below |
127
+ | `slide-top` | Slide down from above |
128
+ | `slide-left` | Slide in from left |
129
+ | `slide-right` | Slide in from right |
130
+ | `fade` | Opacity only, no transform |
131
+ | `none` | Instant, no animation |
132
+
133
+ ```tsx
134
+ // Set on Modal (applies to all content)
135
+ <Modal animation="slide-bottom">...</Modal>
136
+
137
+ // Set on ModalContent (overrides Modal)
138
+ <ModalContent animation="slide-left" spring="gentle">...</ModalContent>
139
+
140
+ // Disable animation entirely
141
+ <ModalContent animation="none">...</ModalContent>
142
+ ```
143
+
144
+ ### Real-World Example: Notification Toast
145
+
146
+ ```tsx
147
+ <Modal>
148
+ <ModalTrigger>
149
+ <button>Show Notification</button>
150
+ </ModalTrigger>
151
+ <ModalContent size="sm" animation="slide-bottom" spring="stiff"
152
+ backdropColor="rgba(0, 0, 0, 0.3)" backdropBlur={4}>
153
+ <div style={{ padding: '24px', textAlign: 'center' }}>
154
+ <h3>Success!</h3>
155
+ <p>Your changes have been saved.</p>
156
+ <ModalClose>Done</ModalClose>
157
+ </div>
158
+ </ModalContent>
159
+ </Modal>
160
+ ```
161
+
162
+ ### Real-World Example: Settings Panel
163
+
164
+ ```tsx
165
+ <Modal>
166
+ <ModalTrigger>
167
+ <button>Settings</button>
168
+ </ModalTrigger>
169
+ <ModalContent size="lg" animation="slide-left" spring="default"
170
+ backdropColor="rgba(0, 0, 0, 0.4)" backdropBlur={8}>
171
+ <ModalHeader>
172
+ <h2>Settings</h2>
173
+ <ModalClose />
174
+ </ModalHeader>
175
+ <ModalBody>
176
+ {/* Toggle sections, forms, danger zones */}
177
+ </ModalBody>
178
+ </ModalContent>
179
+ </Modal>
180
+ ```
181
+
182
+ ### Real-World Example: Command Palette
183
+
184
+ ```tsx
185
+ <Modal>
186
+ <ModalTrigger>
187
+ <button>Search</button>
188
+ </ModalTrigger>
189
+ <ModalContent size="md" animation="scale" spring="stiff"
190
+ backdropColor="rgba(0, 0, 0, 0.6)" backdropBlur={8}>
191
+ <div style={{ padding: '12px' }}>
192
+ <input type="text" placeholder="Search commands..." autoFocus />
193
+ {/* Command list */}
194
+ </div>
195
+ </ModalContent>
196
+ </Modal>
197
+ ```
198
+
199
+ ### Real-World Example: Payment Form
200
+
201
+ ```tsx
202
+ <Modal>
203
+ <ModalTrigger>
204
+ <button>Upgrade to Pro</button>
205
+ </ModalTrigger>
206
+ <ModalContent size="md" spring="gentle"
207
+ backdropColor="rgba(0, 0, 0, 0.5)" backdropBlur={6}>
208
+ <ModalHeader>
209
+ <h2>Upgrade to Pro</h2>
210
+ <ModalClose />
211
+ </ModalHeader>
212
+ <ModalBody>
213
+ <p>$49 / one time</p>
214
+ {/* Card form */}
215
+ </ModalBody>
216
+ <ModalFooter>
217
+ <ModalClose>Cancel</ModalClose>
218
+ <button>Pay $49</button>
219
+ </ModalFooter>
220
+ </ModalContent>
221
+ </Modal>
222
+ ```
223
+
224
+ ### Real-World Example: Image Viewer
225
+
226
+ ```tsx
227
+ <Modal>
228
+ <ModalTrigger>
229
+ <button>View Image</button>
230
+ </ModalTrigger>
231
+ <ModalContent size="xl" animation="scale" spring="gentle"
232
+ backdropColor="rgba(0, 0, 0, 0.85)" backdropBlur={12}>
233
+ <ModalClose />
234
+ {/* Full-width image content */}
235
+ </ModalContent>
236
+ </Modal>
237
+ ```
238
+
239
+ ### Real-World Example: Destructive Alert
240
+
241
+ ```tsx
242
+ <Modal>
243
+ <ModalTrigger>
244
+ <button>Delete Account</button>
245
+ </ModalTrigger>
246
+ <ModalContent size="sm" animation="slide-top" spring="stiff"
247
+ backdropColor="rgba(0, 0, 0, 0.6)" backdropBlur={4}>
248
+ <div style={{ padding: '24px', textAlign: 'center' }}>
249
+ <h3>Are you sure?</h3>
250
+ <p>This action cannot be undone.</p>
251
+ <ModalClose>Cancel</ModalClose>
252
+ <button style={{ background: '#ef4444', color: 'white' }}>
253
+ Yes, delete everything
254
+ </button>
255
+ </div>
256
+ </ModalContent>
257
+ </Modal>
258
+ ```
259
+
260
+ ### Real-World Example: Login Form
261
+
262
+ ```tsx
263
+ <Modal>
264
+ <ModalTrigger>
265
+ <button>Sign in</button>
266
+ </ModalTrigger>
267
+ <ModalContent size="sm" animation="slide-bottom" spring="gentle"
268
+ backdropColor="rgba(16, 185, 129, 0.15)" backdropBlur={12}>
269
+ <div style={{ padding: '24px' }}>
270
+ <h3>Welcome back</h3>
271
+ <input type="email" placeholder="you@example.com" />
272
+ <input type="password" placeholder="Password" />
273
+ <button>Sign in</button>
274
+ </div>
275
+ </ModalContent>
276
+ </Modal>
277
+ ```
278
+
279
+ ### Real-World Example: Pricing Cards
280
+
281
+ ```tsx
282
+ <Modal>
283
+ <ModalTrigger>
284
+ <button>View Pricing</button>
285
+ </ModalTrigger>
286
+ <ModalContent size="lg" animation="slide-right" spring="wobbly"
287
+ backdropColor="rgba(0, 0, 0, 0.5)" backdropBlur={8}>
288
+ <ModalHeader>
289
+ <h2>Choose your plan</h2>
290
+ <ModalClose />
291
+ </ModalHeader>
292
+ <ModalBody>
293
+ {/* Three-column pricing cards */}
294
+ </ModalBody>
295
+ </ModalContent>
296
+ </Modal>
297
+ ```
298
+
112
299
  ## Sizes
113
300
 
114
301
  | Size | Max Width |
@@ -152,15 +339,6 @@ Pass a `SpringConfig` object to fine-tune the animation:
152
339
  | `damping` | Damping force. Higher = less oscillation. |
153
340
  | `mass` | Mass of the animated object. Lower = lighter feel. |
154
341
 
155
- Spring config can also be set on the `Modal` root and it applies to all content panels:
156
-
157
- ```tsx
158
- <Modal spring={{ stiffness: 300, damping: 15, mass: 0.8 }}>
159
- <ModalTrigger>...</ModalTrigger>
160
- <ModalContent>...</ModalContent>
161
- </Modal>
162
- ```
163
-
164
342
  ## Controlled Mode
165
343
 
166
344
  Manage open/close state externally with `useState`:
@@ -261,9 +439,9 @@ function App() {
261
439
 
262
440
  <Modal>
263
441
  <ModalTrigger><button>Second</button></ModalTrigger>
264
- <ModalContent size="lg" spring="gentle">
442
+ <ModalContent size="lg" animation="slide-left" spring="gentle">
265
443
  <ModalHeader><h2>Second Modal</h2><ModalClose /></ModalHeader>
266
- <ModalBody>Different size and spring</ModalBody>
444
+ <ModalBody>Different size, animation, and spring</ModalBody>
267
445
  </ModalContent>
268
446
  </Modal>
269
447
  </>
@@ -310,12 +488,13 @@ import type {
310
488
  ModalFooterProps,
311
489
  SpringConfig,
312
490
  SpringPreset,
491
+ AnimationVariant,
313
492
  } from 'entity-react-modals';
314
493
  ```
315
494
 
316
495
  ## Tree Shaking
317
496
 
318
- The package uses the `exports` field with conditional ESM/CJS builds and marks CSS as the only side effect. Bundlers will tree-shake unused components automatically.
497
+ The package uses the `exports` field with conditional ESM/CJS builds and `sideEffects: false`. Styles are auto-injected on first import. Bundlers will tree-shake unused components automatically.
319
498
 
320
499
  ```tsx
321
500
  // Only imports what you use
package/dist/index.cjs CHANGED
@@ -4,7 +4,124 @@ var react = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var reactDom = require('react-dom');
6
6
 
7
- // src/Modal.tsx
7
+ // src/inject.ts
8
+ var INJECTED = "__ERM_INJECTED__";
9
+ function injectStyles(css) {
10
+ if (typeof document === "undefined") return;
11
+ if (window[INJECTED]) return;
12
+ window[INJECTED] = true;
13
+ const style = document.createElement("style");
14
+ style.textContent = css;
15
+ document.head.appendChild(style);
16
+ }
17
+
18
+ // src/styles.ts
19
+ var styles = `
20
+ :root {
21
+ --rm-backdrop-bg: rgba(0, 0, 0, 0.6);
22
+ --rm-panel-bg: #ffffff;
23
+ --rm-panel-radius: 12px;
24
+ --rm-panel-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
25
+ --rm-close-color: #3b82f6;
26
+ --rm-close-hover: #2563eb;
27
+ --rm-header-border: #e2e8f0;
28
+ --rm-footer-border: #e2e8f0;
29
+ }
30
+
31
+ .rm-backdrop {
32
+ position: fixed;
33
+ inset: 0;
34
+ z-index: 9998;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ padding: 20px;
39
+ opacity: 0;
40
+ }
41
+
42
+ .rm-panel {
43
+ position: relative;
44
+ z-index: 9999;
45
+ background: var(--rm-panel-bg);
46
+ border-radius: var(--rm-panel-radius);
47
+ box-shadow: var(--rm-panel-shadow);
48
+ width: 100%;
49
+ max-height: calc(100vh - 40px);
50
+ opacity: 0;
51
+ transform: scale(0.95);
52
+ display: flex;
53
+ flex-direction: column;
54
+ }
55
+
56
+ .rm-panel--sm { max-width: 400px; }
57
+ .rm-panel--md { max-width: 560px; }
58
+ .rm-panel--lg { max-width: 720px; }
59
+ .rm-panel--xl { max-width: 900px; }
60
+
61
+ .rm-header {
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: space-between;
65
+ padding: 16px 20px;
66
+ border-bottom: 1px solid var(--rm-header-border);
67
+ flex-shrink: 0;
68
+ }
69
+
70
+ .rm-header h2,
71
+ .rm-header h3 {
72
+ margin: 0;
73
+ font-size: 1.125rem;
74
+ font-weight: 600;
75
+ color: #1e293b;
76
+ }
77
+
78
+ .rm-body {
79
+ padding: 20px;
80
+ overflow-y: auto;
81
+ flex: 1;
82
+ min-height: 0;
83
+ }
84
+
85
+ .rm-footer {
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: flex-end;
89
+ gap: 8px;
90
+ padding: 16px 20px;
91
+ border-top: 1px solid var(--rm-footer-border);
92
+ flex-shrink: 0;
93
+ }
94
+
95
+ .rm-close {
96
+ display: inline-flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ width: 28px;
100
+ height: 28px;
101
+ padding: 0;
102
+ border: none;
103
+ border-radius: 6px;
104
+ background: transparent;
105
+ color: var(--rm-close-color);
106
+ font-size: 1.25rem;
107
+ line-height: 1;
108
+ cursor: pointer;
109
+ transition: background-color 0.15s ease, color 0.15s ease;
110
+ }
111
+
112
+ .rm-close:hover {
113
+ background: rgba(59, 130, 246, 0.1);
114
+ color: var(--rm-close-hover);
115
+ }
116
+
117
+ @media (prefers-reduced-motion: reduce) {
118
+ .rm-backdrop,
119
+ .rm-panel {
120
+ transition: none !important;
121
+ animation: none !important;
122
+ }
123
+ }
124
+ `;
8
125
  var ModalContext = react.createContext(null);
9
126
  function useModalContext() {
10
127
  const ctx = react.useContext(ModalContext);
@@ -17,6 +134,7 @@ function Modal({
17
134
  defaultOpen = false,
18
135
  onOpenChange,
19
136
  spring,
137
+ animation,
20
138
  backdropColor,
21
139
  backdropBlur,
22
140
  size,
@@ -46,6 +164,7 @@ function Modal({
46
164
  onClose,
47
165
  onOpen,
48
166
  spring,
167
+ animation,
49
168
  backdropColor,
50
169
  backdropBlur,
51
170
  size,
@@ -114,21 +233,58 @@ function generateSpringKeyframes(from, to, config, options) {
114
233
  const duration = steps * FIXED_DT * 1e3;
115
234
  return { keyframes: positions, duration };
116
235
  }
117
- function springToWAAPIKeyframes(fromValue, toValue, property, config, options) {
118
- const { keyframes: positions, duration } = generateSpringKeyframes(fromValue, toValue, config, options);
119
- const waapiKeyframes = positions.map((pos, i) => {
236
+ function buildTransformKeyframes(positions, variant) {
237
+ return positions.map((pos, i) => {
120
238
  const offset = i / (positions.length - 1);
121
- if (property === "opacity") {
122
- return { opacity: String(pos), offset };
239
+ switch (variant) {
240
+ case "fade":
241
+ return { opacity: String(pos), offset };
242
+ case "scale":
243
+ return {
244
+ transform: `scale(${0.95 + 0.05 * pos})`,
245
+ opacity: String(pos),
246
+ offset
247
+ };
248
+ case "slide-bottom":
249
+ return {
250
+ transform: `translateY(${(1 - pos) * 100}%)`,
251
+ opacity: String(pos),
252
+ offset
253
+ };
254
+ case "slide-top":
255
+ return {
256
+ transform: `translateY(${(pos - 1) * 100}%)`,
257
+ opacity: String(pos),
258
+ offset
259
+ };
260
+ case "slide-left":
261
+ return {
262
+ transform: `translateX(${(pos - 1) * 100}%)`,
263
+ opacity: String(pos),
264
+ offset
265
+ };
266
+ case "slide-right":
267
+ return {
268
+ transform: `translateX(${(1 - pos) * 100}%)`,
269
+ opacity: String(pos),
270
+ offset
271
+ };
272
+ default:
273
+ return { opacity: String(pos), offset };
123
274
  }
124
- const scale = 0.95 + 0.05 * pos;
125
- return {
126
- transform: `scale(${scale})`,
127
- opacity: String(pos),
128
- offset
129
- };
130
275
  });
131
- return { keyframes: waapiKeyframes, duration };
276
+ }
277
+ function springToWAAPIKeyframes(fromValue, toValue, property, config, options) {
278
+ const { keyframes: positions, duration } = generateSpringKeyframes(fromValue, toValue, config, options);
279
+ if (property === "opacity") {
280
+ const keyframes = positions.map((pos, i) => ({
281
+ opacity: String(pos),
282
+ offset: i / (positions.length - 1)
283
+ }));
284
+ return { keyframes, duration };
285
+ }
286
+ const variant = options?.variant ?? "scale";
287
+ return { keyframes: buildTransformKeyframes(positions, variant), duration };
132
288
  }
133
289
 
134
290
  // src/animate.ts
@@ -137,10 +293,11 @@ function prefersReducedMotion() {
137
293
  }
138
294
  var EXIT_MAX_DURATION = 400;
139
295
  function animateIn(backdropEl, panelEl, config) {
140
- if (prefersReducedMotion()) {
296
+ const variant = config?.animation ?? "scale";
297
+ if (prefersReducedMotion() || variant === "none") {
141
298
  backdropEl.style.opacity = "1";
142
299
  panelEl.style.opacity = "1";
143
- panelEl.style.transform = "scale(1)";
300
+ panelEl.style.transform = "none";
144
301
  return [];
145
302
  }
146
303
  const springConfig = resolveSpringConfig(config?.spring);
@@ -148,7 +305,7 @@ function animateIn(backdropEl, panelEl, config) {
148
305
  ...springConfig,
149
306
  stiffness: springConfig.stiffness * 0.8
150
307
  });
151
- const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(0, 1, "transform", springConfig);
308
+ const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(0, 1, "transform", springConfig, { variant });
152
309
  const backdropAnim = backdropEl.animate(backdropKF, {
153
310
  duration: backdropDur,
154
311
  easing: "linear",
@@ -162,7 +319,8 @@ function animateIn(backdropEl, panelEl, config) {
162
319
  return [backdropAnim, panelAnim];
163
320
  }
164
321
  function animateOut(backdropEl, panelEl, config) {
165
- if (prefersReducedMotion()) {
322
+ const variant = config?.animation ?? "scale";
323
+ if (prefersReducedMotion() || variant === "none") {
166
324
  return Promise.resolve();
167
325
  }
168
326
  const springConfig = resolveSpringConfig(config?.spring);
@@ -176,7 +334,8 @@ function animateOut(backdropEl, panelEl, config) {
176
334
  stiffness: exitConfig.stiffness * 0.8
177
335
  }, { maxDuration: EXIT_MAX_DURATION });
178
336
  const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(1, 0, "transform", exitConfig, {
179
- maxDuration: EXIT_MAX_DURATION
337
+ maxDuration: EXIT_MAX_DURATION,
338
+ variant
180
339
  });
181
340
  const backdropAnim = backdropEl.animate(backdropKF, {
182
341
  duration: backdropDur,
@@ -219,16 +378,12 @@ function useClickOutside(enabled, onClick) {
219
378
  }, [enabled, handleClick]);
220
379
  return panelRef;
221
380
  }
222
- var SIZE_MAP = {
223
- sm: "400px",
224
- md: "560px",
225
- lg: "720px",
226
- xl: "900px"
227
- };
228
381
  var SAFETY_UNMOUNT_MS = 600;
229
382
  function ModalContent({
230
383
  children,
384
+ className,
231
385
  size: sizeProp,
386
+ animation: animationProp,
232
387
  closeOnBackdropClick = true,
233
388
  closeOnEscape = true,
234
389
  backdropColor,
@@ -238,6 +393,7 @@ function ModalContent({
238
393
  }) {
239
394
  const ctx = useModalContext();
240
395
  const size = sizeProp ?? ctx.size ?? "md";
396
+ const resolvedAnimation = animationProp ?? ctx.animation ?? "scale";
241
397
  const resolvedBackdropColor = backdropColor ?? ctx.backdropColor ?? "rgba(0, 0, 0, 0.6)";
242
398
  const resolvedBackdropBlur = backdropBlur ?? ctx.backdropBlur ?? 4;
243
399
  const resolvedSpring = spring ?? ctx.spring;
@@ -268,7 +424,8 @@ function ModalContent({
268
424
  requestAnimationFrame(() => {
269
425
  if (backdropRef.current && panelRef.current) {
270
426
  animateIn(backdropRef.current, panelRef.current, {
271
- spring: resolvedSpring});
427
+ spring: resolvedSpring,
428
+ animation: resolvedAnimation});
272
429
  setTimeout(() => {
273
430
  animatingRef.current = false;
274
431
  }, 500);
@@ -288,14 +445,15 @@ function ModalContent({
288
445
  safetyTimerRef.current = setTimeout(unmount, SAFETY_UNMOUNT_MS);
289
446
  if (backdropRef.current && panelRef.current) {
290
447
  animateOut(backdropRef.current, panelRef.current, {
291
- spring: resolvedSpring}).then(unmount);
448
+ spring: resolvedSpring,
449
+ animation: resolvedAnimation}).then(unmount);
292
450
  } else {
293
451
  unmount();
294
452
  }
295
453
  }
296
454
  prevOpen.current = ctx.open;
297
455
  return clearSafetyTimer;
298
- }, [ctx.open, resolvedSpring, animationDuration, clearSafetyTimer]);
456
+ }, [ctx.open, resolvedSpring, resolvedAnimation, animationDuration, clearSafetyTimer]);
299
457
  if (!render) return null;
300
458
  const setRefs = (el) => {
301
459
  clickOutsideRef.current = el;
@@ -316,10 +474,9 @@ function ModalContent({
316
474
  "div",
317
475
  {
318
476
  ref: setRefs,
319
- className: `rm-panel rm-panel--${size}`,
477
+ className: `rm-panel rm-panel--${size}${className ? ` ${className}` : ""}`,
320
478
  role: "dialog",
321
479
  "aria-modal": "true",
322
- style: { maxWidth: SIZE_MAP[size] },
323
480
  children
324
481
  }
325
482
  )
@@ -342,6 +499,9 @@ function ModalFooter({ children, className }) {
342
499
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `rm-footer ${className ?? ""}`, children });
343
500
  }
344
501
 
502
+ // src/index.ts
503
+ injectStyles(styles);
504
+
345
505
  exports.Modal = Modal;
346
506
  exports.ModalBody = ModalBody;
347
507
  exports.ModalClose = ModalClose;