smartsell-ui-kit 0.0.5 → 0.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/dist/modal.cjs CHANGED
@@ -26,6 +26,18 @@ module.exports = __toCommonJS(modal_exports);
26
26
 
27
27
  // src/components/Modal.tsx
28
28
  var import_react = require("react");
29
+
30
+ // src/color.ts
31
+ function withAlpha(hex, alpha) {
32
+ const normalized = hex.replace("#", "").trim();
33
+ const value = normalized.length === 3 ? normalized.split("").map((char) => char + char).join("") : normalized;
34
+ const red = Number.parseInt(value.slice(0, 2), 16);
35
+ const green = Number.parseInt(value.slice(2, 4), 16);
36
+ const blue = Number.parseInt(value.slice(4, 6), 16);
37
+ return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
38
+ }
39
+
40
+ // src/components/Modal.tsx
29
41
  var import_jsx_runtime = require("react/jsx-runtime");
30
42
  var defaultThemeColors = {
31
43
  background: "#f8fafc",
@@ -39,13 +51,16 @@ var defaultThemeColors = {
39
51
  negative: "#dc2626",
40
52
  warning: "#d97706"
41
53
  };
42
- var withAlpha = (hex, alpha) => {
43
- const normalized = hex.replace("#", "").trim();
44
- const value = normalized.length === 3 ? normalized.split("").map((char) => char + char).join("") : normalized;
45
- const red = Number.parseInt(value.slice(0, 2), 16);
46
- const green = Number.parseInt(value.slice(2, 4), 16);
47
- const blue = Number.parseInt(value.slice(4, 6), 16);
48
- return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
54
+ var srOnlyStyle = {
55
+ position: "absolute",
56
+ width: 1,
57
+ height: 1,
58
+ padding: 0,
59
+ margin: -1,
60
+ overflow: "hidden",
61
+ clip: "rect(0, 0, 0, 0)",
62
+ whiteSpace: "nowrap",
63
+ border: 0
49
64
  };
50
65
  var isUiKitThemeTokens = (theme) => {
51
66
  return Boolean(theme && typeof theme === "object" && "theme" in theme);
@@ -81,47 +96,111 @@ var isLikelyMobileViewport = () => {
81
96
  navigator.userAgent
82
97
  );
83
98
  };
99
+ var createTitleId = (title) => {
100
+ if (typeof title === "string" || typeof title === "number") {
101
+ const normalized = String(title).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
102
+ return `smartsell-modal-${normalized || "dialog"}`;
103
+ }
104
+ return "smartsell-modal-dialog";
105
+ };
84
106
  var isLegacyModalProps = (props) => {
85
107
  return "showModal" in props;
86
108
  };
87
- function LegacyActionButton({
88
- label,
89
- onClick,
90
- disabled,
91
- type = "contained",
92
- theme,
93
- style
109
+ var normalizeLegacyAction = (action, fallbackDisabled = false) => {
110
+ var _a, _b, _c;
111
+ return {
112
+ label: action.name,
113
+ onClick: action.onClick,
114
+ appearance: (_a = action.type) != null ? _a : "contained",
115
+ style: (_b = action.style) != null ? _b : { maxWidth: "150px" },
116
+ disabled: (_c = action.disable) != null ? _c : fallbackDisabled
117
+ };
118
+ };
119
+ var normalizeModalProps = (props) => {
120
+ var _a, _b;
121
+ if (!isLegacyModalProps(props)) {
122
+ return props;
123
+ }
124
+ const isBusy = Boolean(props.isLoading);
125
+ const disableAction = Boolean(props.disableActionBtn || props.isLoading);
126
+ return {
127
+ isOpen: props.showModal,
128
+ onClose: props.closeModal,
129
+ title: props.title,
130
+ children: props.children,
131
+ theme: props.theme,
132
+ maximized: props.maximized,
133
+ contentStyle: props.style,
134
+ bodyStyle: props.bodyStyle,
135
+ hideCloseButton: props.hideCloseIcon,
136
+ disableDismiss: isBusy,
137
+ closeOnBackdrop: false,
138
+ closeOnEscape: false,
139
+ isBusy,
140
+ closeAction: props.onlyCloseButton ? {
141
+ label: "Close",
142
+ onClick: props.closeModal,
143
+ appearance: "contained",
144
+ disabled: isBusy
145
+ } : void 0,
146
+ cancelAction: props.onlyCloseButton || !props.cancelButton ? void 0 : {
147
+ label: "Cancel",
148
+ onClick: props.cancelButton,
149
+ appearance: "text",
150
+ style: { maxWidth: "100px" }
151
+ },
152
+ confirmAction: props.onlyCloseButton || props.hideActionButton || !props.action ? void 0 : {
153
+ label: (_a = props.actionNameBtn) != null ? _a : "Save",
154
+ onClick: props.action,
155
+ appearance: "contained",
156
+ style: { maxWidth: "100px" },
157
+ disabled: disableAction
158
+ },
159
+ extraActions: props.onlyCloseButton ? void 0 : (_b = props.additionalActions) == null ? void 0 : _b.map((action) => normalizeLegacyAction(action, disableAction))
160
+ };
161
+ };
162
+ function ModalActionButton({
163
+ action,
164
+ theme
94
165
  }) {
95
166
  var _a, _b;
96
167
  const { colors } = theme;
168
+ const {
169
+ label,
170
+ onClick,
171
+ appearance = "contained",
172
+ disabled = false,
173
+ style
174
+ } = action;
97
175
  const buttonStyle = {
98
176
  width: "100%",
99
177
  display: "flex",
100
178
  alignItems: "center",
101
179
  justifyContent: "center",
102
180
  borderRadius: "0.4rem",
103
- padding: type === "link" ? 0 : "1.3rem",
181
+ padding: appearance === "link" ? 0 : "0.9rem 1.15rem",
104
182
  boxSizing: "border-box",
105
183
  cursor: disabled ? "not-allowed" : "pointer",
106
184
  fontWeight: 700,
107
- fontSize: "1.3rem",
185
+ fontSize: "1.05rem",
186
+ lineHeight: 1.2,
108
187
  margin: 0,
109
188
  textAlign: "center",
110
189
  transition: "0.5s",
111
190
  opacity: disabled ? 0.5 : 1,
112
191
  filter: disabled ? "saturate(0)" : void 0
113
192
  };
114
- if (type === "text") {
193
+ if (appearance === "text") {
115
194
  buttonStyle.background = "none";
116
195
  buttonStyle.border = "1px solid transparent";
117
196
  buttonStyle.color = colors.primary;
118
197
  buttonStyle.boxShadow = "none";
119
- } else if (type === "link") {
198
+ } else if (appearance === "link") {
120
199
  buttonStyle.background = "none";
121
200
  buttonStyle.border = "none";
122
201
  buttonStyle.color = colors.primary;
123
202
  buttonStyle.boxShadow = "none";
124
- } else if (type === "outlined") {
203
+ } else if (appearance === "outlined") {
125
204
  buttonStyle.background = "none";
126
205
  buttonStyle.border = `2px solid ${colors.primary}`;
127
206
  buttonStyle.color = colors.primary;
@@ -140,7 +219,7 @@ function LegacyActionButton({
140
219
  display: "flex",
141
220
  alignItems: "center",
142
221
  justifyContent: "center",
143
- margin: "0 5px",
222
+ margin: 0,
144
223
  marginBottom: (_b = style == null ? void 0 : style.marginBottom) != null ? _b : 0,
145
224
  ...style
146
225
  },
@@ -157,29 +236,91 @@ function LegacyActionButton({
157
236
  }
158
237
  );
159
238
  }
160
- function StandardModal({
239
+ function ModalBusyIndicator({
240
+ theme
241
+ }) {
242
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
243
+ "div",
244
+ {
245
+ "aria-live": "polite",
246
+ role: "status",
247
+ style: {
248
+ position: "relative",
249
+ display: "inline-flex",
250
+ alignItems: "center",
251
+ justifyContent: "center",
252
+ width: 56,
253
+ height: 56,
254
+ borderRadius: 999,
255
+ backgroundColor: withAlpha(theme.colors.surface, 0.88),
256
+ boxShadow: `0 18px 36px ${withAlpha(theme.colors.onSurface, 0.08)}`
257
+ },
258
+ children: [
259
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: srOnlyStyle, children: "Loading" }),
260
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { "aria-hidden": "true", width: "32", height: "32", viewBox: "0 0 40 40", fill: "none", children: [
261
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
262
+ "circle",
263
+ {
264
+ cx: "20",
265
+ cy: "20",
266
+ r: "16",
267
+ stroke: withAlpha(theme.colors.onSurface, 0.12),
268
+ strokeWidth: "4"
269
+ }
270
+ ),
271
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
272
+ "path",
273
+ {
274
+ d: "M20 4C28.837 4 36 11.163 36 20",
275
+ stroke: theme.colors.primary,
276
+ strokeWidth: "4",
277
+ strokeLinecap: "round",
278
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
279
+ "animateTransform",
280
+ {
281
+ attributeName: "transform",
282
+ type: "rotate",
283
+ from: "0 20 20",
284
+ to: "360 20 20",
285
+ dur: "0.75s",
286
+ repeatCount: "indefinite"
287
+ }
288
+ )
289
+ }
290
+ )
291
+ ] })
292
+ ]
293
+ }
294
+ );
295
+ }
296
+ function UnifiedModal({
161
297
  isOpen,
162
298
  onClose,
163
299
  children,
164
- footer,
165
300
  title,
166
- description,
167
301
  headerContent,
302
+ footer,
303
+ confirmAction,
304
+ cancelAction,
305
+ closeAction,
306
+ extraActions,
168
307
  maxWidth,
169
308
  closeOnBackdrop = true,
170
309
  closeOnEscape = true,
171
310
  hideCloseButton = false,
172
311
  hideExpandButton = false,
312
+ disableDismiss = false,
173
313
  maximized,
174
314
  contentStyle,
315
+ bodyStyle,
316
+ isBusy = false,
175
317
  theme
176
318
  }) {
319
+ var _a, _b;
177
320
  const modalTheme = (0, import_react.useMemo)(() => resolveTheme(theme), [theme]);
178
321
  const [isMaximized, setIsMaximized] = (0, import_react.useState)(maximized != null ? maximized : false);
179
- const titleId = (0, import_react.useMemo)(
180
- () => `smartsell-modal-${String(title != null ? title : "dialog").toLowerCase().replace(/[^a-z0-9]+/g, "-")}`,
181
- [title]
182
- );
322
+ const titleId = (0, import_react.useMemo)(() => createTitleId(title), [title]);
323
+ const shouldDisableDismiss = disableDismiss || isBusy;
183
324
  (0, import_react.useEffect)(() => {
184
325
  if (typeof maximized === "boolean") {
185
326
  setIsMaximized(maximized);
@@ -196,7 +337,7 @@ function StandardModal({
196
337
  const previousOverflow = document.body.style.overflow;
197
338
  document.body.style.overflow = "hidden";
198
339
  const handleKeyDown = (event) => {
199
- if (closeOnEscape && event.key === "Escape") {
340
+ if (!shouldDisableDismiss && closeOnEscape && event.key === "Escape") {
200
341
  onClose();
201
342
  }
202
343
  };
@@ -205,47 +346,82 @@ function StandardModal({
205
346
  document.body.style.overflow = previousOverflow;
206
347
  window.removeEventListener("keydown", handleKeyDown);
207
348
  };
208
- }, [closeOnEscape, isOpen, onClose]);
349
+ }, [closeOnEscape, isOpen, onClose, shouldDisableDismiss]);
209
350
  if (!isOpen) {
210
351
  return null;
211
352
  }
212
- const header = headerContent != null ? headerContent : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
213
- title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
214
- "h2",
215
- {
216
- id: titleId,
217
- style: {
218
- margin: 0,
219
- color: modalTheme.colors.onSurface,
220
- fontSize: 30,
221
- fontWeight: 800,
222
- lineHeight: 1.1
223
- },
224
- children: title
225
- }
226
- ) : null,
227
- description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
228
- "p",
229
- {
230
- style: {
231
- margin: 0,
232
- color: modalTheme.mutedText,
233
- fontSize: 15,
234
- lineHeight: 1.6
353
+ const resolvedHeader = headerContent != null ? headerContent : title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
354
+ "h2",
355
+ {
356
+ id: titleId,
357
+ style: {
358
+ margin: 0,
359
+ color: modalTheme.colors.onSurface,
360
+ fontSize: 30,
361
+ fontWeight: 800,
362
+ lineHeight: 1.1
363
+ },
364
+ children: title
365
+ }
366
+ ) : null;
367
+ let footerContent = footer;
368
+ if (footerContent === void 0) {
369
+ if (closeAction && !closeAction.hidden) {
370
+ footerContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
371
+ ModalActionButton,
372
+ {
373
+ action: { ...closeAction, disabled: closeAction.disabled || isBusy },
374
+ theme: modalTheme
375
+ }
376
+ );
377
+ } else {
378
+ const resolvedActions = [
379
+ cancelAction ? {
380
+ ...cancelAction,
381
+ appearance: (_a = cancelAction.appearance) != null ? _a : "text",
382
+ disabled: cancelAction.disabled || isBusy
383
+ } : void 0,
384
+ ...(extraActions != null ? extraActions : []).map((action) => {
385
+ var _a2;
386
+ return {
387
+ ...action,
388
+ appearance: (_a2 = action.appearance) != null ? _a2 : "contained",
389
+ disabled: action.disabled || isBusy
390
+ };
391
+ }),
392
+ confirmAction ? {
393
+ ...confirmAction,
394
+ appearance: (_b = confirmAction.appearance) != null ? _b : "contained",
395
+ disabled: confirmAction.disabled || isBusy
396
+ } : void 0
397
+ ].reduce((items, action) => {
398
+ if (!action || action.hidden) {
399
+ return items;
400
+ }
401
+ items.push(action);
402
+ return items;
403
+ }, []);
404
+ footerContent = resolvedActions.length > 0 ? resolvedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
405
+ ModalActionButton,
406
+ {
407
+ action,
408
+ theme: modalTheme
235
409
  },
236
- children: description
237
- }
238
- ) : null
239
- ] });
410
+ `modal-action-${index}`
411
+ )) : void 0;
412
+ }
413
+ }
414
+ const shouldRenderFooter = footerContent !== void 0 && footerContent !== null && footerContent !== false;
240
415
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
241
416
  "div",
242
417
  {
243
418
  "aria-label": headerContent ? typeof title === "string" ? title : "Dialog" : void 0,
244
419
  "aria-labelledby": headerContent ? void 0 : title ? titleId : void 0,
420
+ "aria-busy": isBusy,
245
421
  "aria-modal": "true",
246
422
  role: "dialog",
247
423
  onMouseDown: (event) => {
248
- if (closeOnBackdrop && event.target === event.currentTarget) {
424
+ if (!shouldDisableDismiss && closeOnBackdrop && event.target === event.currentTarget) {
249
425
  onClose();
250
426
  }
251
427
  },
@@ -271,6 +447,7 @@ function StandardModal({
271
447
  maxWidth: isMaximized ? "100vw" : normalizeWidth(maxWidth),
272
448
  height: isMaximized ? "100vh" : void 0,
273
449
  maxHeight: isMaximized ? "100vh" : "calc(100vh - 32px)",
450
+ minWidth: isMaximized ? "100vw" : 300,
274
451
  borderRadius: isMaximized ? 0 : 30,
275
452
  border: `1px solid ${modalTheme.borderSoft}`,
276
453
  background: `linear-gradient(180deg, ${modalTheme.surfaceRaised}, ${modalTheme.colors.surface})`,
@@ -287,13 +464,23 @@ function StandardModal({
287
464
  display: "flex",
288
465
  alignItems: "flex-start",
289
466
  justifyContent: "space-between",
290
- gap: 16,
291
- padding: "24px 24px 16px",
467
+ gap: 12,
468
+ padding: "18px 20px 12px",
292
469
  borderBottom: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
293
470
  },
294
471
  children: [
295
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1 }, children: header }),
296
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
472
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
473
+ "div",
474
+ {
475
+ style: {
476
+ flex: 1,
477
+ opacity: isBusy ? 0.38 : 1,
478
+ transition: "opacity 180ms ease"
479
+ },
480
+ children: resolvedHeader
481
+ }
482
+ ),
483
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
297
484
  !hideExpandButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
298
485
  "button",
299
486
  {
@@ -302,8 +489,8 @@ function StandardModal({
302
489
  type: "button",
303
490
  onClick: () => setIsMaximized((current) => !current),
304
491
  style: {
305
- height: 42,
306
- width: 42,
492
+ height: 40,
493
+ width: 40,
307
494
  borderRadius: 999,
308
495
  border: `1px solid ${modalTheme.borderSoft}`,
309
496
  backgroundColor: "transparent",
@@ -320,17 +507,18 @@ function StandardModal({
320
507
  {
321
508
  "aria-label": "Close modal",
322
509
  type: "button",
323
- onClick: onClose,
510
+ onClick: shouldDisableDismiss ? void 0 : onClose,
324
511
  style: {
325
- height: 42,
326
- width: 42,
512
+ height: 40,
513
+ width: 40,
327
514
  borderRadius: 999,
328
515
  border: `1px solid ${modalTheme.borderSoft}`,
329
516
  backgroundColor: "transparent",
330
517
  color: modalTheme.colors.onSurface,
331
- cursor: "pointer",
518
+ cursor: shouldDisableDismiss ? "not-allowed" : "pointer",
332
519
  fontSize: 20,
333
- fontWeight: 700
520
+ fontWeight: 700,
521
+ opacity: shouldDisableDismiss ? 0.5 : 1
334
522
  },
335
523
  children: "\xD7"
336
524
  }
@@ -339,308 +527,61 @@ function StandardModal({
339
527
  ]
340
528
  }
341
529
  ),
342
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
530
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
343
531
  "div",
344
532
  {
345
533
  style: {
346
534
  flex: 1,
347
535
  minHeight: 0,
536
+ position: "relative",
348
537
  overflow: "auto",
349
- padding: 24
350
- },
351
- children
352
- }
353
- ),
354
- footer ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
355
- "div",
356
- {
357
- style: {
358
- display: "flex",
359
- justifyContent: "flex-end",
360
- gap: 12,
361
- padding: "16px 24px 24px",
362
- borderTop: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
363
- },
364
- children: footer
365
- }
366
- ) : null
367
- ]
368
- }
369
- )
370
- }
371
- );
372
- }
373
- function LegacyModal({
374
- title,
375
- showModal,
376
- closeModal,
377
- children,
378
- action,
379
- actionNameBtn,
380
- hideActionButton = false,
381
- cancelButton,
382
- disableActionBtn = false,
383
- isLoading = false,
384
- onlyCloseButton = false,
385
- hideCloseIcon = false,
386
- style,
387
- bodyStyle,
388
- additionalActions,
389
- maximized,
390
- theme
391
- }) {
392
- const modalTheme = (0, import_react.useMemo)(() => resolveTheme(theme), [theme]);
393
- const [isMaximized, setIsMaximized] = (0, import_react.useState)(maximized != null ? maximized : false);
394
- const resolvedAction = action != null ? action : (() => null);
395
- (0, import_react.useEffect)(() => {
396
- if (maximized === void 0 && isLikelyMobileViewport()) {
397
- setIsMaximized(true);
398
- }
399
- }, [maximized]);
400
- if (!showModal) {
401
- return null;
402
- }
403
- const actionButtons = () => {
404
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
405
- additionalActions == null ? void 0 : additionalActions.map((item) => {
406
- var _a, _b, _c;
407
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
408
- LegacyActionButton,
409
- {
410
- label: item.name,
411
- onClick: item.onClick,
412
- type: (_a = item.type) != null ? _a : "contained",
413
- style: (_b = item.style) != null ? _b : { maxWidth: "150px" },
414
- theme: modalTheme,
415
- disabled: (_c = item.disable) != null ? _c : disableActionBtn || isLoading
416
- },
417
- item.name
418
- );
419
- }),
420
- !hideActionButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
421
- LegacyActionButton,
422
- {
423
- label: actionNameBtn != null ? actionNameBtn : "Save",
424
- onClick: resolvedAction,
425
- type: "contained",
426
- style: { maxWidth: "100px" },
427
- theme: modalTheme,
428
- disabled: disableActionBtn || isLoading
429
- }
430
- ) : null
431
- ] });
432
- };
433
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
434
- "div",
435
- {
436
- "aria-labelledby": "modal-title",
437
- "aria-modal": "true",
438
- role: "dialog",
439
- style: {
440
- background: `${modalTheme.colors.background}90`,
441
- backdropFilter: "blur(2px)",
442
- width: "100%",
443
- height: "100%",
444
- position: "fixed",
445
- zIndex: 999,
446
- top: 0,
447
- left: 0,
448
- display: "flex",
449
- justifyContent: "center",
450
- alignItems: "center",
451
- boxSizing: "border-box"
452
- },
453
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
454
- "div",
455
- {
456
- id: isLoading ? "ldg1" : void 0,
457
- style: {
458
- position: isMaximized ? "fixed" : "relative",
459
- left: isMaximized ? 0 : void 0,
460
- top: isMaximized ? 0 : void 0,
461
- background: modalTheme.colors.background,
462
- display: "flex",
463
- alignItems: "center",
464
- flexDirection: "column",
465
- borderRadius: "0.8rem",
466
- boxSizing: "border-box",
467
- maxHeight: isMaximized ? "100vh" : "80vh",
468
- maxWidth: isMaximized ? "100vw" : "80vw",
469
- minWidth: isMaximized ? "100vw" : 300,
470
- minHeight: isMaximized ? "100vh" : void 0,
471
- width: isMaximized ? "100vw" : void 0,
472
- boxShadow: "0 24px 64px rgba(15, 23, 42, 0.18)",
473
- ...isLoading ? { opacity: 0.5 } : null,
474
- ...style
475
- },
476
- children: [
477
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
478
- "div",
479
- {
480
- style: {
481
- background: modalTheme.colors.surface,
482
- color: modalTheme.colors.onSurface,
483
- position: "absolute",
484
- top: 0,
485
- zIndex: 500,
486
- display: "flex",
487
- justifyContent: "space-between",
488
- alignItems: "center",
489
- width: "100%",
490
- height: "4rem",
491
- padding: "1rem",
492
- boxSizing: "border-box",
493
- borderTopLeftRadius: "0.8rem",
494
- borderTopRightRadius: "0.8rem",
495
- borderBottom: `1px solid ${withAlpha(modalTheme.colors.onBackground, 0.1)}`
538
+ padding: 24,
539
+ ...bodyStyle
496
540
  },
497
541
  children: [
498
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { id: "modal-title", style: { fontWeight: "bold", fontSize: "1.3rem" }, children: title }),
499
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
542
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
500
543
  "div",
501
544
  {
502
- id: "modal-header-icons",
503
- style: { display: "flex", alignItems: "center", gap: "0.5rem" },
504
- children: [
505
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
506
- "button",
507
- {
508
- "aria-label": isMaximized ? "Minimize modal" : "Maximize modal",
509
- title: isMaximized ? "Minimize" : "Maximize",
510
- type: "button",
511
- onClick: () => setIsMaximized((current) => !current),
512
- style: {
513
- border: "none",
514
- background: "transparent",
515
- color: modalTheme.colors.onSurface,
516
- cursor: "pointer",
517
- fontSize: 18,
518
- lineHeight: 1,
519
- padding: 0
520
- },
521
- children: isMaximized ? "\u25A2" : "\u25A1"
522
- }
523
- ),
524
- !hideCloseIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
525
- "button",
526
- {
527
- "aria-label": "Close modal",
528
- title: "Close",
529
- type: "button",
530
- onClick: isLoading ? void 0 : closeModal,
531
- style: {
532
- border: "none",
533
- background: "transparent",
534
- color: modalTheme.colors.onSurface,
535
- cursor: isLoading ? "not-allowed" : "pointer",
536
- fontSize: 22,
537
- lineHeight: 1,
538
- padding: 0,
539
- opacity: isLoading ? 0.5 : 1
540
- },
541
- children: "\xD7"
542
- }
543
- ) : null
544
- ]
545
+ style: {
546
+ opacity: isBusy ? 0.38 : 1,
547
+ filter: isBusy ? "saturate(0.8)" : "none",
548
+ pointerEvents: isBusy ? "none" : "auto",
549
+ transition: "opacity 180ms ease, filter 180ms ease"
550
+ },
551
+ children
545
552
  }
546
- )
553
+ ),
554
+ isBusy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
555
+ "div",
556
+ {
557
+ style: {
558
+ position: "absolute",
559
+ inset: 0,
560
+ display: "flex",
561
+ alignItems: "center",
562
+ justifyContent: "center",
563
+ backgroundColor: withAlpha(modalTheme.colors.surface, 0.58),
564
+ backdropFilter: "blur(2px)"
565
+ },
566
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalBusyIndicator, { theme: modalTheme })
567
+ }
568
+ ) : null
547
569
  ]
548
570
  }
549
571
  ),
550
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
551
- "div",
552
- {
553
- style: {
554
- scrollbarWidth: "thin",
555
- width: "100%",
556
- maxWidth: "100%",
557
- paddingTop: "4rem",
558
- paddingBottom: "4rem",
559
- overflow: "auto",
560
- ...bodyStyle
561
- },
562
- children
563
- }
564
- ),
565
- onlyCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
572
+ shouldRenderFooter ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
566
573
  "div",
567
574
  {
568
575
  style: {
569
- background: modalTheme.colors.surface,
570
- color: modalTheme.colors.onSurface,
571
- position: "absolute",
572
- bottom: 0,
573
- width: "100%",
574
- height: "4rem",
575
- padding: "0.5rem",
576
- borderTop: `1px solid ${withAlpha(modalTheme.colors.onBackground, 0.1)}`,
577
- boxSizing: "border-box",
578
- borderBottomLeftRadius: "0.8rem",
579
- borderBottomRightRadius: "0.8rem"
580
- },
581
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
582
- "div",
583
- {
584
- className: "buttons-footer",
585
- style: { flex: 1, display: "flex", justifyContent: "end" },
586
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
587
- LegacyActionButton,
588
- {
589
- label: "Close",
590
- onClick: closeModal,
591
- theme: modalTheme,
592
- disabled: isLoading
593
- }
594
- )
595
- }
596
- )
597
- }
598
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
599
- "div",
600
- {
601
- style: {
602
- background: modalTheme.colors.surface,
603
- color: modalTheme.colors.onSurface,
604
- position: "absolute",
605
- bottom: 0,
606
- width: "100%",
607
- height: "4rem",
608
- padding: "0.5rem",
609
- borderTop: `1px solid ${withAlpha(modalTheme.colors.onBackground, 0.1)}`,
610
- boxSizing: "border-box",
611
- borderBottomLeftRadius: "0.8rem",
612
- borderBottomRightRadius: "0.8rem"
576
+ display: "flex",
577
+ justifyContent: "flex-end",
578
+ gap: 10,
579
+ padding: "12px 20px 16px",
580
+ borderTop: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
613
581
  },
614
- children: cancelButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
615
- "div",
616
- {
617
- className: "buttons-footer",
618
- style: { flex: 1, display: "flex", justifyContent: "end" },
619
- children: [
620
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
621
- LegacyActionButton,
622
- {
623
- label: "Cancel",
624
- onClick: cancelButton,
625
- type: "text",
626
- style: { maxWidth: "100px" },
627
- theme: modalTheme,
628
- disabled: false
629
- }
630
- ),
631
- actionButtons()
632
- ]
633
- }
634
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
635
- "div",
636
- {
637
- className: "buttons-footer",
638
- style: { flex: 1, display: "flex", justifyContent: "end" },
639
- children: actionButtons()
640
- }
641
- )
582
+ children: footerContent
642
583
  }
643
- )
584
+ ) : null
644
585
  ]
645
586
  }
646
587
  )
@@ -648,10 +589,7 @@ function LegacyModal({
648
589
  );
649
590
  }
650
591
  function Modal(props) {
651
- if (isLegacyModalProps(props)) {
652
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LegacyModal, { ...props });
653
- }
654
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StandardModal, { ...props });
592
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnifiedModal, { ...normalizeModalProps(props) });
655
593
  }
656
594
  // Annotate the CommonJS export names for ESM import in node:
657
595
  0 && (module.exports = {