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/README.md +36 -24
- package/dist/chunk-YWH2VIAD.js +573 -0
- package/dist/chunk-YWH2VIAD.js.map +1 -0
- package/dist/index.cjs +2554 -674
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -42
- package/dist/index.d.ts +71 -42
- package/dist/index.js +2190 -237
- package/dist/index.js.map +1 -1
- package/dist/{modal-BDeh1TYW.d.cts → modal-B2lmASXk.d.cts} +31 -16
- package/dist/{modal-BDeh1TYW.d.ts → modal-B2lmASXk.d.ts} +31 -16
- package/dist/modal.cjs +293 -355
- package/dist/modal.cjs.map +1 -1
- package/dist/modal.d.cts +2 -2
- package/dist/modal.d.ts +2 -2
- package/dist/modal.js +1 -1
- package/package.json +6 -11
- package/dist/chunk-BI3QBKFG.js +0 -634
- package/dist/chunk-BI3QBKFG.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,29 +5,33 @@
|
|
|
5
5
|
It is designed for tenant developers who should not need to know how the core app is implemented.
|
|
6
6
|
The package stays on the public contract surface:
|
|
7
7
|
|
|
8
|
-
- theme-aware components powered by `smartsell-
|
|
8
|
+
- theme-aware components powered by `smartsell-theme`
|
|
9
9
|
- inline-style primitives that do not depend on private app CSS files
|
|
10
10
|
- a composable modal helper with predictable slot ids for `header`, `body`, and `footer`
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
npm install react smartsell-
|
|
15
|
+
npm install react smartsell-theme smartsell-ui-kit
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
If you want to connect `ComposableModal` to SmartSell slot overrides, install `smartsell-sales-sdk` as well.
|
|
19
|
+
|
|
18
20
|
## Basic button and card
|
|
19
21
|
|
|
20
22
|
```tsx
|
|
23
|
+
import { ThemeProvider } from 'smartsell-theme';
|
|
21
24
|
import { Button, Card } from 'smartsell-ui-kit';
|
|
22
|
-
import type { ModulePageProps } from 'smartsell-sales-sdk';
|
|
23
25
|
|
|
24
|
-
export default function ExamplePage(
|
|
26
|
+
export default function ExamplePage() {
|
|
25
27
|
return (
|
|
26
|
-
<
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
<ThemeProvider>
|
|
29
|
+
<Card title="Example" eyebrow="UI kit">
|
|
30
|
+
<Button onClick={() => window.history.back()}>
|
|
31
|
+
Go back
|
|
32
|
+
</Button>
|
|
33
|
+
</Card>
|
|
34
|
+
</ThemeProvider>
|
|
31
35
|
);
|
|
32
36
|
}
|
|
33
37
|
```
|
|
@@ -37,22 +41,30 @@ export default function ExamplePage({ sdk }: ModulePageProps) {
|
|
|
37
41
|
Use `ComposableModal` when you want the page to keep modal state while tenants customize visual sections independently.
|
|
38
42
|
|
|
39
43
|
```tsx
|
|
44
|
+
import { SlotRenderer, type ModulePageProps, type SlotComponentProps } from 'smartsell-sales-sdk';
|
|
40
45
|
import { ComposableModal, createModalSlotIds } from 'smartsell-ui-kit';
|
|
41
46
|
|
|
42
47
|
const slotIds = createModalSlotIds('order-review');
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
>
|
|
54
|
-
|
|
55
|
-
</
|
|
49
|
+
export default function ExamplePage({ sdk }: ModulePageProps) {
|
|
50
|
+
return (
|
|
51
|
+
<ComposableModal
|
|
52
|
+
isOpen={isOpen}
|
|
53
|
+
onClose={() => setIsOpen(false)}
|
|
54
|
+
onConfirm={submitOrder}
|
|
55
|
+
title="Order review"
|
|
56
|
+
slotBaseId="order-review"
|
|
57
|
+
renderSlot={({ id, context, children }) => (
|
|
58
|
+
<SlotRenderer id={id} sdk={sdk} context={context}>
|
|
59
|
+
{children}
|
|
60
|
+
</SlotRenderer>
|
|
61
|
+
)}
|
|
62
|
+
payload={{ orderNumber: 'SO-1001', total: 421.9 }}
|
|
63
|
+
>
|
|
64
|
+
<div>Default modal body</div>
|
|
65
|
+
</ComposableModal>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
56
68
|
```
|
|
57
69
|
|
|
58
70
|
Slot ids generated by `createModalSlotIds('order-review')`:
|
|
@@ -82,7 +94,7 @@ type OrderPayload = {
|
|
|
82
94
|
|
|
83
95
|
function CustomFooter({ sdk, context }: SlotComponentProps<ModalSlotContext<OrderPayload>>) {
|
|
84
96
|
return (
|
|
85
|
-
<Button
|
|
97
|
+
<Button onClick={() => context?.confirm?.()}>
|
|
86
98
|
Send order {context?.payload?.orderNumber}
|
|
87
99
|
</Button>
|
|
88
100
|
);
|
|
@@ -122,8 +134,8 @@ npm publish
|
|
|
122
134
|
The repository now includes a local Storybook workspace so you can inspect and interact with components before publishing the package.
|
|
123
135
|
|
|
124
136
|
- grouped sidebar navigation for buttons, surfaces, forms, and modals
|
|
125
|
-
- live Controls for component props such as size,
|
|
126
|
-
- a mocked `
|
|
137
|
+
- live Controls for component props such as size, variants, labels, states, and modal behaviors
|
|
138
|
+
- a mocked `ThemeProvider` so components render with the same theme contract used in host apps
|
|
127
139
|
|
|
128
140
|
Run it directly with npm:
|
|
129
141
|
|
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
// src/components/Modal.tsx
|
|
2
|
+
import { useEffect, useMemo, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// src/color.ts
|
|
5
|
+
function withAlpha(hex, alpha) {
|
|
6
|
+
const normalized = hex.replace("#", "").trim();
|
|
7
|
+
const value = normalized.length === 3 ? normalized.split("").map((char) => char + char).join("") : normalized;
|
|
8
|
+
const red = Number.parseInt(value.slice(0, 2), 16);
|
|
9
|
+
const green = Number.parseInt(value.slice(2, 4), 16);
|
|
10
|
+
const blue = Number.parseInt(value.slice(4, 6), 16);
|
|
11
|
+
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/components/Modal.tsx
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var defaultThemeColors = {
|
|
17
|
+
background: "#f8fafc",
|
|
18
|
+
surface: "#ffffff",
|
|
19
|
+
onSurface: "#0f172a",
|
|
20
|
+
onBackground: "#0f172a",
|
|
21
|
+
primary: "#0f766e",
|
|
22
|
+
onPrimary: "#ffffff",
|
|
23
|
+
secondary: "#1d4ed8",
|
|
24
|
+
onSecondary: "#ffffff",
|
|
25
|
+
negative: "#dc2626",
|
|
26
|
+
warning: "#d97706"
|
|
27
|
+
};
|
|
28
|
+
var srOnlyStyle = {
|
|
29
|
+
position: "absolute",
|
|
30
|
+
width: 1,
|
|
31
|
+
height: 1,
|
|
32
|
+
padding: 0,
|
|
33
|
+
margin: -1,
|
|
34
|
+
overflow: "hidden",
|
|
35
|
+
clip: "rect(0, 0, 0, 0)",
|
|
36
|
+
whiteSpace: "nowrap",
|
|
37
|
+
border: 0
|
|
38
|
+
};
|
|
39
|
+
var isUiKitThemeTokens = (theme) => {
|
|
40
|
+
return Boolean(theme && typeof theme === "object" && "theme" in theme);
|
|
41
|
+
};
|
|
42
|
+
var resolveTheme = (theme) => {
|
|
43
|
+
var _a;
|
|
44
|
+
const colorOverrides = isUiKitThemeTokens(theme) ? theme.theme.colors : (_a = theme == null ? void 0 : theme.colors) != null ? _a : {};
|
|
45
|
+
const colors = {
|
|
46
|
+
...defaultThemeColors,
|
|
47
|
+
...colorOverrides
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
colors,
|
|
51
|
+
borderSoft: isUiKitThemeTokens(theme) ? theme.borderSoft : withAlpha(colors.onSurface, 0.1),
|
|
52
|
+
borderStrong: isUiKitThemeTokens(theme) ? theme.borderStrong : withAlpha(colors.onSurface, 0.16),
|
|
53
|
+
surfaceMuted: isUiKitThemeTokens(theme) ? theme.surfaceMuted : withAlpha(colors.onSurface, 0.04),
|
|
54
|
+
surfaceRaised: isUiKitThemeTokens(theme) ? theme.surfaceRaised : withAlpha(colors.surface, 0.94),
|
|
55
|
+
overlay: isUiKitThemeTokens(theme) ? theme.overlay : withAlpha("#030712", 0.62),
|
|
56
|
+
mutedText: isUiKitThemeTokens(theme) ? theme.mutedText : withAlpha(colors.onSurface, 0.72)
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
var normalizeWidth = (maxWidth) => {
|
|
60
|
+
if (typeof maxWidth === "number") {
|
|
61
|
+
return `${maxWidth}px`;
|
|
62
|
+
}
|
|
63
|
+
return maxWidth != null ? maxWidth : "720px";
|
|
64
|
+
};
|
|
65
|
+
var isLikelyMobileViewport = () => {
|
|
66
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
70
|
+
navigator.userAgent
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
var createTitleId = (title) => {
|
|
74
|
+
if (typeof title === "string" || typeof title === "number") {
|
|
75
|
+
const normalized = String(title).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
76
|
+
return `smartsell-modal-${normalized || "dialog"}`;
|
|
77
|
+
}
|
|
78
|
+
return "smartsell-modal-dialog";
|
|
79
|
+
};
|
|
80
|
+
var isLegacyModalProps = (props) => {
|
|
81
|
+
return "showModal" in props;
|
|
82
|
+
};
|
|
83
|
+
var normalizeLegacyAction = (action, fallbackDisabled = false) => {
|
|
84
|
+
var _a, _b, _c;
|
|
85
|
+
return {
|
|
86
|
+
label: action.name,
|
|
87
|
+
onClick: action.onClick,
|
|
88
|
+
appearance: (_a = action.type) != null ? _a : "contained",
|
|
89
|
+
style: (_b = action.style) != null ? _b : { maxWidth: "150px" },
|
|
90
|
+
disabled: (_c = action.disable) != null ? _c : fallbackDisabled
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
var normalizeModalProps = (props) => {
|
|
94
|
+
var _a, _b;
|
|
95
|
+
if (!isLegacyModalProps(props)) {
|
|
96
|
+
return props;
|
|
97
|
+
}
|
|
98
|
+
const isBusy = Boolean(props.isLoading);
|
|
99
|
+
const disableAction = Boolean(props.disableActionBtn || props.isLoading);
|
|
100
|
+
return {
|
|
101
|
+
isOpen: props.showModal,
|
|
102
|
+
onClose: props.closeModal,
|
|
103
|
+
title: props.title,
|
|
104
|
+
children: props.children,
|
|
105
|
+
theme: props.theme,
|
|
106
|
+
maximized: props.maximized,
|
|
107
|
+
contentStyle: props.style,
|
|
108
|
+
bodyStyle: props.bodyStyle,
|
|
109
|
+
hideCloseButton: props.hideCloseIcon,
|
|
110
|
+
disableDismiss: isBusy,
|
|
111
|
+
closeOnBackdrop: false,
|
|
112
|
+
closeOnEscape: false,
|
|
113
|
+
isBusy,
|
|
114
|
+
closeAction: props.onlyCloseButton ? {
|
|
115
|
+
label: "Close",
|
|
116
|
+
onClick: props.closeModal,
|
|
117
|
+
appearance: "contained",
|
|
118
|
+
disabled: isBusy
|
|
119
|
+
} : void 0,
|
|
120
|
+
cancelAction: props.onlyCloseButton || !props.cancelButton ? void 0 : {
|
|
121
|
+
label: "Cancel",
|
|
122
|
+
onClick: props.cancelButton,
|
|
123
|
+
appearance: "text",
|
|
124
|
+
style: { maxWidth: "100px" }
|
|
125
|
+
},
|
|
126
|
+
confirmAction: props.onlyCloseButton || props.hideActionButton || !props.action ? void 0 : {
|
|
127
|
+
label: (_a = props.actionNameBtn) != null ? _a : "Save",
|
|
128
|
+
onClick: props.action,
|
|
129
|
+
appearance: "contained",
|
|
130
|
+
style: { maxWidth: "100px" },
|
|
131
|
+
disabled: disableAction
|
|
132
|
+
},
|
|
133
|
+
extraActions: props.onlyCloseButton ? void 0 : (_b = props.additionalActions) == null ? void 0 : _b.map((action) => normalizeLegacyAction(action, disableAction))
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
function ModalActionButton({
|
|
137
|
+
action,
|
|
138
|
+
theme
|
|
139
|
+
}) {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
const { colors } = theme;
|
|
142
|
+
const {
|
|
143
|
+
label,
|
|
144
|
+
onClick,
|
|
145
|
+
appearance = "contained",
|
|
146
|
+
disabled = false,
|
|
147
|
+
style
|
|
148
|
+
} = action;
|
|
149
|
+
const buttonStyle = {
|
|
150
|
+
width: "100%",
|
|
151
|
+
display: "flex",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
justifyContent: "center",
|
|
154
|
+
borderRadius: "0.4rem",
|
|
155
|
+
padding: appearance === "link" ? 0 : "0.9rem 1.15rem",
|
|
156
|
+
boxSizing: "border-box",
|
|
157
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
158
|
+
fontWeight: 700,
|
|
159
|
+
fontSize: "1.05rem",
|
|
160
|
+
lineHeight: 1.2,
|
|
161
|
+
margin: 0,
|
|
162
|
+
textAlign: "center",
|
|
163
|
+
transition: "0.5s",
|
|
164
|
+
opacity: disabled ? 0.5 : 1,
|
|
165
|
+
filter: disabled ? "saturate(0)" : void 0
|
|
166
|
+
};
|
|
167
|
+
if (appearance === "text") {
|
|
168
|
+
buttonStyle.background = "none";
|
|
169
|
+
buttonStyle.border = "1px solid transparent";
|
|
170
|
+
buttonStyle.color = colors.primary;
|
|
171
|
+
buttonStyle.boxShadow = "none";
|
|
172
|
+
} else if (appearance === "link") {
|
|
173
|
+
buttonStyle.background = "none";
|
|
174
|
+
buttonStyle.border = "none";
|
|
175
|
+
buttonStyle.color = colors.primary;
|
|
176
|
+
buttonStyle.boxShadow = "none";
|
|
177
|
+
} else if (appearance === "outlined") {
|
|
178
|
+
buttonStyle.background = "none";
|
|
179
|
+
buttonStyle.border = `2px solid ${colors.primary}`;
|
|
180
|
+
buttonStyle.color = colors.primary;
|
|
181
|
+
buttonStyle.boxShadow = `0 14px 28px ${withAlpha(colors.onSurface, 0.08)}`;
|
|
182
|
+
} else {
|
|
183
|
+
buttonStyle.background = colors.primary;
|
|
184
|
+
buttonStyle.border = "1px solid transparent";
|
|
185
|
+
buttonStyle.color = colors.onPrimary;
|
|
186
|
+
buttonStyle.boxShadow = `0 14px 28px ${withAlpha(colors.primary, 0.22)}`;
|
|
187
|
+
}
|
|
188
|
+
return /* @__PURE__ */ jsx(
|
|
189
|
+
"div",
|
|
190
|
+
{
|
|
191
|
+
style: {
|
|
192
|
+
width: (_a = style == null ? void 0 : style.width) != null ? _a : (style == null ? void 0 : style.maxWidth) ? "100%" : "max-content",
|
|
193
|
+
display: "flex",
|
|
194
|
+
alignItems: "center",
|
|
195
|
+
justifyContent: "center",
|
|
196
|
+
margin: 0,
|
|
197
|
+
marginBottom: (_b = style == null ? void 0 : style.marginBottom) != null ? _b : 0,
|
|
198
|
+
...style
|
|
199
|
+
},
|
|
200
|
+
children: /* @__PURE__ */ jsx(
|
|
201
|
+
"button",
|
|
202
|
+
{
|
|
203
|
+
type: "button",
|
|
204
|
+
onClick: disabled ? void 0 : onClick,
|
|
205
|
+
disabled,
|
|
206
|
+
style: buttonStyle,
|
|
207
|
+
children: label
|
|
208
|
+
}
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function ModalBusyIndicator({
|
|
214
|
+
theme
|
|
215
|
+
}) {
|
|
216
|
+
return /* @__PURE__ */ jsxs(
|
|
217
|
+
"div",
|
|
218
|
+
{
|
|
219
|
+
"aria-live": "polite",
|
|
220
|
+
role: "status",
|
|
221
|
+
style: {
|
|
222
|
+
position: "relative",
|
|
223
|
+
display: "inline-flex",
|
|
224
|
+
alignItems: "center",
|
|
225
|
+
justifyContent: "center",
|
|
226
|
+
width: 56,
|
|
227
|
+
height: 56,
|
|
228
|
+
borderRadius: 999,
|
|
229
|
+
backgroundColor: withAlpha(theme.colors.surface, 0.88),
|
|
230
|
+
boxShadow: `0 18px 36px ${withAlpha(theme.colors.onSurface, 0.08)}`
|
|
231
|
+
},
|
|
232
|
+
children: [
|
|
233
|
+
/* @__PURE__ */ jsx("span", { style: srOnlyStyle, children: "Loading" }),
|
|
234
|
+
/* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", width: "32", height: "32", viewBox: "0 0 40 40", fill: "none", children: [
|
|
235
|
+
/* @__PURE__ */ jsx(
|
|
236
|
+
"circle",
|
|
237
|
+
{
|
|
238
|
+
cx: "20",
|
|
239
|
+
cy: "20",
|
|
240
|
+
r: "16",
|
|
241
|
+
stroke: withAlpha(theme.colors.onSurface, 0.12),
|
|
242
|
+
strokeWidth: "4"
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
/* @__PURE__ */ jsx(
|
|
246
|
+
"path",
|
|
247
|
+
{
|
|
248
|
+
d: "M20 4C28.837 4 36 11.163 36 20",
|
|
249
|
+
stroke: theme.colors.primary,
|
|
250
|
+
strokeWidth: "4",
|
|
251
|
+
strokeLinecap: "round",
|
|
252
|
+
children: /* @__PURE__ */ jsx(
|
|
253
|
+
"animateTransform",
|
|
254
|
+
{
|
|
255
|
+
attributeName: "transform",
|
|
256
|
+
type: "rotate",
|
|
257
|
+
from: "0 20 20",
|
|
258
|
+
to: "360 20 20",
|
|
259
|
+
dur: "0.75s",
|
|
260
|
+
repeatCount: "indefinite"
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
] })
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
function UnifiedModal({
|
|
271
|
+
isOpen,
|
|
272
|
+
onClose,
|
|
273
|
+
children,
|
|
274
|
+
title,
|
|
275
|
+
headerContent,
|
|
276
|
+
footer,
|
|
277
|
+
confirmAction,
|
|
278
|
+
cancelAction,
|
|
279
|
+
closeAction,
|
|
280
|
+
extraActions,
|
|
281
|
+
maxWidth,
|
|
282
|
+
closeOnBackdrop = true,
|
|
283
|
+
closeOnEscape = true,
|
|
284
|
+
hideCloseButton = false,
|
|
285
|
+
hideExpandButton = false,
|
|
286
|
+
disableDismiss = false,
|
|
287
|
+
maximized,
|
|
288
|
+
contentStyle,
|
|
289
|
+
bodyStyle,
|
|
290
|
+
isBusy = false,
|
|
291
|
+
theme
|
|
292
|
+
}) {
|
|
293
|
+
var _a, _b;
|
|
294
|
+
const modalTheme = useMemo(() => resolveTheme(theme), [theme]);
|
|
295
|
+
const [isMaximized, setIsMaximized] = useState(maximized != null ? maximized : false);
|
|
296
|
+
const titleId = useMemo(() => createTitleId(title), [title]);
|
|
297
|
+
const shouldDisableDismiss = disableDismiss || isBusy;
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
if (typeof maximized === "boolean") {
|
|
300
|
+
setIsMaximized(maximized);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (isLikelyMobileViewport()) {
|
|
304
|
+
setIsMaximized(true);
|
|
305
|
+
}
|
|
306
|
+
}, [maximized]);
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (!isOpen || typeof window === "undefined" || typeof document === "undefined") {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const previousOverflow = document.body.style.overflow;
|
|
312
|
+
document.body.style.overflow = "hidden";
|
|
313
|
+
const handleKeyDown = (event) => {
|
|
314
|
+
if (!shouldDisableDismiss && closeOnEscape && event.key === "Escape") {
|
|
315
|
+
onClose();
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
319
|
+
return () => {
|
|
320
|
+
document.body.style.overflow = previousOverflow;
|
|
321
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
322
|
+
};
|
|
323
|
+
}, [closeOnEscape, isOpen, onClose, shouldDisableDismiss]);
|
|
324
|
+
if (!isOpen) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
const resolvedHeader = headerContent != null ? headerContent : title ? /* @__PURE__ */ jsx(
|
|
328
|
+
"h2",
|
|
329
|
+
{
|
|
330
|
+
id: titleId,
|
|
331
|
+
style: {
|
|
332
|
+
margin: 0,
|
|
333
|
+
color: modalTheme.colors.onSurface,
|
|
334
|
+
fontSize: 30,
|
|
335
|
+
fontWeight: 800,
|
|
336
|
+
lineHeight: 1.1
|
|
337
|
+
},
|
|
338
|
+
children: title
|
|
339
|
+
}
|
|
340
|
+
) : null;
|
|
341
|
+
let footerContent = footer;
|
|
342
|
+
if (footerContent === void 0) {
|
|
343
|
+
if (closeAction && !closeAction.hidden) {
|
|
344
|
+
footerContent = /* @__PURE__ */ jsx(
|
|
345
|
+
ModalActionButton,
|
|
346
|
+
{
|
|
347
|
+
action: { ...closeAction, disabled: closeAction.disabled || isBusy },
|
|
348
|
+
theme: modalTheme
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
} else {
|
|
352
|
+
const resolvedActions = [
|
|
353
|
+
cancelAction ? {
|
|
354
|
+
...cancelAction,
|
|
355
|
+
appearance: (_a = cancelAction.appearance) != null ? _a : "text",
|
|
356
|
+
disabled: cancelAction.disabled || isBusy
|
|
357
|
+
} : void 0,
|
|
358
|
+
...(extraActions != null ? extraActions : []).map((action) => {
|
|
359
|
+
var _a2;
|
|
360
|
+
return {
|
|
361
|
+
...action,
|
|
362
|
+
appearance: (_a2 = action.appearance) != null ? _a2 : "contained",
|
|
363
|
+
disabled: action.disabled || isBusy
|
|
364
|
+
};
|
|
365
|
+
}),
|
|
366
|
+
confirmAction ? {
|
|
367
|
+
...confirmAction,
|
|
368
|
+
appearance: (_b = confirmAction.appearance) != null ? _b : "contained",
|
|
369
|
+
disabled: confirmAction.disabled || isBusy
|
|
370
|
+
} : void 0
|
|
371
|
+
].reduce((items, action) => {
|
|
372
|
+
if (!action || action.hidden) {
|
|
373
|
+
return items;
|
|
374
|
+
}
|
|
375
|
+
items.push(action);
|
|
376
|
+
return items;
|
|
377
|
+
}, []);
|
|
378
|
+
footerContent = resolvedActions.length > 0 ? resolvedActions.map((action, index) => /* @__PURE__ */ jsx(
|
|
379
|
+
ModalActionButton,
|
|
380
|
+
{
|
|
381
|
+
action,
|
|
382
|
+
theme: modalTheme
|
|
383
|
+
},
|
|
384
|
+
`modal-action-${index}`
|
|
385
|
+
)) : void 0;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const shouldRenderFooter = footerContent !== void 0 && footerContent !== null && footerContent !== false;
|
|
389
|
+
return /* @__PURE__ */ jsx(
|
|
390
|
+
"div",
|
|
391
|
+
{
|
|
392
|
+
"aria-label": headerContent ? typeof title === "string" ? title : "Dialog" : void 0,
|
|
393
|
+
"aria-labelledby": headerContent ? void 0 : title ? titleId : void 0,
|
|
394
|
+
"aria-busy": isBusy,
|
|
395
|
+
"aria-modal": "true",
|
|
396
|
+
role: "dialog",
|
|
397
|
+
onMouseDown: (event) => {
|
|
398
|
+
if (!shouldDisableDismiss && closeOnBackdrop && event.target === event.currentTarget) {
|
|
399
|
+
onClose();
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
style: {
|
|
403
|
+
position: "fixed",
|
|
404
|
+
inset: 0,
|
|
405
|
+
zIndex: 70,
|
|
406
|
+
display: "flex",
|
|
407
|
+
alignItems: "center",
|
|
408
|
+
justifyContent: "center",
|
|
409
|
+
padding: isMaximized ? 0 : 16,
|
|
410
|
+
backgroundColor: modalTheme.overlay,
|
|
411
|
+
backdropFilter: "blur(8px)"
|
|
412
|
+
},
|
|
413
|
+
children: /* @__PURE__ */ jsxs(
|
|
414
|
+
"div",
|
|
415
|
+
{
|
|
416
|
+
style: {
|
|
417
|
+
position: "relative",
|
|
418
|
+
display: "flex",
|
|
419
|
+
flexDirection: "column",
|
|
420
|
+
width: isMaximized ? "100vw" : "min(100%, 100%)",
|
|
421
|
+
maxWidth: isMaximized ? "100vw" : normalizeWidth(maxWidth),
|
|
422
|
+
height: isMaximized ? "100vh" : void 0,
|
|
423
|
+
maxHeight: isMaximized ? "100vh" : "calc(100vh - 32px)",
|
|
424
|
+
minWidth: isMaximized ? "100vw" : 300,
|
|
425
|
+
borderRadius: isMaximized ? 0 : 30,
|
|
426
|
+
border: `1px solid ${modalTheme.borderSoft}`,
|
|
427
|
+
background: `linear-gradient(180deg, ${modalTheme.surfaceRaised}, ${modalTheme.colors.surface})`,
|
|
428
|
+
boxShadow: `0 34px 80px ${withAlpha("#020617", 0.28)}`,
|
|
429
|
+
color: modalTheme.colors.onSurface,
|
|
430
|
+
overflow: "hidden",
|
|
431
|
+
...contentStyle
|
|
432
|
+
},
|
|
433
|
+
children: [
|
|
434
|
+
/* @__PURE__ */ jsxs(
|
|
435
|
+
"div",
|
|
436
|
+
{
|
|
437
|
+
style: {
|
|
438
|
+
display: "flex",
|
|
439
|
+
alignItems: "flex-start",
|
|
440
|
+
justifyContent: "space-between",
|
|
441
|
+
gap: 12,
|
|
442
|
+
padding: "18px 20px 12px",
|
|
443
|
+
borderBottom: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
|
|
444
|
+
},
|
|
445
|
+
children: [
|
|
446
|
+
/* @__PURE__ */ jsx(
|
|
447
|
+
"div",
|
|
448
|
+
{
|
|
449
|
+
style: {
|
|
450
|
+
flex: 1,
|
|
451
|
+
opacity: isBusy ? 0.38 : 1,
|
|
452
|
+
transition: "opacity 180ms ease"
|
|
453
|
+
},
|
|
454
|
+
children: resolvedHeader
|
|
455
|
+
}
|
|
456
|
+
),
|
|
457
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
458
|
+
!hideExpandButton ? /* @__PURE__ */ jsx(
|
|
459
|
+
"button",
|
|
460
|
+
{
|
|
461
|
+
"aria-label": isMaximized ? "Minimize modal" : "Maximize modal",
|
|
462
|
+
title: isMaximized ? "Minimize" : "Maximize",
|
|
463
|
+
type: "button",
|
|
464
|
+
onClick: () => setIsMaximized((current) => !current),
|
|
465
|
+
style: {
|
|
466
|
+
height: 40,
|
|
467
|
+
width: 40,
|
|
468
|
+
borderRadius: 999,
|
|
469
|
+
border: `1px solid ${modalTheme.borderSoft}`,
|
|
470
|
+
backgroundColor: "transparent",
|
|
471
|
+
color: modalTheme.colors.onSurface,
|
|
472
|
+
cursor: "pointer",
|
|
473
|
+
fontSize: 18,
|
|
474
|
+
fontWeight: 700
|
|
475
|
+
},
|
|
476
|
+
children: isMaximized ? "\u25A2" : "\u25A1"
|
|
477
|
+
}
|
|
478
|
+
) : null,
|
|
479
|
+
!hideCloseButton ? /* @__PURE__ */ jsx(
|
|
480
|
+
"button",
|
|
481
|
+
{
|
|
482
|
+
"aria-label": "Close modal",
|
|
483
|
+
type: "button",
|
|
484
|
+
onClick: shouldDisableDismiss ? void 0 : onClose,
|
|
485
|
+
style: {
|
|
486
|
+
height: 40,
|
|
487
|
+
width: 40,
|
|
488
|
+
borderRadius: 999,
|
|
489
|
+
border: `1px solid ${modalTheme.borderSoft}`,
|
|
490
|
+
backgroundColor: "transparent",
|
|
491
|
+
color: modalTheme.colors.onSurface,
|
|
492
|
+
cursor: shouldDisableDismiss ? "not-allowed" : "pointer",
|
|
493
|
+
fontSize: 20,
|
|
494
|
+
fontWeight: 700,
|
|
495
|
+
opacity: shouldDisableDismiss ? 0.5 : 1
|
|
496
|
+
},
|
|
497
|
+
children: "\xD7"
|
|
498
|
+
}
|
|
499
|
+
) : null
|
|
500
|
+
] })
|
|
501
|
+
]
|
|
502
|
+
}
|
|
503
|
+
),
|
|
504
|
+
/* @__PURE__ */ jsxs(
|
|
505
|
+
"div",
|
|
506
|
+
{
|
|
507
|
+
style: {
|
|
508
|
+
flex: 1,
|
|
509
|
+
minHeight: 0,
|
|
510
|
+
position: "relative",
|
|
511
|
+
overflow: "auto",
|
|
512
|
+
padding: 24,
|
|
513
|
+
...bodyStyle
|
|
514
|
+
},
|
|
515
|
+
children: [
|
|
516
|
+
/* @__PURE__ */ jsx(
|
|
517
|
+
"div",
|
|
518
|
+
{
|
|
519
|
+
style: {
|
|
520
|
+
opacity: isBusy ? 0.38 : 1,
|
|
521
|
+
filter: isBusy ? "saturate(0.8)" : "none",
|
|
522
|
+
pointerEvents: isBusy ? "none" : "auto",
|
|
523
|
+
transition: "opacity 180ms ease, filter 180ms ease"
|
|
524
|
+
},
|
|
525
|
+
children
|
|
526
|
+
}
|
|
527
|
+
),
|
|
528
|
+
isBusy ? /* @__PURE__ */ jsx(
|
|
529
|
+
"div",
|
|
530
|
+
{
|
|
531
|
+
style: {
|
|
532
|
+
position: "absolute",
|
|
533
|
+
inset: 0,
|
|
534
|
+
display: "flex",
|
|
535
|
+
alignItems: "center",
|
|
536
|
+
justifyContent: "center",
|
|
537
|
+
backgroundColor: withAlpha(modalTheme.colors.surface, 0.58),
|
|
538
|
+
backdropFilter: "blur(2px)"
|
|
539
|
+
},
|
|
540
|
+
children: /* @__PURE__ */ jsx(ModalBusyIndicator, { theme: modalTheme })
|
|
541
|
+
}
|
|
542
|
+
) : null
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
shouldRenderFooter ? /* @__PURE__ */ jsx(
|
|
547
|
+
"div",
|
|
548
|
+
{
|
|
549
|
+
style: {
|
|
550
|
+
display: "flex",
|
|
551
|
+
justifyContent: "flex-end",
|
|
552
|
+
gap: 10,
|
|
553
|
+
padding: "12px 20px 16px",
|
|
554
|
+
borderTop: `1px solid ${withAlpha(modalTheme.colors.onSurface, 0.06)}`
|
|
555
|
+
},
|
|
556
|
+
children: footerContent
|
|
557
|
+
}
|
|
558
|
+
) : null
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
)
|
|
562
|
+
}
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
function Modal(props) {
|
|
566
|
+
return /* @__PURE__ */ jsx(UnifiedModal, { ...normalizeModalProps(props) });
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export {
|
|
570
|
+
withAlpha,
|
|
571
|
+
Modal
|
|
572
|
+
};
|
|
573
|
+
//# sourceMappingURL=chunk-YWH2VIAD.js.map
|