smartsell-ui-kit 0.0.5 → 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/index.cjs CHANGED
@@ -23,7 +23,6 @@ __export(index_exports, {
23
23
  Button: () => Button,
24
24
  Card: () => Card,
25
25
  ComposableModal: () => ComposableModal,
26
- Field: () => Field,
27
26
  Input: () => Input,
28
27
  Modal: () => Modal,
29
28
  Select: () => Select,
@@ -37,6 +36,63 @@ module.exports = __toCommonJS(index_exports);
37
36
  var import_react2 = require("react");
38
37
  var import_smartsell_sales_sdk2 = require("smartsell-sales-sdk");
39
38
 
39
+ // src/components/controlSize.ts
40
+ var CONTROL_METRICS_BY_SIZE = {
41
+ sm: {
42
+ height: 30,
43
+ fontSize: 13,
44
+ lineHeight: "16px",
45
+ paddingX: 12,
46
+ paddingY: 6,
47
+ buttonPaddingX: 14,
48
+ selectPaddingRight: 40,
49
+ selectIndicatorOffset: 12
50
+ },
51
+ md: {
52
+ height: 38,
53
+ fontSize: 14,
54
+ lineHeight: "18px",
55
+ paddingX: 16,
56
+ paddingY: 9,
57
+ buttonPaddingX: 18,
58
+ selectPaddingRight: 44,
59
+ selectIndicatorOffset: 16
60
+ },
61
+ lg: {
62
+ height: 46,
63
+ fontSize: 15,
64
+ lineHeight: "18px",
65
+ paddingX: 18,
66
+ paddingY: 13,
67
+ buttonPaddingX: 20,
68
+ selectPaddingRight: 48,
69
+ selectIndicatorOffset: 18
70
+ }
71
+ };
72
+ var getControlMetrics = (size) => CONTROL_METRICS_BY_SIZE[size];
73
+ var getTextInputPadding = (size, options = {}) => {
74
+ var _a, _b;
75
+ const metrics = getControlMetrics(size);
76
+ const leadingInset = (_a = options.leadingInset) != null ? _a : 0;
77
+ const trailingInset = (_b = options.trailingInset) != null ? _b : 0;
78
+ return `${metrics.paddingY}px ${metrics.paddingX + trailingInset}px ${metrics.paddingY}px ${metrics.paddingX + leadingInset}px`;
79
+ };
80
+ var getSelectControlPadding = (size) => {
81
+ const metrics = getControlMetrics(size);
82
+ return `${metrics.paddingY}px ${metrics.selectPaddingRight}px ${metrics.paddingY}px ${metrics.paddingX}px`;
83
+ };
84
+ var getSelectIndicatorOffset = (size) => getControlMetrics(size).selectIndicatorOffset;
85
+ var getButtonSizeStyles = (size) => {
86
+ const metrics = getControlMetrics(size);
87
+ return {
88
+ boxSizing: "border-box",
89
+ height: metrics.height,
90
+ padding: `0 ${metrics.buttonPaddingX}px`,
91
+ fontSize: metrics.fontSize,
92
+ lineHeight: metrics.lineHeight
93
+ };
94
+ };
95
+
40
96
  // src/theme.ts
41
97
  var import_react = require("react");
42
98
  var import_smartsell_sales_sdk = require("smartsell-sales-sdk");
@@ -58,19 +114,9 @@ function useUiKitTheme(sdk) {
58
114
 
59
115
  // src/components/Button.tsx
60
116
  var import_jsx_runtime = require("react/jsx-runtime");
61
- var getSizeStyles = (size) => {
62
- if (size === "sm") {
63
- return { minHeight: 38, padding: "0 14px", fontSize: 13 };
64
- }
65
- if (size === "lg") {
66
- return { minHeight: 50, padding: "0 20px", fontSize: 15 };
67
- }
68
- return { minHeight: 44, padding: "0 18px", fontSize: 14 };
69
- };
70
117
  function Button({
71
118
  sdk,
72
119
  variant = "solid",
73
- tone = "primary",
74
120
  size = "md",
75
121
  fullWidth = false,
76
122
  leadingIcon,
@@ -94,57 +140,35 @@ function Button({
94
140
  const { theme } = useUiKitTheme(sdk);
95
141
  const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
96
142
  const [isPressed, setIsPressed] = (0, import_react2.useState)(false);
97
- const palette = {
98
- primary: {
99
- background: theme.colors.primary,
100
- foreground: theme.colors.onPrimary,
101
- border: (0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.primary, 0.3)
102
- },
103
- secondary: {
104
- background: theme.colors.secondary,
105
- foreground: theme.colors.onSecondary,
106
- border: (0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.secondary, 0.3)
107
- },
108
- neutral: {
109
- background: theme.colors.surface,
110
- foreground: theme.colors.onSurface,
111
- border: (0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.onSurface, 0.16)
112
- },
113
- danger: {
114
- background: theme.colors.negative,
115
- foreground: "#ffffff",
116
- border: (0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.negative, 0.32)
117
- }
118
- }[tone];
119
143
  const variantStyles = {
120
144
  solid: {
121
- backgroundColor: palette.background,
122
- borderColor: palette.border,
123
- color: palette.foreground
145
+ backgroundColor: theme.colors.primary,
146
+ borderColor: (0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.primary, 0.5),
147
+ color: theme.colors.onPrimary
124
148
  },
125
149
  outline: {
126
150
  backgroundColor: "transparent",
127
- borderColor: palette.border,
128
- color: tone === "neutral" ? palette.foreground : palette.background
151
+ borderColor: (0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.text, 0.5),
152
+ color: theme.colors.onSurface
129
153
  },
130
154
  ghost: {
131
155
  backgroundColor: "transparent",
132
156
  borderColor: "transparent",
133
- color: tone === "neutral" ? palette.foreground : palette.background
157
+ color: theme.colors.onSurface
134
158
  }
135
159
  };
136
- const interactiveColor = tone === "neutral" ? palette.foreground : palette.background;
160
+ const interactiveColor = variant === "solid" ? theme.colors.primary : theme.colors.onSurface;
137
161
  const isInteractive = !disabled;
138
162
  const interactionStyles = {
139
163
  solid: {
140
164
  transform: isPressed ? "translateY(1px) scale(0.985)" : isHovered ? "translateY(-1px)" : "translateY(0)",
141
- boxShadow: isPressed ? `0 8px 16px ${(0, import_smartsell_sales_sdk2.withAlpha)(palette.background, 0.2)}` : isHovered ? `0 18px 36px ${(0, import_smartsell_sales_sdk2.withAlpha)(palette.background, 0.26)}` : `0 14px 28px ${(0, import_smartsell_sales_sdk2.withAlpha)(palette.background, 0.18)}`,
142
- filter: isPressed ? "brightness(0.95)" : isHovered ? "brightness(1.03)" : void 0
165
+ boxShadow: "none",
166
+ filter: void 0
143
167
  },
144
168
  outline: {
145
169
  transform: isPressed ? "translateY(1px) scale(0.985)" : isHovered ? "translateY(-1px)" : "translateY(0)",
146
170
  backgroundColor: isPressed ? (0, import_smartsell_sales_sdk2.withAlpha)(interactiveColor, 0.14) : isHovered ? (0, import_smartsell_sales_sdk2.withAlpha)(interactiveColor, 0.08) : "transparent",
147
- boxShadow: isPressed ? `0 6px 12px ${(0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.onSurface, 0.08)}` : isHovered ? `0 12px 24px ${(0, import_smartsell_sales_sdk2.withAlpha)(theme.colors.onSurface, 0.08)}` : "none"
171
+ boxShadow: "none"
148
172
  },
149
173
  ghost: {
150
174
  transform: isPressed ? "translateY(1px) scale(0.985)" : isHovered ? "translateY(-1px)" : "translateY(0)",
@@ -220,10 +244,9 @@ function Button({
220
244
  cursor: disabled ? "not-allowed" : "pointer",
221
245
  fontWeight: 700,
222
246
  letterSpacing: "0.01em",
223
- lineHeight: 1,
224
247
  opacity: disabled ? 0.58 : 1,
225
- transition: "transform 140ms ease, opacity 160ms ease, background-color 160ms ease, box-shadow 160ms ease, filter 160ms ease",
226
- ...getSizeStyles(size),
248
+ transition: "transform 140ms ease, opacity 160ms ease, background-color 160ms ease",
249
+ ...getButtonSizeStyles(size),
227
250
  ...variantStyles[variant],
228
251
  ...isInteractive ? interactionStyles[variant] : void 0,
229
252
  ...style
@@ -240,43 +263,26 @@ function Button({
240
263
  // src/components/Card.tsx
241
264
  var import_smartsell_sales_sdk3 = require("smartsell-sales-sdk");
242
265
  var import_jsx_runtime2 = require("react/jsx-runtime");
243
- var getToneStyles = (tone, sdk) => {
244
- const { theme } = useUiKitTheme(sdk);
245
- const accent = {
246
- default: theme.colors.primary,
247
- primary: theme.colors.primary,
248
- secondary: theme.colors.secondary,
249
- warning: theme.colors.warning
250
- }[tone];
251
- return {
252
- accent,
253
- background: `linear-gradient(160deg, ${(0, import_smartsell_sales_sdk3.withAlpha)(theme.colors.surface, 0.98)}, ${(0, import_smartsell_sales_sdk3.withAlpha)(accent, 0.08)})`,
254
- border: (0, import_smartsell_sales_sdk3.withAlpha)(accent, 0.22)
255
- };
256
- };
257
266
  function Card({
258
267
  sdk,
259
268
  children,
260
269
  eyebrow,
261
270
  title,
262
271
  action,
263
- tone = "default",
264
272
  padded = true,
265
273
  style,
266
274
  ...rest
267
275
  }) {
268
- const { theme, mutedText } = useUiKitTheme(sdk);
269
- const toneStyles = getToneStyles(tone, sdk);
276
+ const { theme } = useUiKitTheme(sdk);
270
277
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
271
278
  "div",
272
279
  {
273
280
  ...rest,
274
281
  style: {
275
282
  borderRadius: 28,
276
- border: `1px solid ${toneStyles.border}`,
277
- background: toneStyles.background,
278
- color: theme.colors.onSurface,
279
- boxShadow: `0 24px 48px ${(0, import_smartsell_sales_sdk3.withAlpha)(theme.colors.onSurface, 0.06)}`,
283
+ border: `1px solid ${(0, import_smartsell_sales_sdk3.withAlpha)(theme.colors.text, 0.5)}`,
284
+ background: `${(0, import_smartsell_sales_sdk3.withAlpha)(theme.colors.background, 0.7)}`,
285
+ color: theme.colors.text,
280
286
  padding: padded ? 24 : void 0,
281
287
  ...style
282
288
  },
@@ -297,7 +303,7 @@ function Card({
297
303
  "span",
298
304
  {
299
305
  style: {
300
- color: toneStyles.accent,
306
+ color: theme.colors.textLight,
301
307
  fontSize: 12,
302
308
  fontWeight: 800,
303
309
  letterSpacing: "0.16em",
@@ -310,7 +316,7 @@ function Card({
310
316
  "div",
311
317
  {
312
318
  style: {
313
- color: theme.colors.onSurface,
319
+ color: theme.colors.text,
314
320
  fontSize: 24,
315
321
  fontWeight: 700,
316
322
  lineHeight: 1.2
@@ -319,7 +325,7 @@ function Card({
319
325
  }
320
326
  ) : null
321
327
  ] }),
322
- action ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: mutedText }, children: action }) : null
328
+ action ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: theme.colors.text }, children: action }) : null
323
329
  ]
324
330
  }
325
331
  ),
@@ -390,26 +396,89 @@ var isLikelyMobileViewport = () => {
390
396
  navigator.userAgent
391
397
  );
392
398
  };
399
+ var createTitleId = (title) => {
400
+ if (typeof title === "string" || typeof title === "number") {
401
+ const normalized = String(title).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
402
+ return `smartsell-modal-${normalized || "dialog"}`;
403
+ }
404
+ return "smartsell-modal-dialog";
405
+ };
393
406
  var isLegacyModalProps = (props) => {
394
407
  return "showModal" in props;
395
408
  };
396
- function LegacyActionButton({
397
- label,
398
- onClick,
399
- disabled,
400
- type = "contained",
401
- theme,
402
- style
409
+ var normalizeLegacyAction = (action, fallbackDisabled = false) => {
410
+ var _a, _b, _c;
411
+ return {
412
+ label: action.name,
413
+ onClick: action.onClick,
414
+ appearance: (_a = action.type) != null ? _a : "contained",
415
+ style: (_b = action.style) != null ? _b : { maxWidth: "150px" },
416
+ disabled: (_c = action.disable) != null ? _c : fallbackDisabled
417
+ };
418
+ };
419
+ var normalizeModalProps = (props) => {
420
+ var _a, _b;
421
+ if (!isLegacyModalProps(props)) {
422
+ return props;
423
+ }
424
+ const isBusy = Boolean(props.isLoading);
425
+ const disableAction = Boolean(props.disableActionBtn || props.isLoading);
426
+ return {
427
+ isOpen: props.showModal,
428
+ onClose: props.closeModal,
429
+ title: props.title,
430
+ children: props.children,
431
+ theme: props.theme,
432
+ maximized: props.maximized,
433
+ contentStyle: props.style,
434
+ bodyStyle: props.bodyStyle,
435
+ hideCloseButton: props.hideCloseIcon,
436
+ disableDismiss: isBusy,
437
+ closeOnBackdrop: false,
438
+ closeOnEscape: false,
439
+ isBusy,
440
+ closeAction: props.onlyCloseButton ? {
441
+ label: "Close",
442
+ onClick: props.closeModal,
443
+ appearance: "contained",
444
+ disabled: isBusy
445
+ } : void 0,
446
+ cancelAction: props.onlyCloseButton || !props.cancelButton ? void 0 : {
447
+ label: "Cancel",
448
+ onClick: props.cancelButton,
449
+ appearance: "text",
450
+ style: { maxWidth: "100px" }
451
+ },
452
+ confirmAction: props.onlyCloseButton || props.hideActionButton || !props.action ? void 0 : {
453
+ label: (_a = props.actionNameBtn) != null ? _a : "Save",
454
+ onClick: props.action,
455
+ appearance: "contained",
456
+ style: { maxWidth: "100px" },
457
+ disabled: disableAction
458
+ },
459
+ extraActions: props.onlyCloseButton ? void 0 : (_b = props.additionalActions) == null ? void 0 : _b.map((action) => normalizeLegacyAction(action, disableAction))
460
+ };
461
+ };
462
+ function ModalActionButton({
463
+ action,
464
+ theme
403
465
  }) {
404
466
  var _a, _b;
405
467
  const { colors } = theme;
468
+ const {
469
+ label,
470
+ onClick,
471
+ appearance = "contained",
472
+ disabled = false,
473
+ style
474
+ } = action;
406
475
  const buttonStyle = {
407
476
  width: "100%",
408
477
  display: "flex",
409
478
  alignItems: "center",
410
479
  justifyContent: "center",
411
480
  borderRadius: "0.4rem",
412
- padding: type === "link" ? 0 : "1.3rem",
481
+ padding: appearance === "link" ? 0 : "1.3rem",
413
482
  boxSizing: "border-box",
414
483
  cursor: disabled ? "not-allowed" : "pointer",
415
484
  fontWeight: 700,
@@ -420,17 +489,17 @@ function LegacyActionButton({
420
489
  opacity: disabled ? 0.5 : 1,
421
490
  filter: disabled ? "saturate(0)" : void 0
422
491
  };
423
- if (type === "text") {
492
+ if (appearance === "text") {
424
493
  buttonStyle.background = "none";
425
494
  buttonStyle.border = "1px solid transparent";
426
495
  buttonStyle.color = colors.primary;
427
496
  buttonStyle.boxShadow = "none";
428
- } else if (type === "link") {
497
+ } else if (appearance === "link") {
429
498
  buttonStyle.background = "none";
430
499
  buttonStyle.border = "none";
431
500
  buttonStyle.color = colors.primary;
432
501
  buttonStyle.boxShadow = "none";
433
- } else if (type === "outlined") {
502
+ } else if (appearance === "outlined") {
434
503
  buttonStyle.background = "none";
435
504
  buttonStyle.border = `2px solid ${colors.primary}`;
436
505
  buttonStyle.color = colors.primary;
@@ -466,29 +535,34 @@ function LegacyActionButton({
466
535
  }
467
536
  );
468
537
  }
469
- function StandardModal({
538
+ function UnifiedModal({
470
539
  isOpen,
471
540
  onClose,
472
541
  children,
473
- footer,
474
542
  title,
475
543
  description,
476
544
  headerContent,
545
+ footer,
546
+ confirmAction,
547
+ cancelAction,
548
+ closeAction,
549
+ extraActions,
477
550
  maxWidth,
478
551
  closeOnBackdrop = true,
479
552
  closeOnEscape = true,
480
553
  hideCloseButton = false,
481
554
  hideExpandButton = false,
555
+ disableDismiss = false,
482
556
  maximized,
483
557
  contentStyle,
558
+ bodyStyle,
559
+ isBusy = false,
484
560
  theme
485
561
  }) {
562
+ var _a, _b;
486
563
  const modalTheme = (0, import_react3.useMemo)(() => resolveTheme(theme), [theme]);
487
564
  const [isMaximized, setIsMaximized] = (0, import_react3.useState)(maximized != null ? maximized : false);
488
- const titleId = (0, import_react3.useMemo)(
489
- () => `smartsell-modal-${String(title != null ? title : "dialog").toLowerCase().replace(/[^a-z0-9]+/g, "-")}`,
490
- [title]
491
- );
565
+ const titleId = (0, import_react3.useMemo)(() => createTitleId(title), [title]);
492
566
  (0, import_react3.useEffect)(() => {
493
567
  if (typeof maximized === "boolean") {
494
568
  setIsMaximized(maximized);
@@ -505,7 +579,7 @@ function StandardModal({
505
579
  const previousOverflow = document.body.style.overflow;
506
580
  document.body.style.overflow = "hidden";
507
581
  const handleKeyDown = (event) => {
508
- if (closeOnEscape && event.key === "Escape") {
582
+ if (!disableDismiss && closeOnEscape && event.key === "Escape") {
509
583
  onClose();
510
584
  }
511
585
  };
@@ -514,11 +588,11 @@ function StandardModal({
514
588
  document.body.style.overflow = previousOverflow;
515
589
  window.removeEventListener("keydown", handleKeyDown);
516
590
  };
517
- }, [closeOnEscape, isOpen, onClose]);
591
+ }, [closeOnEscape, disableDismiss, isOpen, onClose]);
518
592
  if (!isOpen) {
519
593
  return null;
520
594
  }
521
- const header = headerContent != null ? headerContent : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
595
+ const resolvedHeader = headerContent != null ? headerContent : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
522
596
  title ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
523
597
  "h2",
524
598
  {
@@ -546,6 +620,39 @@ function StandardModal({
546
620
  }
547
621
  ) : null
548
622
  ] });
623
+ let footerContent = footer;
624
+ if (footerContent === void 0) {
625
+ if (closeAction && !closeAction.hidden) {
626
+ footerContent = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModalActionButton, { action: closeAction, theme: modalTheme });
627
+ } else {
628
+ const resolvedActions = [
629
+ cancelAction ? { ...cancelAction, appearance: (_a = cancelAction.appearance) != null ? _a : "text" } : void 0,
630
+ ...(extraActions != null ? extraActions : []).map((action) => {
631
+ var _a2;
632
+ return {
633
+ ...action,
634
+ appearance: (_a2 = action.appearance) != null ? _a2 : "contained"
635
+ };
636
+ }),
637
+ confirmAction ? { ...confirmAction, appearance: (_b = confirmAction.appearance) != null ? _b : "contained" } : void 0
638
+ ].reduce((items, action) => {
639
+ if (!action || action.hidden) {
640
+ return items;
641
+ }
642
+ items.push(action);
643
+ return items;
644
+ }, []);
645
+ footerContent = resolvedActions.length > 0 ? resolvedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
646
+ ModalActionButton,
647
+ {
648
+ action,
649
+ theme: modalTheme
650
+ },
651
+ `modal-action-${index}`
652
+ )) : void 0;
653
+ }
654
+ }
655
+ const shouldRenderFooter = footerContent !== void 0 && footerContent !== null && footerContent !== false;
549
656
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
550
657
  "div",
551
658
  {
@@ -554,7 +661,7 @@ function StandardModal({
554
661
  "aria-modal": "true",
555
662
  role: "dialog",
556
663
  onMouseDown: (event) => {
557
- if (closeOnBackdrop && event.target === event.currentTarget) {
664
+ if (!disableDismiss && closeOnBackdrop && event.target === event.currentTarget) {
558
665
  onClose();
559
666
  }
560
667
  },
@@ -572,6 +679,7 @@ function StandardModal({
572
679
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
573
680
  "div",
574
681
  {
682
+ id: isBusy ? "ldg1" : void 0,
575
683
  style: {
576
684
  position: "relative",
577
685
  display: "flex",
@@ -580,12 +688,14 @@ function StandardModal({
580
688
  maxWidth: isMaximized ? "100vw" : normalizeWidth(maxWidth),
581
689
  height: isMaximized ? "100vh" : void 0,
582
690
  maxHeight: isMaximized ? "100vh" : "calc(100vh - 32px)",
691
+ minWidth: isMaximized ? "100vw" : 300,
583
692
  borderRadius: isMaximized ? 0 : 30,
584
693
  border: `1px solid ${modalTheme.borderSoft}`,
585
694
  background: `linear-gradient(180deg, ${modalTheme.surfaceRaised}, ${modalTheme.colors.surface})`,
586
695
  boxShadow: `0 34px 80px ${withAlpha4("#020617", 0.28)}`,
587
696
  color: modalTheme.colors.onSurface,
588
697
  overflow: "hidden",
698
+ opacity: isBusy ? 0.5 : 1,
589
699
  ...contentStyle
590
700
  },
591
701
  children: [
@@ -601,7 +711,7 @@ function StandardModal({
601
711
  borderBottom: `1px solid ${withAlpha4(modalTheme.colors.onSurface, 0.06)}`
602
712
  },
603
713
  children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 }, children: header }),
714
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 }, children: resolvedHeader }),
605
715
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
606
716
  !hideExpandButton ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
607
717
  "button",
@@ -629,7 +739,7 @@ function StandardModal({
629
739
  {
630
740
  "aria-label": "Close modal",
631
741
  type: "button",
632
- onClick: onClose,
742
+ onClick: disableDismiss ? void 0 : onClose,
633
743
  style: {
634
744
  height: 42,
635
745
  width: 42,
@@ -637,9 +747,10 @@ function StandardModal({
637
747
  border: `1px solid ${modalTheme.borderSoft}`,
638
748
  backgroundColor: "transparent",
639
749
  color: modalTheme.colors.onSurface,
640
- cursor: "pointer",
750
+ cursor: disableDismiss ? "not-allowed" : "pointer",
641
751
  fontSize: 20,
642
- fontWeight: 700
752
+ fontWeight: 700,
753
+ opacity: disableDismiss ? 0.5 : 1
643
754
  },
644
755
  children: "\xD7"
645
756
  }
@@ -655,12 +766,13 @@ function StandardModal({
655
766
  flex: 1,
656
767
  minHeight: 0,
657
768
  overflow: "auto",
658
- padding: 24
769
+ padding: 24,
770
+ ...bodyStyle
659
771
  },
660
772
  children
661
773
  }
662
774
  ),
663
- footer ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
775
+ shouldRenderFooter ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
664
776
  "div",
665
777
  {
666
778
  style: {
@@ -670,7 +782,7 @@ function StandardModal({
670
782
  padding: "16px 24px 24px",
671
783
  borderTop: `1px solid ${withAlpha4(modalTheme.colors.onSurface, 0.06)}`
672
784
  },
673
- children: footer
785
+ children: footerContent
674
786
  }
675
787
  ) : null
676
788
  ]
@@ -679,288 +791,8 @@ function StandardModal({
679
791
  }
680
792
  );
681
793
  }
682
- function LegacyModal({
683
- title,
684
- showModal,
685
- closeModal,
686
- children,
687
- action,
688
- actionNameBtn,
689
- hideActionButton = false,
690
- cancelButton,
691
- disableActionBtn = false,
692
- isLoading = false,
693
- onlyCloseButton = false,
694
- hideCloseIcon = false,
695
- style,
696
- bodyStyle,
697
- additionalActions,
698
- maximized,
699
- theme
700
- }) {
701
- const modalTheme = (0, import_react3.useMemo)(() => resolveTheme(theme), [theme]);
702
- const [isMaximized, setIsMaximized] = (0, import_react3.useState)(maximized != null ? maximized : false);
703
- const resolvedAction = action != null ? action : (() => null);
704
- (0, import_react3.useEffect)(() => {
705
- if (maximized === void 0 && isLikelyMobileViewport()) {
706
- setIsMaximized(true);
707
- }
708
- }, [maximized]);
709
- if (!showModal) {
710
- return null;
711
- }
712
- const actionButtons = () => {
713
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
714
- additionalActions == null ? void 0 : additionalActions.map((item) => {
715
- var _a, _b, _c;
716
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
717
- LegacyActionButton,
718
- {
719
- label: item.name,
720
- onClick: item.onClick,
721
- type: (_a = item.type) != null ? _a : "contained",
722
- style: (_b = item.style) != null ? _b : { maxWidth: "150px" },
723
- theme: modalTheme,
724
- disabled: (_c = item.disable) != null ? _c : disableActionBtn || isLoading
725
- },
726
- item.name
727
- );
728
- }),
729
- !hideActionButton ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
730
- LegacyActionButton,
731
- {
732
- label: actionNameBtn != null ? actionNameBtn : "Save",
733
- onClick: resolvedAction,
734
- type: "contained",
735
- style: { maxWidth: "100px" },
736
- theme: modalTheme,
737
- disabled: disableActionBtn || isLoading
738
- }
739
- ) : null
740
- ] });
741
- };
742
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
743
- "div",
744
- {
745
- "aria-labelledby": "modal-title",
746
- "aria-modal": "true",
747
- role: "dialog",
748
- style: {
749
- background: `${modalTheme.colors.background}90`,
750
- backdropFilter: "blur(2px)",
751
- width: "100%",
752
- height: "100%",
753
- position: "fixed",
754
- zIndex: 999,
755
- top: 0,
756
- left: 0,
757
- display: "flex",
758
- justifyContent: "center",
759
- alignItems: "center",
760
- boxSizing: "border-box"
761
- },
762
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
763
- "div",
764
- {
765
- id: isLoading ? "ldg1" : void 0,
766
- style: {
767
- position: isMaximized ? "fixed" : "relative",
768
- left: isMaximized ? 0 : void 0,
769
- top: isMaximized ? 0 : void 0,
770
- background: modalTheme.colors.background,
771
- display: "flex",
772
- alignItems: "center",
773
- flexDirection: "column",
774
- borderRadius: "0.8rem",
775
- boxSizing: "border-box",
776
- maxHeight: isMaximized ? "100vh" : "80vh",
777
- maxWidth: isMaximized ? "100vw" : "80vw",
778
- minWidth: isMaximized ? "100vw" : 300,
779
- minHeight: isMaximized ? "100vh" : void 0,
780
- width: isMaximized ? "100vw" : void 0,
781
- boxShadow: "0 24px 64px rgba(15, 23, 42, 0.18)",
782
- ...isLoading ? { opacity: 0.5 } : null,
783
- ...style
784
- },
785
- children: [
786
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
787
- "div",
788
- {
789
- style: {
790
- background: modalTheme.colors.surface,
791
- color: modalTheme.colors.onSurface,
792
- position: "absolute",
793
- top: 0,
794
- zIndex: 500,
795
- display: "flex",
796
- justifyContent: "space-between",
797
- alignItems: "center",
798
- width: "100%",
799
- height: "4rem",
800
- padding: "1rem",
801
- boxSizing: "border-box",
802
- borderTopLeftRadius: "0.8rem",
803
- borderTopRightRadius: "0.8rem",
804
- borderBottom: `1px solid ${withAlpha4(modalTheme.colors.onBackground, 0.1)}`
805
- },
806
- children: [
807
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { id: "modal-title", style: { fontWeight: "bold", fontSize: "1.3rem" }, children: title }),
808
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
809
- "div",
810
- {
811
- id: "modal-header-icons",
812
- style: { display: "flex", alignItems: "center", gap: "0.5rem" },
813
- children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
815
- "button",
816
- {
817
- "aria-label": isMaximized ? "Minimize modal" : "Maximize modal",
818
- title: isMaximized ? "Minimize" : "Maximize",
819
- type: "button",
820
- onClick: () => setIsMaximized((current) => !current),
821
- style: {
822
- border: "none",
823
- background: "transparent",
824
- color: modalTheme.colors.onSurface,
825
- cursor: "pointer",
826
- fontSize: 18,
827
- lineHeight: 1,
828
- padding: 0
829
- },
830
- children: isMaximized ? "\u25A2" : "\u25A1"
831
- }
832
- ),
833
- !hideCloseIcon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
834
- "button",
835
- {
836
- "aria-label": "Close modal",
837
- title: "Close",
838
- type: "button",
839
- onClick: isLoading ? void 0 : closeModal,
840
- style: {
841
- border: "none",
842
- background: "transparent",
843
- color: modalTheme.colors.onSurface,
844
- cursor: isLoading ? "not-allowed" : "pointer",
845
- fontSize: 22,
846
- lineHeight: 1,
847
- padding: 0,
848
- opacity: isLoading ? 0.5 : 1
849
- },
850
- children: "\xD7"
851
- }
852
- ) : null
853
- ]
854
- }
855
- )
856
- ]
857
- }
858
- ),
859
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
860
- "div",
861
- {
862
- style: {
863
- scrollbarWidth: "thin",
864
- width: "100%",
865
- maxWidth: "100%",
866
- paddingTop: "4rem",
867
- paddingBottom: "4rem",
868
- overflow: "auto",
869
- ...bodyStyle
870
- },
871
- children
872
- }
873
- ),
874
- onlyCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
875
- "div",
876
- {
877
- style: {
878
- background: modalTheme.colors.surface,
879
- color: modalTheme.colors.onSurface,
880
- position: "absolute",
881
- bottom: 0,
882
- width: "100%",
883
- height: "4rem",
884
- padding: "0.5rem",
885
- borderTop: `1px solid ${withAlpha4(modalTheme.colors.onBackground, 0.1)}`,
886
- boxSizing: "border-box",
887
- borderBottomLeftRadius: "0.8rem",
888
- borderBottomRightRadius: "0.8rem"
889
- },
890
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
891
- "div",
892
- {
893
- className: "buttons-footer",
894
- style: { flex: 1, display: "flex", justifyContent: "end" },
895
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
896
- LegacyActionButton,
897
- {
898
- label: "Close",
899
- onClick: closeModal,
900
- theme: modalTheme,
901
- disabled: isLoading
902
- }
903
- )
904
- }
905
- )
906
- }
907
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
908
- "div",
909
- {
910
- style: {
911
- background: modalTheme.colors.surface,
912
- color: modalTheme.colors.onSurface,
913
- position: "absolute",
914
- bottom: 0,
915
- width: "100%",
916
- height: "4rem",
917
- padding: "0.5rem",
918
- borderTop: `1px solid ${withAlpha4(modalTheme.colors.onBackground, 0.1)}`,
919
- boxSizing: "border-box",
920
- borderBottomLeftRadius: "0.8rem",
921
- borderBottomRightRadius: "0.8rem"
922
- },
923
- children: cancelButton ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
924
- "div",
925
- {
926
- className: "buttons-footer",
927
- style: { flex: 1, display: "flex", justifyContent: "end" },
928
- children: [
929
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
930
- LegacyActionButton,
931
- {
932
- label: "Cancel",
933
- onClick: cancelButton,
934
- type: "text",
935
- style: { maxWidth: "100px" },
936
- theme: modalTheme,
937
- disabled: false
938
- }
939
- ),
940
- actionButtons()
941
- ]
942
- }
943
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
944
- "div",
945
- {
946
- className: "buttons-footer",
947
- style: { flex: 1, display: "flex", justifyContent: "end" },
948
- children: actionButtons()
949
- }
950
- )
951
- }
952
- )
953
- ]
954
- }
955
- )
956
- }
957
- );
958
- }
959
794
  function Modal(props) {
960
- if (isLegacyModalProps(props)) {
961
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LegacyModal, { ...props });
962
- }
963
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StandardModal, { ...props });
795
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UnifiedModal, { ...normalizeModalProps(props) });
964
796
  }
965
797
 
966
798
  // src/components/ComposableModal.tsx
@@ -1009,7 +841,7 @@ function ComposableModal({
1009
841
  [cancelLabel, confirmLabel, description, isBusy, isOpen, onClose, onConfirm, payload, title]
1010
842
  );
1011
843
  const defaultFooter = hideDefaultFooter ? void 0 : footerFallback != null ? footerFallback : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1012
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { sdk, variant: "outline", tone: "neutral", onClick: onClose, disabled: isBusy, children: cancelLabel }),
844
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { sdk, variant: "outline", onClick: onClose, disabled: isBusy, children: cancelLabel }),
1013
845
  onConfirm ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { sdk, onClick: onConfirm, disabled: isBusy, children: confirmLabel }) : null
1014
846
  ] });
1015
847
  const defaultHeader = headerFallback != null ? headerFallback : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
@@ -1061,124 +893,405 @@ function ComposableModal({
1061
893
  );
1062
894
  }
1063
895
 
1064
- // src/components/Field.tsx
896
+ // src/components/Input.tsx
897
+ var import_react5 = require("react");
898
+ var import_smartsell_sales_sdk5 = require("smartsell-sales-sdk");
1065
899
  var import_jsx_runtime5 = require("react/jsx-runtime");
1066
- function Field({
900
+ var PASSWORD_TOGGLE_METRICS_BY_SIZE = {
901
+ sm: {
902
+ buttonSize: 18,
903
+ leftOffset: 8,
904
+ contentGap: 8,
905
+ iconSize: 14
906
+ },
907
+ md: {
908
+ buttonSize: 20,
909
+ leftOffset: 10,
910
+ contentGap: 10,
911
+ iconSize: 16
912
+ },
913
+ lg: {
914
+ buttonSize: 22,
915
+ leftOffset: 12,
916
+ contentGap: 12,
917
+ iconSize: 18
918
+ }
919
+ };
920
+ var getPasswordToggleMetrics = (size) => PASSWORD_TOGGLE_METRICS_BY_SIZE[size];
921
+ function ControlFrame({
1067
922
  sdk,
1068
923
  label,
1069
924
  hint,
1070
925
  error,
1071
926
  htmlFor,
1072
927
  required = false,
928
+ useLabelWrapper = true,
1073
929
  children,
1074
930
  style
1075
931
  }) {
932
+ if (!label && !hint && !error) {
933
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
934
+ }
1076
935
  const { theme, mutedText } = useUiKitTheme(sdk);
1077
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1078
- "label",
1079
- {
1080
- htmlFor,
1081
- style: {
1082
- display: "flex",
1083
- flexDirection: "column",
1084
- gap: 8,
1085
- width: "100%",
1086
- ...style
1087
- },
1088
- children: [
1089
- (label || hint) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
1090
- label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1091
- "span",
1092
- {
1093
- style: {
1094
- color: theme.colors.onSurface,
1095
- fontSize: 14,
1096
- fontWeight: 700,
1097
- letterSpacing: "0.01em"
1098
- },
1099
- children: [
1100
- label,
1101
- required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.colors.negative, marginLeft: 4 }, children: "*" }) : null
1102
- ]
1103
- }
1104
- ) : null,
1105
- hint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1106
- "span",
1107
- {
1108
- style: {
1109
- color: mutedText,
1110
- fontSize: 13,
1111
- lineHeight: 1.45
1112
- },
1113
- children: hint
1114
- }
1115
- ) : null
1116
- ] }),
1117
- children,
1118
- error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
936
+ const labelStyle = {
937
+ color: theme.colors.onSurface,
938
+ fontSize: 14,
939
+ fontWeight: 700,
940
+ letterSpacing: "0.01em"
941
+ };
942
+ const wrapperStyle = {
943
+ display: "flex",
944
+ flexDirection: "column",
945
+ gap: 8,
946
+ width: "100%",
947
+ ...style
948
+ };
949
+ if (!useLabelWrapper) {
950
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: wrapperStyle, children: [
951
+ label || hint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
952
+ label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { htmlFor, style: labelStyle, children: [
953
+ label,
954
+ required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.colors.negative, marginLeft: 4 }, children: "*" }) : null
955
+ ] }) : null,
956
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1119
957
  "span",
1120
958
  {
1121
959
  style: {
1122
- color: theme.colors.negative,
960
+ color: mutedText,
1123
961
  fontSize: 13,
1124
- fontWeight: 600,
1125
962
  lineHeight: 1.45
1126
963
  },
1127
- children: error
964
+ children: hint
1128
965
  }
1129
966
  ) : null
1130
- ]
1131
- }
1132
- );
967
+ ] }) : null,
968
+ children,
969
+ error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
970
+ "span",
971
+ {
972
+ style: {
973
+ color: theme.colors.negative,
974
+ fontSize: 13,
975
+ fontWeight: 600,
976
+ lineHeight: 1.45
977
+ },
978
+ children: error
979
+ }
980
+ ) : null
981
+ ] });
982
+ }
983
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { htmlFor, style: wrapperStyle, children: [
984
+ label || hint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
985
+ label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: labelStyle, children: [
986
+ label,
987
+ required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.colors.negative, marginLeft: 4 }, children: "*" }) : null
988
+ ] }) : null,
989
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
990
+ "span",
991
+ {
992
+ style: {
993
+ color: mutedText,
994
+ fontSize: 13,
995
+ lineHeight: 1.45
996
+ },
997
+ children: hint
998
+ }
999
+ ) : null
1000
+ ] }) : null,
1001
+ children,
1002
+ error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1003
+ "span",
1004
+ {
1005
+ style: {
1006
+ color: theme.colors.negative,
1007
+ fontSize: 13,
1008
+ fontWeight: 600,
1009
+ lineHeight: 1.45
1010
+ },
1011
+ children: error
1012
+ }
1013
+ ) : null
1014
+ ] });
1133
1015
  }
1134
-
1135
- // src/components/Input.tsx
1136
- var import_smartsell_sales_sdk5 = require("smartsell-sales-sdk");
1137
- var import_jsx_runtime6 = require("react/jsx-runtime");
1138
- var getPadding = (size) => {
1139
- if (size === "sm") return "10px 12px";
1140
- if (size === "lg") return "16px 18px";
1141
- return "13px 16px";
1142
- };
1143
1016
  function Input({
1144
1017
  sdk,
1145
1018
  label,
1146
1019
  hint,
1147
1020
  error,
1148
1021
  controlSize = "md",
1022
+ showPasswordToggle = false,
1149
1023
  id,
1150
1024
  disabled,
1151
1025
  style,
1026
+ type = "text",
1152
1027
  ...rest
1153
1028
  }) {
1154
1029
  const { theme, borderSoft, focusRing, surfaceMuted } = useUiKitTheme(sdk);
1030
+ const controlMetrics = getControlMetrics(controlSize);
1031
+ const passwordToggleMetrics = getPasswordToggleMetrics(controlSize);
1032
+ const [isPasswordVisible, setIsPasswordVisible] = (0, import_react5.useState)(false);
1033
+ const isPasswordField = type === "password";
1034
+ const canTogglePasswordVisibility = isPasswordField && showPasswordToggle;
1035
+ const passwordToggleInset = Math.max(
1036
+ 0,
1037
+ passwordToggleMetrics.leftOffset + passwordToggleMetrics.buttonSize + passwordToggleMetrics.contentGap - controlMetrics.paddingX
1038
+ );
1039
+ const leadingInset = Number(canTogglePasswordVisibility) * passwordToggleInset;
1040
+ const resolvedType = canTogglePasswordVisibility ? isPasswordVisible ? "text" : "password" : type;
1155
1041
  const inputStyle = {
1156
1042
  width: "100%",
1043
+ boxSizing: "border-box",
1044
+ height: controlMetrics.height,
1157
1045
  borderRadius: 16,
1158
- border: `1px solid ${error ? theme.colors.negative : borderSoft}`,
1159
- padding: getPadding(controlSize),
1046
+ border: `1px solid ${error ? theme.colors.negative : (0, import_smartsell_sales_sdk5.withAlpha)(theme.colors.textLight, 0.5)}`,
1047
+ backgroundColor: theme.colors.surface,
1048
+ color: theme.colors.text,
1049
+ cursor: disabled ? "not-allowed" : "text",
1050
+ opacity: disabled ? 0.7 : 1,
1051
+ padding: getTextInputPadding(controlSize, { leadingInset }),
1160
1052
  outline: "none",
1161
- color: theme.colors.onSurface,
1162
- backgroundColor: disabled ? surfaceMuted : theme.colors.surface,
1053
+ fontSize: controlMetrics.fontSize,
1054
+ lineHeight: controlMetrics.lineHeight,
1163
1055
  boxShadow: error ? `0 0 0 3px ${(0, import_smartsell_sales_sdk5.withAlpha)(theme.colors.negative, 0.12)}` : `0 0 0 0 ${focusRing}`,
1164
1056
  transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
1165
1057
  ...style
1166
1058
  };
1167
- const input = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { ...rest, id, disabled, style: inputStyle });
1168
- if (!label && !hint && !error) {
1169
- return input;
1170
- }
1171
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Field, { sdk, label, hint, error, htmlFor: id, children: input });
1059
+ const input = canTogglePasswordVisibility ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", width: "100%" }, children: [
1060
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1061
+ "button",
1062
+ {
1063
+ type: "button",
1064
+ "aria-label": isPasswordVisible ? "Hide password" : "Show password",
1065
+ "aria-pressed": isPasswordVisible,
1066
+ disabled,
1067
+ onMouseDown: (event) => {
1068
+ event.preventDefault();
1069
+ },
1070
+ onClick: () => {
1071
+ setIsPasswordVisible((currentValue) => !currentValue);
1072
+ },
1073
+ style: {
1074
+ position: "absolute",
1075
+ top: "50%",
1076
+ left: passwordToggleMetrics.leftOffset,
1077
+ transform: "translateY(-50%)",
1078
+ zIndex: 1,
1079
+ width: passwordToggleMetrics.buttonSize,
1080
+ height: passwordToggleMetrics.buttonSize,
1081
+ display: "inline-flex",
1082
+ alignItems: "center",
1083
+ justifyContent: "center",
1084
+ border: "none",
1085
+ padding: 0,
1086
+ margin: 0,
1087
+ borderRadius: 999,
1088
+ backgroundColor: "transparent",
1089
+ color: isPasswordVisible ? theme.colors.primary : theme.colors.textLight,
1090
+ cursor: disabled ? "not-allowed" : "pointer",
1091
+ opacity: disabled ? 0.5 : 1
1092
+ },
1093
+ children: isPasswordVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1094
+ "svg",
1095
+ {
1096
+ width: passwordToggleMetrics.iconSize,
1097
+ height: passwordToggleMetrics.iconSize,
1098
+ viewBox: "0 0 20 20",
1099
+ fill: "none",
1100
+ "aria-hidden": "true",
1101
+ children: [
1102
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1103
+ "path",
1104
+ {
1105
+ d: "M2.5 3.5L17.5 16.5",
1106
+ stroke: "currentColor",
1107
+ strokeWidth: "1.8",
1108
+ strokeLinecap: "round"
1109
+ }
1110
+ ),
1111
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1112
+ "path",
1113
+ {
1114
+ d: "M8.825 8.786a2 2 0 0 0 2.389 2.389",
1115
+ stroke: "currentColor",
1116
+ strokeWidth: "1.8",
1117
+ strokeLinecap: "round",
1118
+ strokeLinejoin: "round"
1119
+ }
1120
+ ),
1121
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1122
+ "path",
1123
+ {
1124
+ d: "M4.42 6.774C3.422 7.73 2.777 8.815 2.5 9.375c1.182 2.39 3.934 5.625 7.5 5.625 1.155 0 2.224-.34 3.166-.847",
1125
+ stroke: "currentColor",
1126
+ strokeWidth: "1.8",
1127
+ strokeLinecap: "round",
1128
+ strokeLinejoin: "round"
1129
+ }
1130
+ ),
1131
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1132
+ "path",
1133
+ {
1134
+ d: "M7.043 4.455A7.7 7.7 0 0 1 10 3.75c3.566 0 6.318 3.235 7.5 5.625-.39.787-1.504 2.588-3.259 3.986",
1135
+ stroke: "currentColor",
1136
+ strokeWidth: "1.8",
1137
+ strokeLinecap: "round",
1138
+ strokeLinejoin: "round"
1139
+ }
1140
+ )
1141
+ ]
1142
+ }
1143
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1144
+ "svg",
1145
+ {
1146
+ width: passwordToggleMetrics.iconSize,
1147
+ height: passwordToggleMetrics.iconSize,
1148
+ viewBox: "0 0 20 20",
1149
+ fill: "none",
1150
+ "aria-hidden": "true",
1151
+ children: [
1152
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1153
+ "path",
1154
+ {
1155
+ d: "M2.5 10c1.182-2.39 3.934-5.625 7.5-5.625S16.318 7.61 17.5 10c-1.182 2.39-3.934 5.625-7.5 5.625S3.682 12.39 2.5 10Z",
1156
+ stroke: "currentColor",
1157
+ strokeWidth: "1.8",
1158
+ strokeLinecap: "round",
1159
+ strokeLinejoin: "round"
1160
+ }
1161
+ ),
1162
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "10", cy: "10", r: "2.25", stroke: "currentColor", strokeWidth: "1.8" })
1163
+ ]
1164
+ }
1165
+ )
1166
+ }
1167
+ ),
1168
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { ...rest, id, type: resolvedType, disabled, style: inputStyle })
1169
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { ...rest, id, type: resolvedType, disabled, style: inputStyle });
1170
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ControlFrame, { sdk, label, hint, error, htmlFor: id, required: rest.required, children: input });
1172
1171
  }
1173
1172
 
1174
1173
  // src/components/Select.tsx
1174
+ var import_react6 = require("react");
1175
1175
  var import_smartsell_sales_sdk6 = require("smartsell-sales-sdk");
1176
- var import_jsx_runtime7 = require("react/jsx-runtime");
1177
- var getPadding2 = (size) => {
1176
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1177
+ var MENU_OFFSET = 8;
1178
+ var MENU_MAX_HEIGHT = 280;
1179
+ var getOptionPadding = (size) => {
1178
1180
  if (size === "sm") return "10px 12px";
1179
- if (size === "lg") return "16px 18px";
1180
- return "13px 16px";
1181
+ if (size === "lg") return "14px 16px";
1182
+ return "12px 14px";
1181
1183
  };
1184
+ function getTextContent(node) {
1185
+ if (node == null || typeof node === "boolean") {
1186
+ return "";
1187
+ }
1188
+ if (typeof node === "string" || typeof node === "number") {
1189
+ return String(node);
1190
+ }
1191
+ if (Array.isArray(node)) {
1192
+ return node.map(getTextContent).join("");
1193
+ }
1194
+ if ((0, import_react6.isValidElement)(node)) {
1195
+ return getTextContent(node.props.children);
1196
+ }
1197
+ return "";
1198
+ }
1199
+ function normalizeSelectValue(value) {
1200
+ if (Array.isArray(value)) {
1201
+ return value.length > 0 ? normalizeSelectValue(value[0]) : "";
1202
+ }
1203
+ return value == null ? "" : String(value);
1204
+ }
1205
+ function normalizeSelectValues(value) {
1206
+ if (Array.isArray(value)) {
1207
+ return value.map((item) => normalizeSelectValue(item));
1208
+ }
1209
+ if (value == null) {
1210
+ return [];
1211
+ }
1212
+ return [normalizeSelectValue(value)];
1213
+ }
1214
+ function buildOption(keyPrefix, index, props, groupLabel, groupDisabled = false) {
1215
+ var _a;
1216
+ const rawValue = props.value !== void 0 ? props.value : getTextContent(props.children).trim();
1217
+ const normalizedValue = normalizeSelectValue(rawValue);
1218
+ return {
1219
+ key: `${keyPrefix}-${index}-${normalizedValue}`,
1220
+ value: normalizedValue,
1221
+ label: (_a = props.children) != null ? _a : normalizedValue,
1222
+ disabled: groupDisabled || Boolean(props.disabled)
1223
+ };
1224
+ }
1225
+ function parseSelectChildren(children) {
1226
+ const groups = [];
1227
+ const standaloneOptions = [];
1228
+ let optionIndex = 0;
1229
+ let groupIndex = 0;
1230
+ const flushStandaloneOptions = () => {
1231
+ if (standaloneOptions.length === 0) {
1232
+ return;
1233
+ }
1234
+ groups.push({
1235
+ key: `standalone-${groups.length}`,
1236
+ options: [...standaloneOptions]
1237
+ });
1238
+ standaloneOptions.length = 0;
1239
+ };
1240
+ import_react6.Children.forEach(children, (child) => {
1241
+ if (!(0, import_react6.isValidElement)(child)) {
1242
+ return;
1243
+ }
1244
+ if (child.type === "option") {
1245
+ standaloneOptions.push(buildOption("option", optionIndex, child.props));
1246
+ optionIndex += 1;
1247
+ return;
1248
+ }
1249
+ if (child.type !== "optgroup") {
1250
+ return;
1251
+ }
1252
+ flushStandaloneOptions();
1253
+ const groupOptions = [];
1254
+ let groupOptionIndex = 0;
1255
+ import_react6.Children.forEach(child.props.children, (optionChild) => {
1256
+ if (!(0, import_react6.isValidElement)(optionChild) || optionChild.type !== "option") {
1257
+ return;
1258
+ }
1259
+ groupOptions.push(
1260
+ buildOption(
1261
+ `group-${groupIndex}-option`,
1262
+ groupOptionIndex,
1263
+ optionChild.props,
1264
+ child.props.label,
1265
+ Boolean(child.props.disabled)
1266
+ )
1267
+ );
1268
+ groupOptionIndex += 1;
1269
+ });
1270
+ if (groupOptions.length > 0) {
1271
+ groups.push({
1272
+ key: `group-${groupIndex}`,
1273
+ label: child.props.label,
1274
+ options: groupOptions
1275
+ });
1276
+ groupIndex += 1;
1277
+ }
1278
+ });
1279
+ flushStandaloneOptions();
1280
+ return groups;
1281
+ }
1282
+ function filterSelectGroups(groups, query) {
1283
+ const normalizedQuery = query.trim().toLowerCase();
1284
+ if (!normalizedQuery) {
1285
+ return groups;
1286
+ }
1287
+ return groups.map((group) => ({
1288
+ ...group,
1289
+ options: group.options.filter((option) => {
1290
+ const optionText = getTextContent(option.label).trim().toLowerCase();
1291
+ return optionText.includes(normalizedQuery);
1292
+ })
1293
+ })).filter((group) => group.options.length > 0);
1294
+ }
1182
1295
  function Select({
1183
1296
  sdk,
1184
1297
  label,
@@ -1189,32 +1302,845 @@ function Select({
1189
1302
  disabled,
1190
1303
  style,
1191
1304
  children,
1305
+ value,
1306
+ defaultValue,
1307
+ onChange,
1308
+ onFocus,
1309
+ onBlur,
1310
+ onKeyDown,
1311
+ onClick,
1312
+ autoFocus,
1313
+ className,
1314
+ isMulti,
1315
+ isFilterable,
1316
+ multiple,
1192
1317
  ...rest
1193
1318
  }) {
1194
- const { theme, borderSoft, focusRing, surfaceMuted } = useUiKitTheme(sdk);
1195
- const selectStyle = {
1196
- width: "100%",
1197
- borderRadius: 16,
1198
- border: `1px solid ${error ? theme.colors.negative : borderSoft}`,
1199
- padding: getPadding2(controlSize),
1200
- outline: "none",
1201
- color: theme.colors.onSurface,
1202
- backgroundColor: disabled ? surfaceMuted : theme.colors.surface,
1203
- boxShadow: error ? `0 0 0 3px ${(0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.negative, 0.12)}` : `0 0 0 0 ${focusRing}`,
1204
- transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
1205
- ...style
1319
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1320
+ const { theme, borderSoft, mutedText, surfaceMuted, surfaceRaised } = useUiKitTheme(sdk);
1321
+ const generatedId = (0, import_react6.useId)().replace(/:/g, "");
1322
+ const resolvedId = id != null ? id : `ss-select-${generatedId}`;
1323
+ const isMultiSelect = Boolean(isMulti || multiple);
1324
+ const hasFilter = Boolean(isFilterable);
1325
+ const groups = parseSelectChildren(children);
1326
+ const flatOptions = groups.flatMap((group) => group.options);
1327
+ const enabledOptions = flatOptions.filter((option) => !option.disabled);
1328
+ const isControlled = value !== void 0;
1329
+ const fallbackValues = defaultValue !== void 0 ? normalizeSelectValues(defaultValue) : isMultiSelect ? [] : ((_a = enabledOptions[0]) == null ? void 0 : _a.value) ? [enabledOptions[0].value] : [];
1330
+ const [uncontrolledValues, setUncontrolledValues] = (0, import_react6.useState)(fallbackValues);
1331
+ const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
1332
+ const [filterQuery, setFilterQuery] = (0, import_react6.useState)("");
1333
+ const [menuPlacement, setMenuPlacement] = (0, import_react6.useState)("bottom");
1334
+ const [isPlacementResolved, setIsPlacementResolved] = (0, import_react6.useState)(false);
1335
+ const [highlightedValue, setHighlightedValue] = (0, import_react6.useState)((_d = (_c = fallbackValues[0]) != null ? _c : (_b = enabledOptions[0]) == null ? void 0 : _b.value) != null ? _d : "");
1336
+ const shellRef = (0, import_react6.useRef)(null);
1337
+ const buttonRef = (0, import_react6.useRef)(null);
1338
+ const menuRef = (0, import_react6.useRef)(null);
1339
+ const searchInputRef = (0, import_react6.useRef)(null);
1340
+ const hiddenSelectRef = (0, import_react6.useRef)(null);
1341
+ const selectedValues = isControlled ? normalizeSelectValues(value) : uncontrolledValues;
1342
+ const selectedValue = (_e = selectedValues[0]) != null ? _e : "";
1343
+ const selectedOptions = flatOptions.filter((option) => selectedValues.includes(option.value));
1344
+ const selectedOption = (_f = selectedOptions[0]) != null ? _f : null;
1345
+ const displayLabel = isMultiSelect ? selectedOptions.length > 0 ? selectedOptions.map((option) => getTextContent(option.label).trim() || option.value).join(", ") : null : (_g = selectedOption == null ? void 0 : selectedOption.label) != null ? _g : selectedValue ? selectedValue : null;
1346
+ const displayContent = displayLabel != null ? displayLabel : "\xA0";
1347
+ const visibleGroups = hasFilter ? filterSelectGroups(groups, filterQuery) : groups;
1348
+ const visibleOptions = visibleGroups.flatMap((group) => group.options);
1349
+ const visibleEnabledOptions = visibleOptions.filter((option) => !option.disabled);
1350
+ const visibleEnabledValues = visibleEnabledOptions.map((option) => option.value);
1351
+ const selectedValuesKey = selectedValues.join("\0");
1352
+ const visibleEnabledValuesKey = visibleEnabledValues.join("\0");
1353
+ const indicatorOffset = getSelectIndicatorOffset(controlSize);
1354
+ const controlMetrics = getControlMetrics(controlSize);
1355
+ const listboxId = `${resolvedId}-listbox`;
1356
+ const scrollbarThumbColor = (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.22);
1357
+ const scrollbarThumbHoverColor = (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.32);
1358
+ const highlightedOption = (_h = visibleOptions.find((option) => option.value === highlightedValue)) != null ? _h : null;
1359
+ const optionHoverBackground = (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.primary, 1);
1360
+ const optionSelectedBackground = (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.primary, 1);
1361
+ const triggerShadow = error ? `0 0 0 3px ${(0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.negative, 0.12)}` : "none";
1362
+ const buttonPassthroughProps = Object.fromEntries(
1363
+ Object.entries(rest).filter(([key]) => key.startsWith("aria-") || key.startsWith("data-"))
1364
+ );
1365
+ (0, import_react6.useEffect)(() => {
1366
+ var _a2, _b2, _c2, _d2;
1367
+ if (isControlled) {
1368
+ return;
1369
+ }
1370
+ const invalidValues = uncontrolledValues.filter(
1371
+ (currentValue) => !flatOptions.some((option) => option.value === currentValue)
1372
+ );
1373
+ if (invalidValues.length === 0) {
1374
+ return;
1375
+ }
1376
+ const nextValues = defaultValue !== void 0 ? normalizeSelectValues(defaultValue).filter(
1377
+ (currentValue) => flatOptions.some((option) => option.value === currentValue)
1378
+ ) : isMultiSelect ? [] : ((_a2 = enabledOptions[0]) == null ? void 0 : _a2.value) ? [enabledOptions[0].value] : [];
1379
+ setUncontrolledValues(nextValues);
1380
+ setHighlightedValue((_d2 = (_c2 = nextValues[0]) != null ? _c2 : (_b2 = enabledOptions[0]) == null ? void 0 : _b2.value) != null ? _d2 : "");
1381
+ }, [children, defaultValue, enabledOptions, flatOptions, isControlled, isMultiSelect, uncontrolledValues]);
1382
+ (0, import_react6.useEffect)(() => {
1383
+ var _a2, _b2, _c2;
1384
+ if (!isOpen) {
1385
+ setMenuPlacement("bottom");
1386
+ setIsPlacementResolved(false);
1387
+ return;
1388
+ }
1389
+ const nextHighlightedValue = (_c2 = (_b2 = [...selectedValues].reverse().find((currentValue) => visibleEnabledValues.includes(currentValue))) != null ? _b2 : (_a2 = visibleEnabledOptions[0]) == null ? void 0 : _a2.value) != null ? _c2 : "";
1390
+ setHighlightedValue(nextHighlightedValue);
1391
+ }, [isOpen, selectedValuesKey, visibleEnabledValuesKey]);
1392
+ (0, import_react6.useEffect)(() => {
1393
+ var _a2;
1394
+ if (!isOpen || !hasFilter) {
1395
+ return;
1396
+ }
1397
+ (_a2 = searchInputRef.current) == null ? void 0 : _a2.focus();
1398
+ }, [hasFilter, isOpen]);
1399
+ (0, import_react6.useEffect)(() => {
1400
+ if (!isOpen) {
1401
+ return;
1402
+ }
1403
+ const frameId = window.requestAnimationFrame(() => {
1404
+ var _a2;
1405
+ const triggerRect = (_a2 = buttonRef.current) == null ? void 0 : _a2.getBoundingClientRect();
1406
+ const menuElement = menuRef.current;
1407
+ if (!triggerRect || !menuElement) {
1408
+ setMenuPlacement("bottom");
1409
+ setIsPlacementResolved(true);
1410
+ return;
1411
+ }
1412
+ const measuredMenuHeight = menuElement.getBoundingClientRect().height;
1413
+ const menuHeight = Math.min(measuredMenuHeight || menuElement.scrollHeight, MENU_MAX_HEIGHT);
1414
+ const availableBelow = window.innerHeight - triggerRect.bottom - MENU_OFFSET;
1415
+ const availableAbove = triggerRect.top - MENU_OFFSET;
1416
+ const nextPlacement = availableBelow < menuHeight && availableAbove >= menuHeight ? "top" : "bottom";
1417
+ setMenuPlacement(nextPlacement);
1418
+ setIsPlacementResolved(true);
1419
+ });
1420
+ return () => {
1421
+ window.cancelAnimationFrame(frameId);
1422
+ };
1423
+ }, [isOpen, visibleOptions.length]);
1424
+ (0, import_react6.useEffect)(() => {
1425
+ if (isOpen) {
1426
+ return;
1427
+ }
1428
+ setFilterQuery("");
1429
+ }, [isOpen]);
1430
+ (0, import_react6.useEffect)(() => {
1431
+ if (!isOpen) {
1432
+ return;
1433
+ }
1434
+ const handlePointerDown = (event) => {
1435
+ var _a2;
1436
+ if ((_a2 = shellRef.current) == null ? void 0 : _a2.contains(event.target)) {
1437
+ return;
1438
+ }
1439
+ setIsOpen(false);
1440
+ };
1441
+ document.addEventListener("pointerdown", handlePointerDown);
1442
+ return () => {
1443
+ document.removeEventListener("pointerdown", handlePointerDown);
1444
+ };
1445
+ }, [isOpen]);
1446
+ (0, import_react6.useEffect)(() => {
1447
+ var _a2;
1448
+ if (isControlled) {
1449
+ return;
1450
+ }
1451
+ const form = (_a2 = hiddenSelectRef.current) == null ? void 0 : _a2.form;
1452
+ if (!form) {
1453
+ return;
1454
+ }
1455
+ const handleReset = () => {
1456
+ queueMicrotask(() => {
1457
+ var _a3, _b2, _c2, _d2;
1458
+ const nextValues = defaultValue !== void 0 ? normalizeSelectValues(defaultValue) : isMultiSelect ? [] : ((_a3 = enabledOptions[0]) == null ? void 0 : _a3.value) ? [enabledOptions[0].value] : [];
1459
+ setUncontrolledValues(nextValues);
1460
+ setHighlightedValue((_d2 = (_c2 = nextValues[0]) != null ? _c2 : (_b2 = enabledOptions[0]) == null ? void 0 : _b2.value) != null ? _d2 : "");
1461
+ setIsOpen(false);
1462
+ });
1463
+ };
1464
+ form.addEventListener("reset", handleReset);
1465
+ return () => {
1466
+ form.removeEventListener("reset", handleReset);
1467
+ };
1468
+ }, [defaultValue, enabledOptions, isControlled, isMultiSelect]);
1469
+ const syncHiddenSelect = (nextValues) => {
1470
+ var _a2, _b2;
1471
+ const selectElement = hiddenSelectRef.current;
1472
+ if (!selectElement) {
1473
+ return;
1474
+ }
1475
+ if (isMultiSelect) {
1476
+ Array.from(selectElement.options).forEach((optionElement) => {
1477
+ optionElement.selected = nextValues.includes(optionElement.value);
1478
+ });
1479
+ } else {
1480
+ const descriptor = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, "value");
1481
+ if (descriptor == null ? void 0 : descriptor.set) {
1482
+ descriptor.set.call(selectElement, (_a2 = nextValues[0]) != null ? _a2 : "");
1483
+ } else {
1484
+ selectElement.value = (_b2 = nextValues[0]) != null ? _b2 : "";
1485
+ }
1486
+ }
1487
+ selectElement.dispatchEvent(new Event("change", { bubbles: true }));
1206
1488
  };
1207
- const select = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("select", { ...rest, id, disabled, style: selectStyle, children });
1208
- if (!label && !hint && !error) {
1209
- return select;
1210
- }
1211
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { sdk, label, hint, error, htmlFor: id, children: select });
1489
+ const updateMultiSelection = (nextValues) => {
1490
+ var _a2, _b2, _c2;
1491
+ if (!isMultiSelect || disabled) {
1492
+ return;
1493
+ }
1494
+ if (!isControlled) {
1495
+ setUncontrolledValues(nextValues);
1496
+ }
1497
+ setHighlightedValue((_c2 = (_b2 = nextValues[nextValues.length - 1]) != null ? _b2 : (_a2 = enabledOptions[0]) == null ? void 0 : _a2.value) != null ? _c2 : "");
1498
+ syncHiddenSelect(nextValues);
1499
+ };
1500
+ const toggleVisibleSelection = (checked) => {
1501
+ if (!isMultiSelect || disabled || visibleEnabledValues.length === 0) {
1502
+ return;
1503
+ }
1504
+ const nextValues = checked ? Array.from(/* @__PURE__ */ new Set([...selectedValues, ...visibleEnabledValues])) : selectedValues.filter((currentValue) => !visibleEnabledValues.includes(currentValue));
1505
+ updateMultiSelection(nextValues);
1506
+ };
1507
+ const commitSelection = (nextValue) => {
1508
+ var _a2;
1509
+ if (disabled) {
1510
+ if (!isMultiSelect) {
1511
+ setIsOpen(false);
1512
+ }
1513
+ return;
1514
+ }
1515
+ if (isMultiSelect) {
1516
+ const nextValues = selectedValues.includes(nextValue) ? selectedValues.filter((currentValue) => currentValue !== nextValue) : [...selectedValues, nextValue];
1517
+ updateMultiSelection(nextValues);
1518
+ return;
1519
+ }
1520
+ if (nextValue === selectedValue) {
1521
+ setIsOpen(false);
1522
+ return;
1523
+ }
1524
+ if (!isControlled) {
1525
+ setUncontrolledValues([nextValue]);
1526
+ }
1527
+ setHighlightedValue(nextValue);
1528
+ setIsOpen(false);
1529
+ syncHiddenSelect([nextValue]);
1530
+ (_a2 = buttonRef.current) == null ? void 0 : _a2.focus();
1531
+ };
1532
+ const handleHiddenSelectChange = (event) => {
1533
+ var _a2, _b2, _c2;
1534
+ const nextValues = isMultiSelect ? Array.from(event.currentTarget.selectedOptions, (option) => option.value) : [event.currentTarget.value];
1535
+ if (!isControlled) {
1536
+ setUncontrolledValues(nextValues);
1537
+ }
1538
+ setHighlightedValue((_c2 = (_b2 = nextValues[nextValues.length - 1]) != null ? _b2 : (_a2 = enabledOptions[0]) == null ? void 0 : _a2.value) != null ? _c2 : "");
1539
+ onChange == null ? void 0 : onChange(event);
1540
+ };
1541
+ const visibleSelectedCount = visibleEnabledValues.filter((currentValue) => selectedValues.includes(currentValue)).length;
1542
+ const hasSomeVisibleSelected = visibleSelectedCount > 0 && visibleSelectedCount < visibleEnabledValues.length;
1543
+ const hasAllVisibleSelected = visibleEnabledValues.length > 0 && visibleSelectedCount === visibleEnabledValues.length;
1544
+ const canToggleVisibleSelection = !disabled && visibleEnabledValues.length > 0;
1545
+ const bulkToggleControl = isMultiSelect ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1546
+ "button",
1547
+ {
1548
+ type: "button",
1549
+ role: "checkbox",
1550
+ "aria-label": "Toggle all visible options",
1551
+ "aria-checked": hasAllVisibleSelected ? true : hasSomeVisibleSelected ? "mixed" : false,
1552
+ disabled: !canToggleVisibleSelection,
1553
+ onMouseDown: (event) => {
1554
+ event.preventDefault();
1555
+ event.stopPropagation();
1556
+ },
1557
+ onClick: (event) => {
1558
+ event.stopPropagation();
1559
+ toggleVisibleSelection(!hasAllVisibleSelected);
1560
+ },
1561
+ style: {
1562
+ width: 20,
1563
+ height: 20,
1564
+ padding: 0,
1565
+ margin: 0,
1566
+ borderRadius: 999,
1567
+ border: `1.5px solid ${hasAllVisibleSelected || hasSomeVisibleSelected ? theme.colors.secondary : (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.22)}`,
1568
+ backgroundColor: hasAllVisibleSelected || hasSomeVisibleSelected ? theme.colors.secondary : theme.colors.surface,
1569
+ display: "inline-flex",
1570
+ alignItems: "center",
1571
+ justifyContent: "center",
1572
+ flexShrink: 0,
1573
+ cursor: canToggleVisibleSelection ? "pointer" : "not-allowed",
1574
+ opacity: canToggleVisibleSelection ? 1 : 0.45
1575
+ },
1576
+ children: hasAllVisibleSelected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1577
+ "span",
1578
+ {
1579
+ "aria-hidden": "true",
1580
+ style: {
1581
+ width: 8,
1582
+ height: 8,
1583
+ borderRadius: 999,
1584
+ backgroundColor: theme.colors.surface
1585
+ }
1586
+ }
1587
+ ) : hasSomeVisibleSelected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1588
+ "span",
1589
+ {
1590
+ "aria-hidden": "true",
1591
+ style: {
1592
+ width: 8,
1593
+ height: 2,
1594
+ borderRadius: 999,
1595
+ backgroundColor: theme.colors.surface
1596
+ }
1597
+ }
1598
+ ) : null
1599
+ }
1600
+ ) : null;
1601
+ const moveHighlight = (direction) => {
1602
+ if (visibleEnabledOptions.length === 0) {
1603
+ return;
1604
+ }
1605
+ const currentIndex = visibleEnabledOptions.findIndex((option) => option.value === highlightedValue);
1606
+ if (currentIndex === -1) {
1607
+ setHighlightedValue(
1608
+ direction === 1 ? visibleEnabledOptions[0].value : visibleEnabledOptions[visibleEnabledOptions.length - 1].value
1609
+ );
1610
+ return;
1611
+ }
1612
+ const nextIndex = Math.max(0, Math.min(visibleEnabledOptions.length - 1, currentIndex + direction));
1613
+ setHighlightedValue(visibleEnabledOptions[nextIndex].value);
1614
+ };
1615
+ const handleTriggerClick = (event) => {
1616
+ onClick == null ? void 0 : onClick(event);
1617
+ if (event.defaultPrevented || disabled || flatOptions.length === 0) {
1618
+ return;
1619
+ }
1620
+ setIsOpen((current) => !current);
1621
+ };
1622
+ const handleTriggerFocus = (event) => {
1623
+ onFocus == null ? void 0 : onFocus(event);
1624
+ };
1625
+ const handleTriggerBlur = (event) => {
1626
+ var _a2;
1627
+ const nextTarget = event.relatedTarget;
1628
+ if (!((_a2 = shellRef.current) == null ? void 0 : _a2.contains(nextTarget))) {
1629
+ setIsOpen(false);
1630
+ }
1631
+ onBlur == null ? void 0 : onBlur(event);
1632
+ };
1633
+ const handleTriggerKeyDown = (event) => {
1634
+ var _a2, _b2, _c2;
1635
+ onKeyDown == null ? void 0 : onKeyDown(event);
1636
+ if (event.defaultPrevented || disabled || visibleEnabledOptions.length === 0) {
1637
+ return;
1638
+ }
1639
+ if (event.key === "ArrowDown") {
1640
+ event.preventDefault();
1641
+ if (!isOpen) {
1642
+ setIsOpen(true);
1643
+ setHighlightedValue((_a2 = selectedOption == null ? void 0 : selectedOption.value) != null ? _a2 : visibleEnabledOptions[0].value);
1644
+ return;
1645
+ }
1646
+ moveHighlight(1);
1647
+ return;
1648
+ }
1649
+ if (event.key === "ArrowUp") {
1650
+ event.preventDefault();
1651
+ if (!isOpen) {
1652
+ setIsOpen(true);
1653
+ setHighlightedValue((_b2 = selectedOption == null ? void 0 : selectedOption.value) != null ? _b2 : visibleEnabledOptions[visibleEnabledOptions.length - 1].value);
1654
+ return;
1655
+ }
1656
+ moveHighlight(-1);
1657
+ return;
1658
+ }
1659
+ if (event.key === "Home" && isOpen) {
1660
+ event.preventDefault();
1661
+ setHighlightedValue(visibleEnabledOptions[0].value);
1662
+ return;
1663
+ }
1664
+ if (event.key === "End" && isOpen) {
1665
+ event.preventDefault();
1666
+ setHighlightedValue(visibleEnabledOptions[visibleEnabledOptions.length - 1].value);
1667
+ return;
1668
+ }
1669
+ if (event.key === "Enter" || event.key === " ") {
1670
+ event.preventDefault();
1671
+ if (!isOpen) {
1672
+ setIsOpen(true);
1673
+ setHighlightedValue((_c2 = selectedOption == null ? void 0 : selectedOption.value) != null ? _c2 : visibleEnabledOptions[0].value);
1674
+ return;
1675
+ }
1676
+ if (highlightedOption && !highlightedOption.disabled) {
1677
+ commitSelection(highlightedOption.value);
1678
+ }
1679
+ return;
1680
+ }
1681
+ if (event.key === "Escape" && isOpen) {
1682
+ event.preventDefault();
1683
+ setIsOpen(false);
1684
+ return;
1685
+ }
1686
+ if (event.key === "Tab") {
1687
+ setIsOpen(false);
1688
+ }
1689
+ };
1690
+ const handleFilterKeyDown = (event) => {
1691
+ var _a2;
1692
+ if (event.key === "ArrowDown") {
1693
+ event.preventDefault();
1694
+ moveHighlight(1);
1695
+ return;
1696
+ }
1697
+ if (event.key === "ArrowUp") {
1698
+ event.preventDefault();
1699
+ moveHighlight(-1);
1700
+ return;
1701
+ }
1702
+ if (event.key === "Enter") {
1703
+ event.preventDefault();
1704
+ if (highlightedOption && !highlightedOption.disabled) {
1705
+ commitSelection(highlightedOption.value);
1706
+ }
1707
+ return;
1708
+ }
1709
+ if (event.key === "Escape") {
1710
+ event.preventDefault();
1711
+ setIsOpen(false);
1712
+ (_a2 = buttonRef.current) == null ? void 0 : _a2.focus();
1713
+ return;
1714
+ }
1715
+ if (event.key === "Tab") {
1716
+ setIsOpen(false);
1717
+ }
1718
+ };
1719
+ const select = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: shellRef, style: { position: "relative", width: "100%" }, children: [
1720
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1721
+ "button",
1722
+ {
1723
+ ...buttonPassthroughProps,
1724
+ id: resolvedId,
1725
+ ref: buttonRef,
1726
+ type: "button",
1727
+ className,
1728
+ title: rest.title,
1729
+ disabled: disabled || flatOptions.length === 0,
1730
+ autoFocus,
1731
+ tabIndex: rest.tabIndex,
1732
+ role: "combobox",
1733
+ "aria-controls": listboxId,
1734
+ "aria-expanded": isOpen,
1735
+ "aria-haspopup": "listbox",
1736
+ "aria-invalid": error ? true : rest["aria-invalid"],
1737
+ "aria-required": rest.required,
1738
+ onClick: handleTriggerClick,
1739
+ onFocus: handleTriggerFocus,
1740
+ onBlur: handleTriggerBlur,
1741
+ onKeyDown: handleTriggerKeyDown,
1742
+ style: {
1743
+ width: "100%",
1744
+ boxSizing: "border-box",
1745
+ height: controlMetrics.height,
1746
+ borderRadius: 16,
1747
+ border: `1px solid ${error ? theme.colors.negative : (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.textLight, 0.5)}`,
1748
+ backgroundColor: theme.colors.surface,
1749
+ color: displayLabel ? theme.colors.onSurface : mutedText,
1750
+ cursor: disabled ? "not-allowed" : "pointer",
1751
+ opacity: disabled ? 0.7 : 1,
1752
+ padding: getSelectControlPadding(controlSize),
1753
+ outline: "none",
1754
+ font: "inherit",
1755
+ fontSize: controlMetrics.fontSize,
1756
+ lineHeight: controlMetrics.lineHeight,
1757
+ transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
1758
+ display: "flex",
1759
+ alignItems: "center",
1760
+ justifyContent: "space-between",
1761
+ gap: 12,
1762
+ minWidth: 0,
1763
+ textAlign: "left",
1764
+ ...style
1765
+ },
1766
+ children: [
1767
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1768
+ "span",
1769
+ {
1770
+ style: {
1771
+ display: "block",
1772
+ flex: "1 1 auto",
1773
+ minWidth: 0,
1774
+ overflow: "hidden",
1775
+ textOverflow: "ellipsis",
1776
+ whiteSpace: "nowrap"
1777
+ },
1778
+ children: displayContent
1779
+ }
1780
+ ),
1781
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1782
+ "span",
1783
+ {
1784
+ "aria-hidden": "true",
1785
+ style: {
1786
+ position: "absolute",
1787
+ right: indicatorOffset,
1788
+ top: "50%",
1789
+ transform: `translateY(-50%) rotate(${isOpen ? 180 : 0}deg)`,
1790
+ transformOrigin: "center",
1791
+ color: disabled ? (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.42) : mutedText,
1792
+ display: "flex",
1793
+ alignItems: "center",
1794
+ justifyContent: "center",
1795
+ pointerEvents: "none",
1796
+ transition: "transform 160ms ease, color 160ms ease"
1797
+ },
1798
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1799
+ "path",
1800
+ {
1801
+ d: "M5.75 7.75L10 12l4.25-4.25",
1802
+ stroke: "currentColor",
1803
+ strokeWidth: "1.8",
1804
+ strokeLinecap: "round",
1805
+ strokeLinejoin: "round"
1806
+ }
1807
+ ) })
1808
+ }
1809
+ )
1810
+ ]
1811
+ }
1812
+ ),
1813
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1814
+ "select",
1815
+ {
1816
+ ...rest,
1817
+ id: `${resolvedId}-native`,
1818
+ ref: hiddenSelectRef,
1819
+ name: rest.name,
1820
+ disabled,
1821
+ multiple: isMultiSelect,
1822
+ value: isMultiSelect ? selectedValues : selectedValue,
1823
+ onChange: handleHiddenSelectChange,
1824
+ tabIndex: -1,
1825
+ "aria-hidden": "true",
1826
+ style: {
1827
+ position: "absolute",
1828
+ width: 1,
1829
+ height: 1,
1830
+ padding: 0,
1831
+ margin: 0,
1832
+ border: 0,
1833
+ opacity: 0,
1834
+ pointerEvents: "none",
1835
+ clipPath: "inset(50%)"
1836
+ },
1837
+ children
1838
+ }
1839
+ ),
1840
+ isOpen ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1841
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
1842
+ #${listboxId} {
1843
+ scrollbar-width: thin;
1844
+ scrollbar-color: ${scrollbarThumbColor} transparent;
1845
+ }
1846
+
1847
+ #${listboxId}::-webkit-scrollbar {
1848
+ width: 8px;
1849
+ }
1850
+
1851
+ #${listboxId}::-webkit-scrollbar-track {
1852
+ background: transparent;
1853
+ }
1854
+
1855
+ #${listboxId}::-webkit-scrollbar-thumb {
1856
+ background: ${scrollbarThumbColor};
1857
+ border-radius: 999px;
1858
+ border: 2px solid transparent;
1859
+ background-clip: padding-box;
1860
+ }
1861
+
1862
+ #${listboxId}::-webkit-scrollbar-thumb:hover {
1863
+ background: ${scrollbarThumbHoverColor};
1864
+ background-clip: padding-box;
1865
+ }
1866
+ ` }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1868
+ "div",
1869
+ {
1870
+ ref: menuRef,
1871
+ style: {
1872
+ position: "absolute",
1873
+ top: menuPlacement === "bottom" ? `calc(100% + ${MENU_OFFSET}px)` : "auto",
1874
+ bottom: menuPlacement === "top" ? `calc(100% + ${MENU_OFFSET}px)` : "auto",
1875
+ left: 0,
1876
+ right: 0,
1877
+ zIndex: 30,
1878
+ maxHeight: MENU_MAX_HEIGHT,
1879
+ overflow: "hidden",
1880
+ boxSizing: "border-box",
1881
+ borderRadius: 20,
1882
+ border: `1px solid ${(0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.textLight, 0.5)}`,
1883
+ backgroundColor: surfaceRaised,
1884
+ // boxShadow: `0 10px 24px ${withAlpha(theme.colors.onSurface, 0.08)}`,
1885
+ padding: 8,
1886
+ backdropFilter: "blur(6px)",
1887
+ visibility: isPlacementResolved ? "visible" : "hidden",
1888
+ display: "flex",
1889
+ flexDirection: "column",
1890
+ gap: 4
1891
+ },
1892
+ children: [
1893
+ hasFilter ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1894
+ "div",
1895
+ {
1896
+ style: {
1897
+ display: "flex",
1898
+ alignItems: "center",
1899
+ justifyContent: "flex-start",
1900
+ gap: 8,
1901
+ padding: "4px 4px 10px",
1902
+ borderBottom: `1px solid ${(0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.08)}`,
1903
+ flexShrink: 0
1904
+ },
1905
+ children: [
1906
+ bulkToggleControl,
1907
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1908
+ "input",
1909
+ {
1910
+ ref: searchInputRef,
1911
+ type: "search",
1912
+ value: filterQuery,
1913
+ onChange: (event) => {
1914
+ setFilterQuery(event.currentTarget.value);
1915
+ },
1916
+ onKeyDown: handleFilterKeyDown,
1917
+ onMouseDown: (event) => {
1918
+ event.stopPropagation();
1919
+ },
1920
+ placeholder: "Search options",
1921
+ "aria-label": "Search options",
1922
+ style: {
1923
+ flex: "1 1 auto",
1924
+ width: "100%",
1925
+ border: `1px solid ${(0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.textLight, 0.5)}`,
1926
+ backgroundColor: theme.colors.surface,
1927
+ padding: "8px 12px",
1928
+ borderRadius: 12,
1929
+ font: "inherit",
1930
+ fontSize: 12,
1931
+ lineHeight: 1.4,
1932
+ color: theme.colors.textLight,
1933
+ outline: "none",
1934
+ boxSizing: "border-box"
1935
+ }
1936
+ }
1937
+ )
1938
+ ]
1939
+ }
1940
+ ) : isMultiSelect ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1941
+ "div",
1942
+ {
1943
+ style: {
1944
+ display: "flex",
1945
+ alignItems: "center",
1946
+ justifyContent: "flex-start",
1947
+ padding: "4px 4px 10px",
1948
+ borderBottom: `1px solid ${(0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.08)}`,
1949
+ flexShrink: 0
1950
+ },
1951
+ children: bulkToggleControl
1952
+ }
1953
+ ) : null,
1954
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1955
+ "div",
1956
+ {
1957
+ id: listboxId,
1958
+ role: "listbox",
1959
+ "aria-labelledby": resolvedId,
1960
+ "aria-multiselectable": isMultiSelect || void 0,
1961
+ style: {
1962
+ overflowY: "auto",
1963
+ overflowX: "hidden",
1964
+ minHeight: 0,
1965
+ flex: "1 1 auto"
1966
+ },
1967
+ children: visibleGroups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1968
+ "div",
1969
+ {
1970
+ style: {
1971
+ padding: "14px 12px",
1972
+ color: mutedText,
1973
+ fontSize: 13,
1974
+ textAlign: "center"
1975
+ },
1976
+ children: "No options found."
1977
+ }
1978
+ ) : visibleGroups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1979
+ "div",
1980
+ {
1981
+ style: {
1982
+ display: "flex",
1983
+ flexDirection: "column",
1984
+ gap: 4,
1985
+ marginTop: group.label ? 4 : 0
1986
+ },
1987
+ children: [
1988
+ group.label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1989
+ "span",
1990
+ {
1991
+ style: {
1992
+ padding: "6px 8px 2px",
1993
+ color: mutedText,
1994
+ fontSize: 11,
1995
+ fontWeight: 800,
1996
+ letterSpacing: "0.08em",
1997
+ textTransform: "uppercase"
1998
+ },
1999
+ children: group.label
2000
+ }
2001
+ ) : null,
2002
+ group.options.map((option) => {
2003
+ const isSelected = selectedValues.includes(option.value);
2004
+ const isHighlighted = option.value === highlightedValue;
2005
+ const isActive = isSelected || isHighlighted;
2006
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2007
+ "div",
2008
+ {
2009
+ role: "option",
2010
+ "aria-selected": isSelected,
2011
+ "aria-disabled": option.disabled,
2012
+ onMouseEnter: () => {
2013
+ if (!option.disabled) {
2014
+ setHighlightedValue(option.value);
2015
+ }
2016
+ },
2017
+ onMouseDown: (event) => {
2018
+ event.preventDefault();
2019
+ },
2020
+ onClick: () => {
2021
+ if (!option.disabled) {
2022
+ commitSelection(option.value);
2023
+ }
2024
+ },
2025
+ style: {
2026
+ display: "flex",
2027
+ alignItems: "center",
2028
+ justifyContent: "space-between",
2029
+ gap: 12,
2030
+ width: "100%",
2031
+ minWidth: 0,
2032
+ boxSizing: "border-box",
2033
+ borderRadius: 14,
2034
+ padding: getOptionPadding(controlSize),
2035
+ cursor: option.disabled ? "not-allowed" : "pointer",
2036
+ color: option.disabled ? (0, import_smartsell_sales_sdk6.withAlpha)(theme.colors.onSurface, 0.38) : isActive ? theme.colors.onPrimary : theme.colors.onSurface,
2037
+ backgroundColor: isSelected ? optionSelectedBackground : isHighlighted ? optionHoverBackground : "transparent",
2038
+ fontWeight: isSelected ? 700 : 500,
2039
+ transition: "background-color 140ms ease, color 140ms ease"
2040
+ },
2041
+ children: [
2042
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2043
+ "span",
2044
+ {
2045
+ style: {
2046
+ display: "flex",
2047
+ alignItems: "center",
2048
+ gap: 10,
2049
+ flex: "1 1 auto",
2050
+ minWidth: 0
2051
+ },
2052
+ children: [
2053
+ isMultiSelect ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2054
+ "span",
2055
+ {
2056
+ "aria-hidden": "true",
2057
+ style: {
2058
+ width: 10,
2059
+ height: 10,
2060
+ borderRadius: 999,
2061
+ flexShrink: 0,
2062
+ border: `1.5px solid ${isSelected ? theme.colors.secondary : "currentColor"}`,
2063
+ backgroundColor: isSelected ? theme.colors.secondary : "transparent",
2064
+ opacity: option.disabled ? 0.45 : 1,
2065
+ transition: "background-color 140ms ease, border-color 140ms ease, opacity 140ms ease"
2066
+ }
2067
+ }
2068
+ ) : null,
2069
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2070
+ "span",
2071
+ {
2072
+ style: {
2073
+ display: "block",
2074
+ flex: "1 1 auto",
2075
+ minWidth: 0,
2076
+ overflow: "hidden",
2077
+ textOverflow: "ellipsis",
2078
+ whiteSpace: "nowrap"
2079
+ },
2080
+ children: option.label
2081
+ }
2082
+ )
2083
+ ]
2084
+ }
2085
+ ),
2086
+ isSelected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2087
+ "span",
2088
+ {
2089
+ "aria-hidden": "true",
2090
+ style: {
2091
+ display: "flex",
2092
+ alignItems: "center",
2093
+ justifyContent: "center",
2094
+ color: theme.colors.primary,
2095
+ flexShrink: 0
2096
+ },
2097
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2098
+ "path",
2099
+ {
2100
+ d: "M5.75 10.25L8.5 13l5.75-6",
2101
+ stroke: "currentColor",
2102
+ strokeWidth: "1.8",
2103
+ strokeLinecap: "round",
2104
+ strokeLinejoin: "round"
2105
+ }
2106
+ ) })
2107
+ }
2108
+ ) : null
2109
+ ]
2110
+ },
2111
+ option.key
2112
+ );
2113
+ })
2114
+ ]
2115
+ },
2116
+ group.key
2117
+ ))
2118
+ }
2119
+ )
2120
+ ]
2121
+ }
2122
+ )
2123
+ ] }) : null
2124
+ ] });
2125
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2126
+ ControlFrame,
2127
+ {
2128
+ sdk,
2129
+ label,
2130
+ hint,
2131
+ error,
2132
+ htmlFor: resolvedId,
2133
+ required: rest.required,
2134
+ useLabelWrapper: false,
2135
+ children: select
2136
+ }
2137
+ );
1212
2138
  }
1213
2139
 
1214
2140
  // src/components/Textarea.tsx
1215
2141
  var import_smartsell_sales_sdk7 = require("smartsell-sales-sdk");
1216
- var import_jsx_runtime8 = require("react/jsx-runtime");
1217
- var getPadding3 = (size) => {
2142
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2143
+ var getPadding = (size) => {
1218
2144
  if (size === "sm") return "10px 12px";
1219
2145
  if (size === "lg") return "16px 18px";
1220
2146
  return "13px 16px";
@@ -1233,30 +2159,29 @@ function Textarea({
1233
2159
  }) {
1234
2160
  const { theme, borderSoft, focusRing, surfaceMuted } = useUiKitTheme(sdk);
1235
2161
  const textareaStyle = {
2162
+ border: `1px solid ${error ? theme.colors.negative : (0, import_smartsell_sales_sdk7.withAlpha)(theme.colors.textLight, 0.5)}`,
2163
+ backgroundColor: theme.colors.surface,
2164
+ color: theme.colors.text,
2165
+ cursor: disabled ? "not-allowed" : "text",
2166
+ opacity: disabled ? 0.7 : 1,
1236
2167
  width: "100%",
2168
+ boxSizing: "border-box",
1237
2169
  borderRadius: 16,
1238
- border: `1px solid ${error ? theme.colors.negative : borderSoft}`,
1239
- padding: getPadding3(controlSize),
2170
+ padding: getPadding(controlSize),
1240
2171
  outline: "none",
1241
- color: theme.colors.onSurface,
1242
- backgroundColor: disabled ? surfaceMuted : theme.colors.surface,
1243
2172
  boxShadow: error ? `0 0 0 3px ${(0, import_smartsell_sales_sdk7.withAlpha)(theme.colors.negative, 0.12)}` : `0 0 0 0 ${focusRing}`,
1244
2173
  transition: "border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease",
1245
2174
  resize: "vertical",
1246
2175
  ...style
1247
2176
  };
1248
- const textarea = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { ...rest, id, disabled, rows, style: textareaStyle });
1249
- if (!label && !hint && !error) {
1250
- return textarea;
1251
- }
1252
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Field, { sdk, label, hint, error, htmlFor: id, children: textarea });
2177
+ const textarea = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { ...rest, id, disabled, rows, style: textareaStyle });
2178
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ControlFrame, { sdk, label, hint, error, htmlFor: id, required: rest.required, children: textarea });
1253
2179
  }
1254
2180
  // Annotate the CommonJS export names for ESM import in node:
1255
2181
  0 && (module.exports = {
1256
2182
  Button,
1257
2183
  Card,
1258
2184
  ComposableModal,
1259
- Field,
1260
2185
  Input,
1261
2186
  Modal,
1262
2187
  Select,