smartsell-ui-kit 0.0.1

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/index.js ADDED
@@ -0,0 +1,662 @@
1
+ // src/components/Button.tsx
2
+ import { withAlpha as withAlpha2 } from "smartsell-sales-sdk";
3
+
4
+ // src/theme.ts
5
+ import { useMemo } from "react";
6
+ import {
7
+ useSalesTheme,
8
+ withAlpha
9
+ } from "smartsell-sales-sdk";
10
+ function useUiKitTheme(sdk) {
11
+ const { theme } = useSalesTheme(sdk);
12
+ return useMemo(() => {
13
+ return {
14
+ theme,
15
+ borderSoft: withAlpha(theme.colors.onSurface, 0.1),
16
+ borderStrong: withAlpha(theme.colors.onSurface, 0.16),
17
+ surfaceMuted: withAlpha(theme.colors.onSurface, 0.04),
18
+ surfaceRaised: withAlpha(theme.colors.surface, 0.94),
19
+ overlay: withAlpha("#030712", 0.62),
20
+ focusRing: withAlpha(theme.colors.primary, 0.22),
21
+ mutedText: withAlpha(theme.colors.onSurface, 0.72)
22
+ };
23
+ }, [theme]);
24
+ }
25
+
26
+ // src/components/Button.tsx
27
+ import { jsxs } from "react/jsx-runtime";
28
+ var getSizeStyles = (size) => {
29
+ if (size === "sm") {
30
+ return { minHeight: 38, padding: "0 14px", fontSize: 13 };
31
+ }
32
+ if (size === "lg") {
33
+ return { minHeight: 50, padding: "0 20px", fontSize: 15 };
34
+ }
35
+ return { minHeight: 44, padding: "0 18px", fontSize: 14 };
36
+ };
37
+ function Button({
38
+ sdk,
39
+ variant = "solid",
40
+ tone = "primary",
41
+ size = "md",
42
+ fullWidth = false,
43
+ leadingIcon,
44
+ trailingIcon,
45
+ children,
46
+ disabled,
47
+ style,
48
+ type = "button",
49
+ ...rest
50
+ }) {
51
+ const { theme } = useUiKitTheme(sdk);
52
+ const palette = {
53
+ primary: {
54
+ background: theme.colors.primary,
55
+ foreground: theme.colors.onPrimary,
56
+ border: withAlpha2(theme.colors.primary, 0.3)
57
+ },
58
+ secondary: {
59
+ background: theme.colors.secondary,
60
+ foreground: theme.colors.onSecondary,
61
+ border: withAlpha2(theme.colors.secondary, 0.3)
62
+ },
63
+ neutral: {
64
+ background: theme.colors.surface,
65
+ foreground: theme.colors.onSurface,
66
+ border: withAlpha2(theme.colors.onSurface, 0.16)
67
+ },
68
+ danger: {
69
+ background: theme.colors.negative,
70
+ foreground: "#ffffff",
71
+ border: withAlpha2(theme.colors.negative, 0.32)
72
+ }
73
+ }[tone];
74
+ const variantStyles = {
75
+ solid: {
76
+ backgroundColor: palette.background,
77
+ borderColor: palette.border,
78
+ color: palette.foreground
79
+ },
80
+ outline: {
81
+ backgroundColor: "transparent",
82
+ borderColor: palette.border,
83
+ color: tone === "neutral" ? palette.foreground : palette.background
84
+ },
85
+ ghost: {
86
+ backgroundColor: "transparent",
87
+ borderColor: "transparent",
88
+ color: tone === "neutral" ? palette.foreground : palette.background
89
+ }
90
+ };
91
+ return /* @__PURE__ */ jsxs(
92
+ "button",
93
+ {
94
+ ...rest,
95
+ type,
96
+ disabled,
97
+ style: {
98
+ display: "inline-flex",
99
+ alignItems: "center",
100
+ justifyContent: "center",
101
+ gap: 10,
102
+ width: fullWidth ? "100%" : void 0,
103
+ borderRadius: 16,
104
+ borderStyle: "solid",
105
+ borderWidth: 1,
106
+ cursor: disabled ? "not-allowed" : "pointer",
107
+ fontWeight: 700,
108
+ letterSpacing: "0.01em",
109
+ lineHeight: 1,
110
+ opacity: disabled ? 0.58 : 1,
111
+ transition: "transform 160ms ease, opacity 160ms ease, background-color 160ms ease",
112
+ boxShadow: variant === "solid" ? `0 14px 28px ${withAlpha2(palette.background, 0.18)}` : "none",
113
+ ...getSizeStyles(size),
114
+ ...variantStyles[variant],
115
+ ...style
116
+ },
117
+ children: [
118
+ leadingIcon,
119
+ children,
120
+ trailingIcon
121
+ ]
122
+ }
123
+ );
124
+ }
125
+
126
+ // src/components/Card.tsx
127
+ import { withAlpha as withAlpha3 } from "smartsell-sales-sdk";
128
+ import { jsx, jsxs as jsxs2 } from "react/jsx-runtime";
129
+ var getToneStyles = (tone, sdk) => {
130
+ const { theme } = useUiKitTheme(sdk);
131
+ const accent = {
132
+ default: theme.colors.primary,
133
+ primary: theme.colors.primary,
134
+ secondary: theme.colors.secondary,
135
+ warning: theme.colors.warning
136
+ }[tone];
137
+ return {
138
+ accent,
139
+ background: `linear-gradient(160deg, ${withAlpha3(theme.colors.surface, 0.98)}, ${withAlpha3(accent, 0.08)})`,
140
+ border: withAlpha3(accent, 0.22)
141
+ };
142
+ };
143
+ function Card({
144
+ sdk,
145
+ children,
146
+ eyebrow,
147
+ title,
148
+ action,
149
+ tone = "default",
150
+ padded = true,
151
+ style,
152
+ ...rest
153
+ }) {
154
+ const { theme, mutedText } = useUiKitTheme(sdk);
155
+ const toneStyles = getToneStyles(tone, sdk);
156
+ return /* @__PURE__ */ jsxs2(
157
+ "div",
158
+ {
159
+ ...rest,
160
+ style: {
161
+ borderRadius: 28,
162
+ border: `1px solid ${toneStyles.border}`,
163
+ background: toneStyles.background,
164
+ color: theme.colors.onSurface,
165
+ boxShadow: `0 24px 48px ${withAlpha3(theme.colors.onSurface, 0.06)}`,
166
+ padding: padded ? 24 : void 0,
167
+ ...style
168
+ },
169
+ children: [
170
+ (eyebrow || title || action) && /* @__PURE__ */ jsxs2(
171
+ "div",
172
+ {
173
+ style: {
174
+ display: "flex",
175
+ justifyContent: "space-between",
176
+ alignItems: "flex-start",
177
+ gap: 16,
178
+ marginBottom: 18
179
+ },
180
+ children: [
181
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
182
+ eyebrow ? /* @__PURE__ */ jsx(
183
+ "span",
184
+ {
185
+ style: {
186
+ color: toneStyles.accent,
187
+ fontSize: 12,
188
+ fontWeight: 800,
189
+ letterSpacing: "0.16em",
190
+ textTransform: "uppercase"
191
+ },
192
+ children: eyebrow
193
+ }
194
+ ) : null,
195
+ title ? /* @__PURE__ */ jsx(
196
+ "div",
197
+ {
198
+ style: {
199
+ color: theme.colors.onSurface,
200
+ fontSize: 24,
201
+ fontWeight: 700,
202
+ lineHeight: 1.2
203
+ },
204
+ children: title
205
+ }
206
+ ) : null
207
+ ] }),
208
+ action ? /* @__PURE__ */ jsx("div", { style: { color: mutedText }, children: action }) : null
209
+ ]
210
+ }
211
+ ),
212
+ children
213
+ ]
214
+ }
215
+ );
216
+ }
217
+
218
+ // src/components/ComposableModal.tsx
219
+ import { useMemo as useMemo3 } from "react";
220
+ import { SlotRenderer } from "smartsell-sales-sdk";
221
+
222
+ // src/components/Modal.tsx
223
+ import { useEffect, useMemo as useMemo2 } from "react";
224
+ import { withAlpha as withAlpha4 } from "smartsell-sales-sdk";
225
+ import { jsx as jsx2, jsxs as jsxs3 } from "react/jsx-runtime";
226
+ var normalizeWidth = (maxWidth) => {
227
+ if (typeof maxWidth === "number") {
228
+ return `${maxWidth}px`;
229
+ }
230
+ return maxWidth != null ? maxWidth : "720px";
231
+ };
232
+ function Modal({
233
+ sdk,
234
+ isOpen,
235
+ onClose,
236
+ children,
237
+ footer,
238
+ title,
239
+ description,
240
+ headerContent,
241
+ maxWidth,
242
+ closeOnBackdrop = true,
243
+ closeOnEscape = true,
244
+ hideCloseButton = false,
245
+ contentStyle
246
+ }) {
247
+ const { theme, borderSoft, overlay, surfaceRaised, mutedText } = useUiKitTheme(sdk);
248
+ const titleId = useMemo2(
249
+ () => `smartsell-modal-${String(title != null ? title : "dialog").toLowerCase().replace(/[^a-z0-9]+/g, "-")}`,
250
+ [title]
251
+ );
252
+ useEffect(() => {
253
+ if (!isOpen || typeof window === "undefined" || typeof document === "undefined") {
254
+ return;
255
+ }
256
+ const previousOverflow = document.body.style.overflow;
257
+ document.body.style.overflow = "hidden";
258
+ const handleKeyDown = (event) => {
259
+ if (closeOnEscape && event.key === "Escape") {
260
+ onClose();
261
+ }
262
+ };
263
+ window.addEventListener("keydown", handleKeyDown);
264
+ return () => {
265
+ document.body.style.overflow = previousOverflow;
266
+ window.removeEventListener("keydown", handleKeyDown);
267
+ };
268
+ }, [closeOnEscape, isOpen, onClose]);
269
+ if (!isOpen) {
270
+ return null;
271
+ }
272
+ const header = headerContent != null ? headerContent : /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
273
+ title ? /* @__PURE__ */ jsx2(
274
+ "h2",
275
+ {
276
+ id: titleId,
277
+ style: {
278
+ margin: 0,
279
+ color: theme.colors.onSurface,
280
+ fontSize: 30,
281
+ fontWeight: 800,
282
+ lineHeight: 1.1
283
+ },
284
+ children: title
285
+ }
286
+ ) : null,
287
+ description ? /* @__PURE__ */ jsx2(
288
+ "p",
289
+ {
290
+ style: {
291
+ margin: 0,
292
+ color: mutedText,
293
+ fontSize: 15,
294
+ lineHeight: 1.6
295
+ },
296
+ children: description
297
+ }
298
+ ) : null
299
+ ] });
300
+ return /* @__PURE__ */ jsx2(
301
+ "div",
302
+ {
303
+ "aria-labelledby": title ? titleId : void 0,
304
+ "aria-modal": "true",
305
+ role: "dialog",
306
+ onMouseDown: (event) => {
307
+ if (closeOnBackdrop && event.target === event.currentTarget) {
308
+ onClose();
309
+ }
310
+ },
311
+ style: {
312
+ position: "fixed",
313
+ inset: 0,
314
+ zIndex: 70,
315
+ display: "flex",
316
+ alignItems: "center",
317
+ justifyContent: "center",
318
+ padding: 16,
319
+ backgroundColor: overlay,
320
+ backdropFilter: "blur(8px)"
321
+ },
322
+ children: /* @__PURE__ */ jsxs3(
323
+ "div",
324
+ {
325
+ style: {
326
+ width: "min(100%, 100%)",
327
+ maxWidth: normalizeWidth(maxWidth),
328
+ borderRadius: 30,
329
+ border: `1px solid ${borderSoft}`,
330
+ background: `linear-gradient(180deg, ${surfaceRaised}, ${theme.colors.surface})`,
331
+ boxShadow: `0 34px 80px ${withAlpha4("#020617", 0.28)}`,
332
+ color: theme.colors.onSurface,
333
+ overflow: "hidden",
334
+ ...contentStyle
335
+ },
336
+ children: [
337
+ /* @__PURE__ */ jsxs3(
338
+ "div",
339
+ {
340
+ style: {
341
+ display: "flex",
342
+ alignItems: "flex-start",
343
+ justifyContent: "space-between",
344
+ gap: 16,
345
+ padding: "24px 24px 0"
346
+ },
347
+ children: [
348
+ /* @__PURE__ */ jsx2("div", { style: { flex: 1 }, children: header }),
349
+ !hideCloseButton ? /* @__PURE__ */ jsx2(
350
+ "button",
351
+ {
352
+ "aria-label": "Close modal",
353
+ type: "button",
354
+ onClick: onClose,
355
+ style: {
356
+ height: 42,
357
+ width: 42,
358
+ borderRadius: 999,
359
+ border: `1px solid ${borderSoft}`,
360
+ backgroundColor: "transparent",
361
+ color: theme.colors.onSurface,
362
+ cursor: "pointer",
363
+ fontSize: 20,
364
+ fontWeight: 700
365
+ },
366
+ children: "\xD7"
367
+ }
368
+ ) : null
369
+ ]
370
+ }
371
+ ),
372
+ /* @__PURE__ */ jsx2("div", { style: { padding: 24 }, children }),
373
+ footer ? /* @__PURE__ */ jsx2(
374
+ "div",
375
+ {
376
+ style: {
377
+ display: "flex",
378
+ justifyContent: "flex-end",
379
+ gap: 12,
380
+ padding: "0 24px 24px",
381
+ borderTop: `1px solid ${withAlpha4(theme.colors.onSurface, 0.06)}`
382
+ },
383
+ children: footer
384
+ }
385
+ ) : null
386
+ ]
387
+ }
388
+ )
389
+ }
390
+ );
391
+ }
392
+
393
+ // src/components/ComposableModal.tsx
394
+ import { Fragment, jsx as jsx3, jsxs as jsxs4 } from "react/jsx-runtime";
395
+ var createModalSlotIds = (slotBaseId) => ({
396
+ header: `${slotBaseId}:modal-header`,
397
+ body: `${slotBaseId}:modal-body`,
398
+ footer: `${slotBaseId}:modal-footer`
399
+ });
400
+ function ComposableModal({
401
+ sdk,
402
+ isOpen,
403
+ onClose,
404
+ title,
405
+ description,
406
+ slotBaseId,
407
+ payload,
408
+ onConfirm,
409
+ confirmLabel = "Confirm",
410
+ cancelLabel = "Cancel",
411
+ isBusy = false,
412
+ closeOnBackdrop = true,
413
+ closeOnEscape = true,
414
+ hideDefaultFooter = false,
415
+ maxWidth,
416
+ headerFallback,
417
+ footerFallback,
418
+ children
419
+ }) {
420
+ const slotIds = createModalSlotIds(slotBaseId);
421
+ const context = useMemo3(
422
+ () => ({
423
+ title,
424
+ description,
425
+ payload,
426
+ close: onClose,
427
+ confirm: onConfirm,
428
+ confirmLabel,
429
+ cancelLabel,
430
+ isOpen,
431
+ isBusy
432
+ }),
433
+ [cancelLabel, confirmLabel, description, isBusy, isOpen, onClose, onConfirm, payload, title]
434
+ );
435
+ const defaultFooter = hideDefaultFooter ? void 0 : footerFallback != null ? footerFallback : /* @__PURE__ */ jsxs4(Fragment, { children: [
436
+ /* @__PURE__ */ jsx3(Button, { sdk, variant: "outline", tone: "neutral", onClick: onClose, disabled: isBusy, children: cancelLabel }),
437
+ onConfirm ? /* @__PURE__ */ jsx3(Button, { sdk, onClick: onConfirm, disabled: isBusy, children: confirmLabel }) : null
438
+ ] });
439
+ const headerContent = /* @__PURE__ */ jsx3(SlotRenderer, { id: slotIds.header, sdk, context, children: headerFallback });
440
+ const bodyContent = /* @__PURE__ */ jsx3(SlotRenderer, { id: slotIds.body, sdk, context, children });
441
+ const footerContent = /* @__PURE__ */ jsx3(SlotRenderer, { id: slotIds.footer, sdk, context, children: defaultFooter });
442
+ return /* @__PURE__ */ jsx3(
443
+ Modal,
444
+ {
445
+ sdk,
446
+ isOpen,
447
+ onClose,
448
+ title,
449
+ description,
450
+ headerContent,
451
+ footer: footerContent,
452
+ maxWidth,
453
+ closeOnBackdrop,
454
+ closeOnEscape,
455
+ children: bodyContent
456
+ }
457
+ );
458
+ }
459
+
460
+ // src/components/Field.tsx
461
+ import { jsx as jsx4, jsxs as jsxs5 } from "react/jsx-runtime";
462
+ function Field({
463
+ sdk,
464
+ label,
465
+ hint,
466
+ error,
467
+ htmlFor,
468
+ required = false,
469
+ children,
470
+ style
471
+ }) {
472
+ const { theme, mutedText } = useUiKitTheme(sdk);
473
+ return /* @__PURE__ */ jsxs5(
474
+ "label",
475
+ {
476
+ htmlFor,
477
+ style: {
478
+ display: "flex",
479
+ flexDirection: "column",
480
+ gap: 8,
481
+ width: "100%",
482
+ ...style
483
+ },
484
+ children: [
485
+ (label || hint) && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
486
+ label ? /* @__PURE__ */ jsxs5(
487
+ "span",
488
+ {
489
+ style: {
490
+ color: theme.colors.onSurface,
491
+ fontSize: 14,
492
+ fontWeight: 700,
493
+ letterSpacing: "0.01em"
494
+ },
495
+ children: [
496
+ label,
497
+ required ? /* @__PURE__ */ jsx4("span", { style: { color: theme.colors.negative, marginLeft: 4 }, children: "*" }) : null
498
+ ]
499
+ }
500
+ ) : null,
501
+ hint ? /* @__PURE__ */ jsx4(
502
+ "span",
503
+ {
504
+ style: {
505
+ color: mutedText,
506
+ fontSize: 13,
507
+ lineHeight: 1.45
508
+ },
509
+ children: hint
510
+ }
511
+ ) : null
512
+ ] }),
513
+ children,
514
+ error ? /* @__PURE__ */ jsx4(
515
+ "span",
516
+ {
517
+ style: {
518
+ color: theme.colors.negative,
519
+ fontSize: 13,
520
+ fontWeight: 600,
521
+ lineHeight: 1.45
522
+ },
523
+ children: error
524
+ }
525
+ ) : null
526
+ ]
527
+ }
528
+ );
529
+ }
530
+
531
+ // src/components/Input.tsx
532
+ import { withAlpha as withAlpha5 } from "smartsell-sales-sdk";
533
+ import { jsx as jsx5 } from "react/jsx-runtime";
534
+ var getPadding = (size) => {
535
+ if (size === "sm") return "10px 12px";
536
+ if (size === "lg") return "16px 18px";
537
+ return "13px 16px";
538
+ };
539
+ function Input({
540
+ sdk,
541
+ label,
542
+ hint,
543
+ error,
544
+ controlSize = "md",
545
+ id,
546
+ disabled,
547
+ style,
548
+ ...rest
549
+ }) {
550
+ const { theme, borderSoft, focusRing, surfaceMuted } = useUiKitTheme(sdk);
551
+ const inputStyle = {
552
+ width: "100%",
553
+ borderRadius: 16,
554
+ border: `1px solid ${error ? theme.colors.negative : borderSoft}`,
555
+ padding: getPadding(controlSize),
556
+ outline: "none",
557
+ color: theme.colors.onSurface,
558
+ backgroundColor: disabled ? surfaceMuted : theme.colors.surface,
559
+ boxShadow: error ? `0 0 0 3px ${withAlpha5(theme.colors.negative, 0.12)}` : `0 0 0 0 ${focusRing}`,
560
+ transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
561
+ ...style
562
+ };
563
+ const input = /* @__PURE__ */ jsx5("input", { ...rest, id, disabled, style: inputStyle });
564
+ if (!label && !hint && !error) {
565
+ return input;
566
+ }
567
+ return /* @__PURE__ */ jsx5(Field, { sdk, label, hint, error, htmlFor: id, children: input });
568
+ }
569
+
570
+ // src/components/Select.tsx
571
+ import { withAlpha as withAlpha6 } from "smartsell-sales-sdk";
572
+ import { jsx as jsx6 } from "react/jsx-runtime";
573
+ var getPadding2 = (size) => {
574
+ if (size === "sm") return "10px 12px";
575
+ if (size === "lg") return "16px 18px";
576
+ return "13px 16px";
577
+ };
578
+ function Select({
579
+ sdk,
580
+ label,
581
+ hint,
582
+ error,
583
+ controlSize = "md",
584
+ id,
585
+ disabled,
586
+ style,
587
+ children,
588
+ ...rest
589
+ }) {
590
+ const { theme, borderSoft, focusRing, surfaceMuted } = useUiKitTheme(sdk);
591
+ const selectStyle = {
592
+ width: "100%",
593
+ borderRadius: 16,
594
+ border: `1px solid ${error ? theme.colors.negative : borderSoft}`,
595
+ padding: getPadding2(controlSize),
596
+ outline: "none",
597
+ color: theme.colors.onSurface,
598
+ backgroundColor: disabled ? surfaceMuted : theme.colors.surface,
599
+ boxShadow: error ? `0 0 0 3px ${withAlpha6(theme.colors.negative, 0.12)}` : `0 0 0 0 ${focusRing}`,
600
+ transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
601
+ ...style
602
+ };
603
+ const select = /* @__PURE__ */ jsx6("select", { ...rest, id, disabled, style: selectStyle, children });
604
+ if (!label && !hint && !error) {
605
+ return select;
606
+ }
607
+ return /* @__PURE__ */ jsx6(Field, { sdk, label, hint, error, htmlFor: id, children: select });
608
+ }
609
+
610
+ // src/components/Textarea.tsx
611
+ import { withAlpha as withAlpha7 } from "smartsell-sales-sdk";
612
+ import { jsx as jsx7 } from "react/jsx-runtime";
613
+ var getPadding3 = (size) => {
614
+ if (size === "sm") return "10px 12px";
615
+ if (size === "lg") return "16px 18px";
616
+ return "13px 16px";
617
+ };
618
+ function Textarea({
619
+ sdk,
620
+ label,
621
+ hint,
622
+ error,
623
+ controlSize = "md",
624
+ id,
625
+ disabled,
626
+ style,
627
+ rows = 5,
628
+ ...rest
629
+ }) {
630
+ const { theme, borderSoft, focusRing, surfaceMuted } = useUiKitTheme(sdk);
631
+ const textareaStyle = {
632
+ width: "100%",
633
+ borderRadius: 16,
634
+ border: `1px solid ${error ? theme.colors.negative : borderSoft}`,
635
+ padding: getPadding3(controlSize),
636
+ outline: "none",
637
+ color: theme.colors.onSurface,
638
+ backgroundColor: disabled ? surfaceMuted : theme.colors.surface,
639
+ boxShadow: error ? `0 0 0 3px ${withAlpha7(theme.colors.negative, 0.12)}` : `0 0 0 0 ${focusRing}`,
640
+ transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
641
+ resize: "vertical",
642
+ ...style
643
+ };
644
+ const textarea = /* @__PURE__ */ jsx7("textarea", { ...rest, id, disabled, rows, style: textareaStyle });
645
+ if (!label && !hint && !error) {
646
+ return textarea;
647
+ }
648
+ return /* @__PURE__ */ jsx7(Field, { sdk, label, hint, error, htmlFor: id, children: textarea });
649
+ }
650
+ export {
651
+ Button,
652
+ Card,
653
+ ComposableModal,
654
+ Field,
655
+ Input,
656
+ Modal,
657
+ Select,
658
+ Textarea,
659
+ createModalSlotIds,
660
+ useUiKitTheme
661
+ };
662
+ //# sourceMappingURL=index.js.map