smartsell-ui-kit 0.0.4 → 0.0.6

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
@@ -81,26 +81,89 @@ var isLikelyMobileViewport = () => {
81
81
  navigator.userAgent
82
82
  );
83
83
  };
84
+ var createTitleId = (title) => {
85
+ if (typeof title === "string" || typeof title === "number") {
86
+ const normalized = String(title).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
87
+ return `smartsell-modal-${normalized || "dialog"}`;
88
+ }
89
+ return "smartsell-modal-dialog";
90
+ };
84
91
  var isLegacyModalProps = (props) => {
85
92
  return "showModal" in props;
86
93
  };
87
- function LegacyActionButton({
88
- label,
89
- onClick,
90
- disabled,
91
- type = "contained",
92
- theme,
93
- style
94
+ var normalizeLegacyAction = (action, fallbackDisabled = false) => {
95
+ var _a, _b, _c;
96
+ return {
97
+ label: action.name,
98
+ onClick: action.onClick,
99
+ appearance: (_a = action.type) != null ? _a : "contained",
100
+ style: (_b = action.style) != null ? _b : { maxWidth: "150px" },
101
+ disabled: (_c = action.disable) != null ? _c : fallbackDisabled
102
+ };
103
+ };
104
+ var normalizeModalProps = (props) => {
105
+ var _a, _b;
106
+ if (!isLegacyModalProps(props)) {
107
+ return props;
108
+ }
109
+ const isBusy = Boolean(props.isLoading);
110
+ const disableAction = Boolean(props.disableActionBtn || props.isLoading);
111
+ return {
112
+ isOpen: props.showModal,
113
+ onClose: props.closeModal,
114
+ title: props.title,
115
+ children: props.children,
116
+ theme: props.theme,
117
+ maximized: props.maximized,
118
+ contentStyle: props.style,
119
+ bodyStyle: props.bodyStyle,
120
+ hideCloseButton: props.hideCloseIcon,
121
+ disableDismiss: isBusy,
122
+ closeOnBackdrop: false,
123
+ closeOnEscape: false,
124
+ isBusy,
125
+ closeAction: props.onlyCloseButton ? {
126
+ label: "Close",
127
+ onClick: props.closeModal,
128
+ appearance: "contained",
129
+ disabled: isBusy
130
+ } : void 0,
131
+ cancelAction: props.onlyCloseButton || !props.cancelButton ? void 0 : {
132
+ label: "Cancel",
133
+ onClick: props.cancelButton,
134
+ appearance: "text",
135
+ style: { maxWidth: "100px" }
136
+ },
137
+ confirmAction: props.onlyCloseButton || props.hideActionButton || !props.action ? void 0 : {
138
+ label: (_a = props.actionNameBtn) != null ? _a : "Save",
139
+ onClick: props.action,
140
+ appearance: "contained",
141
+ style: { maxWidth: "100px" },
142
+ disabled: disableAction
143
+ },
144
+ extraActions: props.onlyCloseButton ? void 0 : (_b = props.additionalActions) == null ? void 0 : _b.map((action) => normalizeLegacyAction(action, disableAction))
145
+ };
146
+ };
147
+ function ModalActionButton({
148
+ action,
149
+ theme
94
150
  }) {
95
151
  var _a, _b;
96
152
  const { colors } = theme;
153
+ const {
154
+ label,
155
+ onClick,
156
+ appearance = "contained",
157
+ disabled = false,
158
+ style
159
+ } = action;
97
160
  const buttonStyle = {
98
161
  width: "100%",
99
162
  display: "flex",
100
163
  alignItems: "center",
101
164
  justifyContent: "center",
102
165
  borderRadius: "0.4rem",
103
- padding: type === "link" ? 0 : "1.3rem",
166
+ padding: appearance === "link" ? 0 : "1.3rem",
104
167
  boxSizing: "border-box",
105
168
  cursor: disabled ? "not-allowed" : "pointer",
106
169
  fontWeight: 700,
@@ -111,17 +174,17 @@ function LegacyActionButton({
111
174
  opacity: disabled ? 0.5 : 1,
112
175
  filter: disabled ? "saturate(0)" : void 0
113
176
  };
114
- if (type === "text") {
177
+ if (appearance === "text") {
115
178
  buttonStyle.background = "none";
116
179
  buttonStyle.border = "1px solid transparent";
117
180
  buttonStyle.color = colors.primary;
118
181
  buttonStyle.boxShadow = "none";
119
- } else if (type === "link") {
182
+ } else if (appearance === "link") {
120
183
  buttonStyle.background = "none";
121
184
  buttonStyle.border = "none";
122
185
  buttonStyle.color = colors.primary;
123
186
  buttonStyle.boxShadow = "none";
124
- } else if (type === "outlined") {
187
+ } else if (appearance === "outlined") {
125
188
  buttonStyle.background = "none";
126
189
  buttonStyle.border = `2px solid ${colors.primary}`;
127
190
  buttonStyle.color = colors.primary;
@@ -157,29 +220,34 @@ function LegacyActionButton({
157
220
  }
158
221
  );
159
222
  }
160
- function StandardModal({
223
+ function UnifiedModal({
161
224
  isOpen,
162
225
  onClose,
163
226
  children,
164
- footer,
165
227
  title,
166
228
  description,
167
229
  headerContent,
230
+ footer,
231
+ confirmAction,
232
+ cancelAction,
233
+ closeAction,
234
+ extraActions,
168
235
  maxWidth,
169
236
  closeOnBackdrop = true,
170
237
  closeOnEscape = true,
171
238
  hideCloseButton = false,
172
239
  hideExpandButton = false,
240
+ disableDismiss = false,
173
241
  maximized,
174
242
  contentStyle,
243
+ bodyStyle,
244
+ isBusy = false,
175
245
  theme
176
246
  }) {
247
+ var _a, _b;
177
248
  const modalTheme = (0, import_react.useMemo)(() => resolveTheme(theme), [theme]);
178
249
  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
- );
250
+ const titleId = (0, import_react.useMemo)(() => createTitleId(title), [title]);
183
251
  (0, import_react.useEffect)(() => {
184
252
  if (typeof maximized === "boolean") {
185
253
  setIsMaximized(maximized);
@@ -196,7 +264,7 @@ function StandardModal({
196
264
  const previousOverflow = document.body.style.overflow;
197
265
  document.body.style.overflow = "hidden";
198
266
  const handleKeyDown = (event) => {
199
- if (closeOnEscape && event.key === "Escape") {
267
+ if (!disableDismiss && closeOnEscape && event.key === "Escape") {
200
268
  onClose();
201
269
  }
202
270
  };
@@ -205,11 +273,11 @@ function StandardModal({
205
273
  document.body.style.overflow = previousOverflow;
206
274
  window.removeEventListener("keydown", handleKeyDown);
207
275
  };
208
- }, [closeOnEscape, isOpen, onClose]);
276
+ }, [closeOnEscape, disableDismiss, isOpen, onClose]);
209
277
  if (!isOpen) {
210
278
  return null;
211
279
  }
212
- const header = headerContent != null ? headerContent : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
280
+ const resolvedHeader = headerContent != null ? headerContent : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
213
281
  title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
214
282
  "h2",
215
283
  {
@@ -237,6 +305,39 @@ function StandardModal({
237
305
  }
238
306
  ) : null
239
307
  ] });
308
+ let footerContent = footer;
309
+ if (footerContent === void 0) {
310
+ if (closeAction && !closeAction.hidden) {
311
+ footerContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalActionButton, { action: closeAction, theme: modalTheme });
312
+ } else {
313
+ const resolvedActions = [
314
+ cancelAction ? { ...cancelAction, appearance: (_a = cancelAction.appearance) != null ? _a : "text" } : void 0,
315
+ ...(extraActions != null ? extraActions : []).map((action) => {
316
+ var _a2;
317
+ return {
318
+ ...action,
319
+ appearance: (_a2 = action.appearance) != null ? _a2 : "contained"
320
+ };
321
+ }),
322
+ confirmAction ? { ...confirmAction, appearance: (_b = confirmAction.appearance) != null ? _b : "contained" } : void 0
323
+ ].reduce((items, action) => {
324
+ if (!action || action.hidden) {
325
+ return items;
326
+ }
327
+ items.push(action);
328
+ return items;
329
+ }, []);
330
+ footerContent = resolvedActions.length > 0 ? resolvedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
331
+ ModalActionButton,
332
+ {
333
+ action,
334
+ theme: modalTheme
335
+ },
336
+ `modal-action-${index}`
337
+ )) : void 0;
338
+ }
339
+ }
340
+ const shouldRenderFooter = footerContent !== void 0 && footerContent !== null && footerContent !== false;
240
341
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
241
342
  "div",
242
343
  {
@@ -245,7 +346,7 @@ function StandardModal({
245
346
  "aria-modal": "true",
246
347
  role: "dialog",
247
348
  onMouseDown: (event) => {
248
- if (closeOnBackdrop && event.target === event.currentTarget) {
349
+ if (!disableDismiss && closeOnBackdrop && event.target === event.currentTarget) {
249
350
  onClose();
250
351
  }
251
352
  },
@@ -263,6 +364,7 @@ function StandardModal({
263
364
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
264
365
  "div",
265
366
  {
367
+ id: isBusy ? "ldg1" : void 0,
266
368
  style: {
267
369
  position: "relative",
268
370
  display: "flex",
@@ -271,12 +373,14 @@ function StandardModal({
271
373
  maxWidth: isMaximized ? "100vw" : normalizeWidth(maxWidth),
272
374
  height: isMaximized ? "100vh" : void 0,
273
375
  maxHeight: isMaximized ? "100vh" : "calc(100vh - 32px)",
376
+ minWidth: isMaximized ? "100vw" : 300,
274
377
  borderRadius: isMaximized ? 0 : 30,
275
378
  border: `1px solid ${modalTheme.borderSoft}`,
276
379
  background: `linear-gradient(180deg, ${modalTheme.surfaceRaised}, ${modalTheme.colors.surface})`,
277
380
  boxShadow: `0 34px 80px ${withAlpha("#020617", 0.28)}`,
278
381
  color: modalTheme.colors.onSurface,
279
382
  overflow: "hidden",
383
+ opacity: isBusy ? 0.5 : 1,
280
384
  ...contentStyle
281
385
  },
282
386
  children: [
@@ -292,7 +396,7 @@ function StandardModal({
292
396
  borderBottom: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
293
397
  },
294
398
  children: [
295
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1 }, children: header }),
399
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1 }, children: resolvedHeader }),
296
400
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
297
401
  !hideExpandButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
298
402
  "button",
@@ -320,7 +424,7 @@ function StandardModal({
320
424
  {
321
425
  "aria-label": "Close modal",
322
426
  type: "button",
323
- onClick: onClose,
427
+ onClick: disableDismiss ? void 0 : onClose,
324
428
  style: {
325
429
  height: 42,
326
430
  width: 42,
@@ -328,9 +432,10 @@ function StandardModal({
328
432
  border: `1px solid ${modalTheme.borderSoft}`,
329
433
  backgroundColor: "transparent",
330
434
  color: modalTheme.colors.onSurface,
331
- cursor: "pointer",
435
+ cursor: disableDismiss ? "not-allowed" : "pointer",
332
436
  fontSize: 20,
333
- fontWeight: 700
437
+ fontWeight: 700,
438
+ opacity: disableDismiss ? 0.5 : 1
334
439
  },
335
440
  children: "\xD7"
336
441
  }
@@ -346,12 +451,13 @@ function StandardModal({
346
451
  flex: 1,
347
452
  minHeight: 0,
348
453
  overflow: "auto",
349
- padding: 24
454
+ padding: 24,
455
+ ...bodyStyle
350
456
  },
351
457
  children
352
458
  }
353
459
  ),
354
- footer ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
460
+ shouldRenderFooter ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
355
461
  "div",
356
462
  {
357
463
  style: {
@@ -361,7 +467,7 @@ function StandardModal({
361
467
  padding: "16px 24px 24px",
362
468
  borderTop: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
363
469
  },
364
- children: footer
470
+ children: footerContent
365
471
  }
366
472
  ) : null
367
473
  ]
@@ -370,288 +476,8 @@ function StandardModal({
370
476
  }
371
477
  );
372
478
  }
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)}`
496
- },
497
- 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)(
500
- "div",
501
- {
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
- }
546
- )
547
- ]
548
- }
549
- ),
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)(
566
- "div",
567
- {
568
- 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"
613
- },
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
- )
642
- }
643
- )
644
- ]
645
- }
646
- )
647
- }
648
- );
649
- }
650
479
  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 });
480
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnifiedModal, { ...normalizeModalProps(props) });
655
481
  }
656
482
  // Annotate the CommonJS export names for ESM import in node:
657
483
  0 && (module.exports = {