myoperator-ui 0.0.219 → 0.0.220

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.
Files changed (2) hide show
  1. package/dist/index.js +1809 -757
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -118,6 +118,7 @@ function transformSemanticClassesInContent(content) {
118
118
  const cnRegex = /\bcn\s*\(/g;
119
119
  let cnMatch;
120
120
  while ((cnMatch = cnRegex.exec(content)) !== null) {
121
+ if (cnMatch.index < lastIndex) continue;
121
122
  result += content.slice(lastIndex, cnMatch.index);
122
123
  let depth = 1;
123
124
  let i = cnMatch.index + cnMatch[0].length;
@@ -266,8 +267,10 @@ function looksLikeTailwindClasses(str) {
266
267
  return false;
267
268
  });
268
269
  }
270
+ var BORDER_WIDTH_RE = /^border(-[trblxy])?(-[0248]|-\[.+\])?$/;
271
+ var BORDER_STYLE_RE = /^border-(solid|dashed|dotted|double|hidden|none)$/;
269
272
  function prefixClassString(classString, prefix) {
270
- return classString.split(" ").map((cls) => {
273
+ const prefixed = classString.split(" ").map((cls) => {
271
274
  if (!cls) return cls;
272
275
  if ((cls.startsWith("aria-") || cls.startsWith("data-")) && !cls.includes("[") && !cls.includes(":")) return cls;
273
276
  if (cls.startsWith("[&") || cls.startsWith("[&_")) {
@@ -317,7 +320,14 @@ function prefixClassString(classString, prefix) {
317
320
  return `-${prefix}${cls.slice(1)}`;
318
321
  }
319
322
  return `${prefix}${cls}`;
320
- }).join(" ");
323
+ });
324
+ const origClasses = classString.split(" ");
325
+ const hasBorderWidth = origClasses.some((c) => BORDER_WIDTH_RE.test(c));
326
+ const hasBorderStyle = origClasses.some((c) => BORDER_STYLE_RE.test(c));
327
+ if (hasBorderWidth && !hasBorderStyle) {
328
+ prefixed.push(`${prefix}border-solid`);
329
+ }
330
+ return prefixed.join(" ");
321
331
  }
322
332
  function prefixTailwindClasses(content, prefix) {
323
333
  content = transformSemanticClassesInContent(content);
@@ -335,6 +345,7 @@ function prefixTailwindClasses(content, prefix) {
335
345
  const cnRegex = /\bcn\s*\(/g;
336
346
  let cnMatch;
337
347
  while ((cnMatch = cnRegex.exec(content)) !== null) {
348
+ if (cnMatch.index < lastIndex) continue;
338
349
  result += content.slice(lastIndex, cnMatch.index);
339
350
  let depth = 1;
340
351
  let i = cnMatch.index + cnMatch[0].length;
@@ -373,7 +384,120 @@ function prefixTailwindClasses(content, prefix) {
373
384
  return `className="${prefixed}"`;
374
385
  }
375
386
  );
376
- const nonClassKeys = ["name", "displayName", "type", "role", "id", "htmlFor", "for", "placeholder", "alt", "src", "href", "target", "rel", "method", "action", "enctype", "accept", "pattern", "autocomplete", "value", "defaultValue", "label", "text", "message", "helperText", "ariaLabel", "ariaDescribedBy", "description", "title", "content", "header", "footer", "caption", "summary", "tooltip", "errorMessage", "successMessage", "warningMessage", "infoMessage", "hint"];
387
+ const nonClassKeys = [
388
+ // HTML attributes
389
+ "name",
390
+ "displayName",
391
+ "type",
392
+ "role",
393
+ "id",
394
+ "htmlFor",
395
+ "for",
396
+ "placeholder",
397
+ "alt",
398
+ "src",
399
+ "href",
400
+ "target",
401
+ "rel",
402
+ "method",
403
+ "action",
404
+ "enctype",
405
+ "accept",
406
+ "pattern",
407
+ "autocomplete",
408
+ "value",
409
+ "defaultValue",
410
+ "label",
411
+ "text",
412
+ "message",
413
+ "helperText",
414
+ "ariaLabel",
415
+ "ariaDescribedBy",
416
+ "description",
417
+ "title",
418
+ "content",
419
+ "header",
420
+ "footer",
421
+ "caption",
422
+ "summary",
423
+ "tooltip",
424
+ "errorMessage",
425
+ "successMessage",
426
+ "warningMessage",
427
+ "infoMessage",
428
+ "hint",
429
+ // CSS style properties (camelCase — safe because they can't be CVA variant keys)
430
+ "width",
431
+ "height",
432
+ "minWidth",
433
+ "maxWidth",
434
+ "minHeight",
435
+ "maxHeight",
436
+ "padding",
437
+ "paddingTop",
438
+ "paddingRight",
439
+ "paddingBottom",
440
+ "paddingLeft",
441
+ "margin",
442
+ "marginTop",
443
+ "marginRight",
444
+ "marginBottom",
445
+ "marginLeft",
446
+ "fontSize",
447
+ "fontWeight",
448
+ "fontFamily",
449
+ "fontStyle",
450
+ "lineHeight",
451
+ "letterSpacing",
452
+ "backgroundColor",
453
+ "borderColor",
454
+ "borderWidth",
455
+ "borderStyle",
456
+ "borderRadius",
457
+ "zIndex",
458
+ "overflow",
459
+ "overflowX",
460
+ "overflowY",
461
+ "userSelect",
462
+ "transitionDuration",
463
+ "transitionProperty",
464
+ "boxShadow",
465
+ "textShadow",
466
+ "outlineOffset",
467
+ "rowGap",
468
+ "columnGap",
469
+ "gridTemplateColumns",
470
+ "gridTemplateRows",
471
+ "flexBasis",
472
+ "flexGrow",
473
+ "flexShrink",
474
+ "flexDirection",
475
+ "flexWrap",
476
+ "alignItems",
477
+ "alignSelf",
478
+ "justifyContent",
479
+ "justifyItems",
480
+ "textAlign",
481
+ "textDecoration",
482
+ "textTransform",
483
+ "whiteSpace",
484
+ "wordBreak",
485
+ "wordSpacing",
486
+ "aspectRatio",
487
+ "scrollbarWidth",
488
+ "scrollBehavior",
489
+ "backgroundImage",
490
+ "backgroundSize",
491
+ "backgroundPosition",
492
+ "backgroundRepeat",
493
+ "borderTop",
494
+ "borderRight",
495
+ "borderBottom",
496
+ "borderLeft",
497
+ "strokeWidth",
498
+ "strokeDasharray",
499
+ "strokeDashoffset"
500
+ ];
377
501
  function hasObviousTailwindPatterns(value) {
378
502
  return /(?:^|\s)(hover|focus|active|disabled|group|peer|data-|aria-|sm:|md:|lg:|xl:|2xl:|dark:)/.test(value) || // Group/peer with selectors
379
503
  /group-\[|peer-\[/.test(value) || // Arbitrary selectors
@@ -433,8 +557,264 @@ function prefixTailwindClasses(content, prefix) {
433
557
  return `${funcName}('${prefixed}'`;
434
558
  }
435
559
  );
560
+ {
561
+ let jsxResult = "";
562
+ let jsxLastIndex = 0;
563
+ const jsxRegex = /className\s*=\s*\{/g;
564
+ let jsxMatch;
565
+ while ((jsxMatch = jsxRegex.exec(content)) !== null) {
566
+ if (jsxMatch.index < jsxLastIndex) continue;
567
+ jsxResult += content.slice(jsxLastIndex, jsxMatch.index);
568
+ const bracePos = jsxMatch.index + jsxMatch[0].length - 1;
569
+ let depth = 1;
570
+ let pos = bracePos + 1;
571
+ while (pos < content.length && depth > 0) {
572
+ const ch = content[pos];
573
+ if (ch === "{") {
574
+ depth++;
575
+ pos++;
576
+ continue;
577
+ }
578
+ if (ch === "}") {
579
+ depth--;
580
+ if (depth === 0) {
581
+ pos++;
582
+ break;
583
+ }
584
+ pos++;
585
+ continue;
586
+ }
587
+ if (ch === '"') {
588
+ pos++;
589
+ while (pos < content.length && content[pos] !== '"') {
590
+ if (content[pos] === "\\") pos++;
591
+ pos++;
592
+ }
593
+ pos++;
594
+ continue;
595
+ }
596
+ if (ch === "'") {
597
+ pos++;
598
+ while (pos < content.length && content[pos] !== "'") {
599
+ if (content[pos] === "\\") pos++;
600
+ pos++;
601
+ }
602
+ pos++;
603
+ continue;
604
+ }
605
+ if (ch === "`") {
606
+ pos++;
607
+ let tDepth = 0;
608
+ while (pos < content.length) {
609
+ if (content[pos] === "\\") {
610
+ pos += 2;
611
+ continue;
612
+ }
613
+ if (content[pos] === "`" && tDepth === 0) {
614
+ pos++;
615
+ break;
616
+ }
617
+ if (content[pos] === "$" && content[pos + 1] === "{") {
618
+ tDepth++;
619
+ pos += 2;
620
+ continue;
621
+ }
622
+ if (content[pos] === "}" && tDepth > 0) {
623
+ tDepth--;
624
+ pos++;
625
+ continue;
626
+ }
627
+ pos++;
628
+ }
629
+ continue;
630
+ }
631
+ pos++;
632
+ }
633
+ const expr = content.slice(bracePos + 1, pos - 1);
634
+ const exprTrimmed = expr.trimStart();
635
+ if (/^(cn|cva)\s*\(/.test(exprTrimmed)) {
636
+ jsxResult += content.slice(jsxMatch.index, pos);
637
+ jsxLastIndex = pos;
638
+ continue;
639
+ }
640
+ const prefixedExpr = prefixClassNameExpression(expr, prefix);
641
+ jsxResult += jsxMatch[0] + prefixedExpr + "}";
642
+ jsxLastIndex = pos;
643
+ }
644
+ jsxResult += content.slice(jsxLastIndex);
645
+ content = jsxResult;
646
+ }
436
647
  return content;
437
648
  }
649
+ function isAlreadyPrefixed(classString, prefix) {
650
+ if (!classString.trim()) return false;
651
+ return classString.trim().split(/\s+/).every((c) => {
652
+ const lastColon = c.lastIndexOf(":");
653
+ const utility = lastColon >= 0 ? c.slice(lastColon + 1) : c;
654
+ return utility.startsWith(prefix) || utility.startsWith(`-${prefix}`) || utility.startsWith(`!${prefix}`) || utility.startsWith(`!-${prefix}`);
655
+ });
656
+ }
657
+ function prefixStaticTemplatePart(text, prefix) {
658
+ const trimmed = text.trim();
659
+ if (!trimmed || !looksLikeTailwindClasses(trimmed)) return text;
660
+ const leading = text.match(/^(\s*)/)?.[1] || "";
661
+ const trailing = text.match(/(\s*)$/)?.[1] || "";
662
+ return leading + prefixClassString(trimmed, prefix) + trailing;
663
+ }
664
+ function prefixStringLiteralsInExpr(code, prefix) {
665
+ let result = code.replace(/"([^"]*)"/g, (m, classes) => {
666
+ if (!classes.trim() || !looksLikeTailwindClasses(classes) || isAlreadyPrefixed(classes, prefix)) return m;
667
+ return `"${prefixClassString(classes, prefix)}"`;
668
+ });
669
+ result = result.replace(/'([^']*)'/g, (m, classes) => {
670
+ if (!classes.trim() || !looksLikeTailwindClasses(classes) || isAlreadyPrefixed(classes, prefix)) return m;
671
+ return `'${prefixClassString(classes, prefix)}'`;
672
+ });
673
+ return result;
674
+ }
675
+ function prefixClassNameExpression(expr, prefix) {
676
+ let result = "";
677
+ let i = 0;
678
+ while (i < expr.length) {
679
+ if (expr[i] === "`") {
680
+ result += "`";
681
+ i++;
682
+ let staticText = "";
683
+ while (i < expr.length && expr[i] !== "`") {
684
+ if (expr[i] === "\\") {
685
+ staticText += expr[i] + (expr[i + 1] || "");
686
+ i += 2;
687
+ continue;
688
+ }
689
+ if (expr[i] === "$" && i + 1 < expr.length && expr[i + 1] === "{") {
690
+ if (staticText) {
691
+ result += prefixStaticTemplatePart(staticText, prefix);
692
+ staticText = "";
693
+ }
694
+ result += "${";
695
+ i += 2;
696
+ let exprDepth = 1;
697
+ let exprContent = "";
698
+ while (i < expr.length && exprDepth > 0) {
699
+ if (expr[i] === '"') {
700
+ exprContent += expr[i];
701
+ i++;
702
+ while (i < expr.length && expr[i] !== '"') {
703
+ if (expr[i] === "\\") {
704
+ exprContent += expr[i];
705
+ i++;
706
+ }
707
+ exprContent += expr[i];
708
+ i++;
709
+ }
710
+ if (i < expr.length) {
711
+ exprContent += expr[i];
712
+ i++;
713
+ }
714
+ continue;
715
+ }
716
+ if (expr[i] === "'") {
717
+ exprContent += expr[i];
718
+ i++;
719
+ while (i < expr.length && expr[i] !== "'") {
720
+ if (expr[i] === "\\") {
721
+ exprContent += expr[i];
722
+ i++;
723
+ }
724
+ exprContent += expr[i];
725
+ i++;
726
+ }
727
+ if (i < expr.length) {
728
+ exprContent += expr[i];
729
+ i++;
730
+ }
731
+ continue;
732
+ }
733
+ if (expr[i] === "`") {
734
+ exprContent += expr[i];
735
+ i++;
736
+ let nestedDepth = 0;
737
+ while (i < expr.length) {
738
+ if (expr[i] === "\\") {
739
+ exprContent += expr[i];
740
+ i++;
741
+ if (i < expr.length) {
742
+ exprContent += expr[i];
743
+ i++;
744
+ }
745
+ ;
746
+ continue;
747
+ }
748
+ if (expr[i] === "`" && nestedDepth === 0) {
749
+ exprContent += expr[i];
750
+ i++;
751
+ break;
752
+ }
753
+ if (expr[i] === "$" && i + 1 < expr.length && expr[i + 1] === "{") {
754
+ nestedDepth++;
755
+ exprContent += "${";
756
+ i += 2;
757
+ continue;
758
+ }
759
+ if (expr[i] === "}" && nestedDepth > 0) {
760
+ nestedDepth--;
761
+ }
762
+ exprContent += expr[i];
763
+ i++;
764
+ }
765
+ continue;
766
+ }
767
+ if (expr[i] === "{") exprDepth++;
768
+ else if (expr[i] === "}") {
769
+ exprDepth--;
770
+ if (exprDepth === 0) {
771
+ i++;
772
+ break;
773
+ }
774
+ }
775
+ exprContent += expr[i];
776
+ i++;
777
+ }
778
+ result += prefixStringLiteralsInExpr(exprContent, prefix) + "}";
779
+ continue;
780
+ }
781
+ staticText += expr[i];
782
+ i++;
783
+ }
784
+ if (staticText) {
785
+ result += prefixStaticTemplatePart(staticText, prefix);
786
+ }
787
+ if (i < expr.length && expr[i] === "`") {
788
+ result += "`";
789
+ i++;
790
+ }
791
+ } else if (expr[i] === '"' || expr[i] === "'") {
792
+ const quote = expr[i];
793
+ const strStart = i;
794
+ i++;
795
+ let str = "";
796
+ while (i < expr.length && expr[i] !== quote) {
797
+ if (expr[i] === "\\") {
798
+ str += expr[i] + (expr[i + 1] || "");
799
+ i += 2;
800
+ continue;
801
+ }
802
+ str += expr[i];
803
+ i++;
804
+ }
805
+ if (i < expr.length) i++;
806
+ if (str.trim() && looksLikeTailwindClasses(str) && !isAlreadyPrefixed(str, prefix)) {
807
+ result += quote + prefixClassString(str, prefix) + quote;
808
+ } else {
809
+ result += expr.slice(strStart, i);
810
+ }
811
+ } else {
812
+ result += expr[i];
813
+ i++;
814
+ }
815
+ }
816
+ return result;
817
+ }
438
818
  async function getRegistry(prefix = "") {
439
819
  return {
440
820
  "avatar": {
@@ -534,7 +914,7 @@ export interface AvatarProps
534
914
  * <Avatar initials="AS" size="xs" />
535
915
  * \`\`\`
536
916
  */
537
- const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
917
+ const Avatar = React.forwardRef(
538
918
  (
539
919
  {
540
920
  className,
@@ -547,8 +927,8 @@ const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
547
927
  status,
548
928
  children,
549
929
  ...props
550
- },
551
- ref
930
+ }: AvatarProps,
931
+ ref: React.Ref<HTMLDivElement>
552
932
  ) => {
553
933
  const resolvedSize = size ?? "md";
554
934
  const displayInitials = initials ?? (name ? getInitials(name) : undefined);
@@ -625,8 +1005,8 @@ export interface DateDividerProps
625
1005
  children: React.ReactNode;
626
1006
  }
627
1007
 
628
- const DateDivider = React.forwardRef<HTMLDivElement, DateDividerProps>(
629
- ({ className, children, ...props }, ref) => (
1008
+ const DateDivider = React.forwardRef(
1009
+ ({ className, children, ...props }: DateDividerProps, ref: React.Ref<HTMLDivElement>) => (
630
1010
  <div
631
1011
  ref={ref}
632
1012
  className={cn("flex items-center gap-4 my-4", className)}
@@ -682,8 +1062,8 @@ export interface ImageMediaProps extends React.HTMLAttributes<HTMLDivElement> {
682
1062
  maxHeight?: number | string;
683
1063
  }
684
1064
 
685
- const ImageMedia = React.forwardRef<HTMLDivElement, ImageMediaProps>(
686
- ({ className, src, alt = "Image", maxHeight = 280, ...props }, ref) => {
1065
+ const ImageMedia = React.forwardRef(
1066
+ ({ className, src, alt = "Image", maxHeight = 280, ...props }: ImageMediaProps, ref: React.Ref<HTMLDivElement>) => {
687
1067
  const maxHeightStyle =
688
1068
  typeof maxHeight === "number" ? \`\${maxHeight}px\` : maxHeight;
689
1069
 
@@ -747,7 +1127,7 @@ export interface PhoneInputProps
747
1127
  wrapperClassName?: string;
748
1128
  }
749
1129
 
750
- const PhoneInput = React.forwardRef<HTMLInputElement, PhoneInputProps>(
1130
+ const PhoneInput = React.forwardRef(
751
1131
  (
752
1132
  {
753
1133
  className,
@@ -758,8 +1138,8 @@ const PhoneInput = React.forwardRef<HTMLInputElement, PhoneInputProps>(
758
1138
  wrapperClassName,
759
1139
  disabled,
760
1140
  ...props
761
- },
762
- ref
1141
+ }: PhoneInputProps,
1142
+ ref: React.Ref<HTMLInputElement>
763
1143
  ) => {
764
1144
  return (
765
1145
  <div
@@ -843,8 +1223,8 @@ export interface ReplyQuoteProps extends React.HTMLAttributes<HTMLDivElement> {
843
1223
  message: string;
844
1224
  }
845
1225
 
846
- const ReplyQuote = React.forwardRef<HTMLDivElement, ReplyQuoteProps>(
847
- ({ className, sender, message, onClick, onKeyDown, role, tabIndex, "aria-label": ariaLabel, ...props }, ref) => {
1226
+ const ReplyQuote = React.forwardRef(
1227
+ ({ className, sender, message, onClick, onKeyDown, role, tabIndex, "aria-label": ariaLabel, ...props }: ReplyQuoteProps, ref: React.Ref<HTMLDivElement>) => {
848
1228
  const isInteractive = !!onClick;
849
1229
 
850
1230
  const handleKeyDown = React.useCallback(
@@ -924,8 +1304,8 @@ export interface SystemMessageProps
924
1304
  children: string;
925
1305
  }
926
1306
 
927
- const SystemMessage = React.forwardRef<HTMLDivElement, SystemMessageProps>(
928
- ({ className, children, ...props }, ref) => (
1307
+ const SystemMessage = React.forwardRef(
1308
+ ({ className, children, ...props }: SystemMessageProps, ref: React.Ref<HTMLDivElement>) => (
929
1309
  <div
930
1310
  ref={ref}
931
1311
  className={cn("flex justify-center my-1", className)}
@@ -986,8 +1366,8 @@ export interface UnreadSeparatorProps
986
1366
  label?: string;
987
1367
  }
988
1368
 
989
- const UnreadSeparator = React.forwardRef<HTMLDivElement, UnreadSeparatorProps>(
990
- ({ className, count, label, ...props }, ref) => (
1369
+ const UnreadSeparator = React.forwardRef(
1370
+ ({ className, count, label, ...props }: UnreadSeparatorProps, ref: React.Ref<HTMLDivElement>) => (
991
1371
  <div
992
1372
  ref={ref}
993
1373
  className={cn("flex items-center gap-4 my-2", className)}
@@ -1043,12 +1423,12 @@ const buttonVariants = cva(
1043
1423
  success:
1044
1424
  "bg-semantic-success-primary text-semantic-text-inverted hover:bg-semantic-success-hover",
1045
1425
  outline:
1046
- "border border-semantic-border-layout bg-semantic-bg-primary text-semantic-text-secondary hover:bg-semantic-primary-surface",
1426
+ "border border-[var(--color-neutral-300,#D5D7DA)] bg-semantic-bg-primary text-semantic-text-secondary hover:bg-semantic-primary-surface",
1047
1427
  secondary:
1048
1428
  "bg-semantic-primary-surface text-semantic-text-secondary hover:bg-semantic-bg-hover",
1049
1429
  ghost:
1050
1430
  "text-semantic-text-muted hover:bg-semantic-bg-ui hover:text-semantic-text-primary",
1051
- link: "text-semantic-text-secondary underline-offset-4 hover:underline",
1431
+ link: "text-semantic-text-link underline-offset-4 hover:underline",
1052
1432
  dashed:
1053
1433
  "border border-dashed border-semantic-bg-hover bg-transparent text-semantic-text-muted hover:border-semantic-border-primary hover:text-semantic-text-secondary hover:bg-[var(--color-neutral-50)]",
1054
1434
  },
@@ -1094,7 +1474,7 @@ export interface ButtonProps
1094
1474
  loadingText?: string;
1095
1475
  }
1096
1476
 
1097
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
1477
+ const Button = React.forwardRef(
1098
1478
  (
1099
1479
  {
1100
1480
  className,
@@ -1108,8 +1488,8 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
1108
1488
  children,
1109
1489
  disabled,
1110
1490
  ...props
1111
- },
1112
- ref
1491
+ }: ButtonProps,
1492
+ ref: React.Ref<HTMLButtonElement>
1113
1493
  ) => {
1114
1494
  const Comp = asChild ? Slot : "button";
1115
1495
 
@@ -1225,7 +1605,7 @@ export interface BadgeProps
1225
1605
  asChild?: boolean;
1226
1606
  }
1227
1607
 
1228
- const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
1608
+ const Badge = React.forwardRef(
1229
1609
  (
1230
1610
  {
1231
1611
  className,
@@ -1236,8 +1616,8 @@ const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
1236
1616
  asChild = false,
1237
1617
  children,
1238
1618
  ...props
1239
- },
1240
- ref
1619
+ }: BadgeProps,
1620
+ ref: React.Ref<HTMLDivElement>
1241
1621
  ) => {
1242
1622
  const Comp = asChild ? Slot : "div";
1243
1623
 
@@ -1326,7 +1706,7 @@ export interface ContactListItemProps
1326
1706
  * />
1327
1707
  * \`\`\`
1328
1708
  */
1329
- const ContactListItem = React.forwardRef<HTMLDivElement, ContactListItemProps>(
1709
+ const ContactListItem = React.forwardRef(
1330
1710
  (
1331
1711
  {
1332
1712
  name,
@@ -1337,8 +1717,8 @@ const ContactListItem = React.forwardRef<HTMLDivElement, ContactListItemProps>(
1337
1717
  onClick,
1338
1718
  className,
1339
1719
  ...props
1340
- },
1341
- ref
1720
+ }: ContactListItemProps,
1721
+ ref: React.Ref<HTMLDivElement>
1342
1722
  ) => {
1343
1723
  return (
1344
1724
  <div
@@ -1537,7 +1917,7 @@ export interface TypographyProps extends React.HTMLAttributes<HTMLElement> {
1537
1917
  * <Typography truncate>Very long text that will be truncated...</Typography>
1538
1918
  * \`\`\`
1539
1919
  */
1540
- const Typography = React.forwardRef<HTMLElement, TypographyProps>(
1920
+ const Typography = React.forwardRef(
1541
1921
  (
1542
1922
  {
1543
1923
  children,
@@ -1550,8 +1930,8 @@ const Typography = React.forwardRef<HTMLElement, TypographyProps>(
1550
1930
  tag,
1551
1931
  htmlFor,
1552
1932
  ...props
1553
- },
1554
- ref
1933
+ }: TypographyProps,
1934
+ ref: React.Ref<HTMLElement>
1555
1935
  ) => {
1556
1936
  const key: Key = \`\${kind}-\${variant}\`;
1557
1937
  const Tag = (tag || mapTagName[key]) as React.ElementType;
@@ -1619,9 +1999,9 @@ const inputVariants = cva(
1619
1999
  variants: {
1620
2000
  state: {
1621
2001
  default:
1622
- "border border-semantic-border-input hover:border-semantic-border-input-focus focus:outline-none focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
2002
+ "border border-semantic-border-input focus:outline-none focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
1623
2003
  error:
1624
- "border border-semantic-error-primary/40 hover:border-semantic-error-primary focus:outline-none focus:border-semantic-error-primary focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
2004
+ "border border-semantic-error-primary/40 focus:outline-none focus:border-semantic-error-primary focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
1625
2005
  },
1626
2006
  },
1627
2007
  defaultVariants: {
@@ -1648,8 +2028,8 @@ export interface InputProps
1648
2028
  showCheckIcon?: boolean;
1649
2029
  }
1650
2030
 
1651
- const Input = React.forwardRef<HTMLInputElement, InputProps>(
1652
- ({ className, state, type, showCheckIcon, onFocus, onBlur, onWheel, ...props }, ref) => {
2031
+ const Input = React.forwardRef(
2032
+ ({ className, state, type, showCheckIcon, onFocus, onBlur, onWheel, ...props }: InputProps, ref: React.Ref<HTMLInputElement>) => {
1653
2033
  const [isFocused, setIsFocused] = React.useState(false);
1654
2034
 
1655
2035
  const inputEl = (
@@ -1747,10 +2127,7 @@ const Select = SelectPrimitive.Root;
1747
2127
 
1748
2128
  const SelectGroup = SelectPrimitive.Group;
1749
2129
 
1750
- const SelectValue = React.forwardRef<
1751
- React.ElementRef<typeof SelectPrimitive.Value>,
1752
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Value>
1753
- >(({ className, ...props }, ref) => (
2130
+ const SelectValue = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Value>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Value>>) => (
1754
2131
  <SelectPrimitive.Value
1755
2132
  ref={ref}
1756
2133
  className={cn("[&[data-placeholder]]:text-semantic-text-muted", className)}
@@ -1764,10 +2141,7 @@ export interface SelectTriggerProps
1764
2141
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>,
1765
2142
  VariantProps<typeof selectTriggerVariants> {}
1766
2143
 
1767
- const SelectTrigger = React.forwardRef<
1768
- React.ElementRef<typeof SelectPrimitive.Trigger>,
1769
- SelectTriggerProps
1770
- >(({ className, state, children, ...props }, ref) => (
2144
+ const SelectTrigger = React.forwardRef(({ className, state, children, ...props }: SelectTriggerProps, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Trigger>>) => (
1771
2145
  <SelectPrimitive.Trigger
1772
2146
  ref={ref}
1773
2147
  className={cn(selectTriggerVariants({ state, className }))}
@@ -1781,10 +2155,7 @@ const SelectTrigger = React.forwardRef<
1781
2155
  ));
1782
2156
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1783
2157
 
1784
- const SelectScrollUpButton = React.forwardRef<
1785
- React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
1786
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
1787
- >(({ className, ...props }, ref) => (
2158
+ const SelectScrollUpButton = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.ScrollUpButton>>) => (
1788
2159
  <SelectPrimitive.ScrollUpButton
1789
2160
  ref={ref}
1790
2161
  className={cn(
@@ -1798,10 +2169,7 @@ const SelectScrollUpButton = React.forwardRef<
1798
2169
  ));
1799
2170
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
1800
2171
 
1801
- const SelectScrollDownButton = React.forwardRef<
1802
- React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
1803
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
1804
- >(({ className, ...props }, ref) => (
2172
+ const SelectScrollDownButton = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.ScrollDownButton>>) => (
1805
2173
  <SelectPrimitive.ScrollDownButton
1806
2174
  ref={ref}
1807
2175
  className={cn(
@@ -1855,10 +2223,7 @@ function useUnlockBodyScroll() {
1855
2223
  }, []);
1856
2224
  }
1857
2225
 
1858
- const SelectContent = React.forwardRef<
1859
- React.ElementRef<typeof SelectPrimitive.Content>,
1860
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
1861
- >(({ className, children, position = "popper", ...props }, ref) => {
2226
+ const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Content>>) => {
1862
2227
  useUnlockBodyScroll();
1863
2228
 
1864
2229
  return (
@@ -1896,10 +2261,7 @@ const SelectContent = React.forwardRef<
1896
2261
  });
1897
2262
  SelectContent.displayName = SelectPrimitive.Content.displayName;
1898
2263
 
1899
- const SelectLabel = React.forwardRef<
1900
- React.ElementRef<typeof SelectPrimitive.Label>,
1901
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
1902
- >(({ className, ...props }, ref) => (
2264
+ const SelectLabel = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Label>>) => (
1903
2265
  <SelectPrimitive.Label
1904
2266
  ref={ref}
1905
2267
  className={cn(
@@ -1911,10 +2273,7 @@ const SelectLabel = React.forwardRef<
1911
2273
  ));
1912
2274
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
1913
2275
 
1914
- const SelectItem = React.forwardRef<
1915
- React.ElementRef<typeof SelectPrimitive.Item>,
1916
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
1917
- >(({ className, children, ...props }, ref) => (
2276
+ const SelectItem = React.forwardRef(({ className, children, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Item>>) => (
1918
2277
  <SelectPrimitive.Item
1919
2278
  ref={ref}
1920
2279
  className={cn(
@@ -1935,10 +2294,7 @@ const SelectItem = React.forwardRef<
1935
2294
  ));
1936
2295
  SelectItem.displayName = SelectPrimitive.Item.displayName;
1937
2296
 
1938
- const SelectSeparator = React.forwardRef<
1939
- React.ElementRef<typeof SelectPrimitive.Separator>,
1940
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
1941
- >(({ className, ...props }, ref) => (
2297
+ const SelectSeparator = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>, ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Separator>>) => (
1942
2298
  <SelectPrimitive.Separator
1943
2299
  ref={ref}
1944
2300
  className={cn("-mx-1 my-1 h-px bg-semantic-border-layout", className)}
@@ -2069,10 +2425,7 @@ export interface CheckboxProps
2069
2425
  separateLabel?: boolean;
2070
2426
  }
2071
2427
 
2072
- const Checkbox = React.forwardRef<
2073
- React.ElementRef<typeof CheckboxPrimitive.Root>,
2074
- CheckboxProps
2075
- >(
2428
+ const Checkbox = React.forwardRef(
2076
2429
  (
2077
2430
  {
2078
2431
  className,
@@ -2085,8 +2438,8 @@ const Checkbox = React.forwardRef<
2085
2438
  id,
2086
2439
  disabled,
2087
2440
  ...props
2088
- },
2089
- ref
2441
+ }: CheckboxProps,
2442
+ ref: React.Ref<React.ElementRef<typeof CheckboxPrimitive.Root>>
2090
2443
  ) => {
2091
2444
  const checkbox = (
2092
2445
  <CheckboxPrimitive.Root
@@ -2290,13 +2643,10 @@ export interface SwitchProps
2290
2643
  labelPosition?: "left" | "right";
2291
2644
  }
2292
2645
 
2293
- const Switch = React.forwardRef<
2294
- React.ElementRef<typeof SwitchPrimitives.Root>,
2295
- SwitchProps
2296
- >(
2646
+ const Switch = React.forwardRef(
2297
2647
  (
2298
- { className, size, label, labelPosition = "right", disabled, ...props },
2299
- ref
2648
+ { className, size, label, labelPosition = "right", disabled, ...props }: SwitchProps,
2649
+ ref: React.Ref<React.ElementRef<typeof SwitchPrimitives.Root>>
2300
2650
  ) => {
2301
2651
  const switchElement = (
2302
2652
  <SwitchPrimitives.Root
@@ -2367,16 +2717,7 @@ export { Switch, switchVariants };
2367
2717
  files: [
2368
2718
  {
2369
2719
  name: "text-field.tsx",
2370
- content: prefixTailwindClasses(`import {
2371
- forwardRef,
2372
- useRef,
2373
- useCallback,
2374
- useState,
2375
- useId,
2376
- type ChangeEvent,
2377
- type ReactNode,
2378
- type ComponentProps,
2379
- } from "react";
2720
+ content: prefixTailwindClasses(`import * as React from "react";
2380
2721
  import { cva, type VariantProps } from "class-variance-authority";
2381
2722
  import { Loader2, X } from "lucide-react";
2382
2723
 
@@ -2391,9 +2732,9 @@ const textFieldContainerVariants = cva(
2391
2732
  variants: {
2392
2733
  state: {
2393
2734
  default:
2394
- "border border-semantic-border-input focus-within:border-semantic-border-input-focus/50 focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
2735
+ "border border-semantic-border-input focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
2395
2736
  error:
2396
- "border border-semantic-error-primary/40 focus-within:border-semantic-error-primary/60 focus-within:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
2737
+ "border border-semantic-error-primary/40 focus-within:border-semantic-error-primary focus-within:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
2397
2738
  },
2398
2739
  disabled: {
2399
2740
  true: "cursor-not-allowed opacity-50 bg-[var(--color-neutral-50)]",
@@ -2416,9 +2757,9 @@ const textFieldInputVariants = cva(
2416
2757
  variants: {
2417
2758
  state: {
2418
2759
  default:
2419
- "border border-semantic-border-input focus:outline-none focus:border-semantic-border-input-focus/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
2760
+ "border border-semantic-border-input focus:outline-none focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
2420
2761
  error:
2421
- "border border-semantic-error-primary/40 focus:outline-none focus:border-semantic-error-primary/60 focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
2762
+ "border border-semantic-error-primary/40 focus:outline-none focus:border-semantic-error-primary focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
2422
2763
  },
2423
2764
  size: {
2424
2765
  default: "h-[42px] px-4 py-2 text-base file:text-base",
@@ -2444,7 +2785,7 @@ const textFieldInputVariants = cva(
2444
2785
  */
2445
2786
  export interface TextFieldProps
2446
2787
  extends
2447
- Omit<ComponentProps<"input">, "size">,
2788
+ Omit<React.ComponentProps<"input">, "size">,
2448
2789
  VariantProps<typeof textFieldInputVariants> {
2449
2790
  /** Size of the text field \u2014 \`default\` (42px) or \`sm\` (36px, compact) */
2450
2791
  size?: "default" | "sm";
@@ -2457,9 +2798,9 @@ export interface TextFieldProps
2457
2798
  /** Error message - shows error state with red styling */
2458
2799
  error?: string;
2459
2800
  /** Icon displayed on the left inside the input */
2460
- leftIcon?: ReactNode;
2801
+ leftIcon?: React.ReactNode;
2461
2802
  /** Icon displayed on the right inside the input */
2462
- rightIcon?: ReactNode;
2803
+ rightIcon?: React.ReactNode;
2463
2804
  /** Text prefix inside input (e.g., "https://") */
2464
2805
  prefix?: string;
2465
2806
  /** Text suffix inside input (e.g., ".com") */
@@ -2480,7 +2821,7 @@ export interface TextFieldProps
2480
2821
  inputContainerClassName?: string;
2481
2822
  }
2482
2823
 
2483
- const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2824
+ const TextField = React.forwardRef(
2484
2825
  (
2485
2826
  {
2486
2827
  className,
@@ -2510,22 +2851,22 @@ const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2510
2851
  id,
2511
2852
  type,
2512
2853
  ...props
2513
- },
2514
- ref
2854
+ }: TextFieldProps,
2855
+ ref: React.ForwardedRef<HTMLInputElement>
2515
2856
  ) => {
2516
2857
  // Internal ref for programmatic control (e.g., clearable)
2517
- const internalRef = useRef<HTMLInputElement>(null);
2518
- const mergedRef = useCallback(
2858
+ const internalRef = React.useRef<HTMLInputElement | null>(null);
2859
+ const mergedRef = React.useCallback(
2519
2860
  (node: HTMLInputElement | null) => {
2520
2861
  internalRef.current = node;
2521
2862
  if (typeof ref === "function") ref(node);
2522
- else if (ref) ref.current = node;
2863
+ else if (ref && typeof ref === "object") ref.current = node;
2523
2864
  },
2524
2865
  [ref]
2525
2866
  );
2526
2867
 
2527
2868
  // Internal state for character count in uncontrolled mode
2528
- const [internalValue, setInternalValue] = useState(
2869
+ const [internalValue, setInternalValue] = React.useState(
2529
2870
  defaultValue ?? ""
2530
2871
  );
2531
2872
 
@@ -2537,7 +2878,7 @@ const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2537
2878
  const derivedState = error ? "error" : (state ?? "default");
2538
2879
 
2539
2880
  // Handle change for both controlled and uncontrolled
2540
- const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
2881
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
2541
2882
  if (!isControlled) {
2542
2883
  setInternalValue(e.target.value);
2543
2884
  }
@@ -2564,7 +2905,7 @@ const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2564
2905
  const charCount = String(currentValue).length;
2565
2906
 
2566
2907
  // Generate unique IDs for accessibility
2567
- const generatedId = useId();
2908
+ const generatedId = React.useId();
2568
2909
  const inputId = id || generatedId;
2569
2910
  const helperId = \`\${inputId}-helper\`;
2570
2911
  const errorId = \`\${inputId}-error\`;
@@ -2683,12 +3024,12 @@ const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2683
3024
  {error ? (
2684
3025
  <span
2685
3026
  id={errorId}
2686
- className="text-xs text-semantic-error-primary"
3027
+ className="text-sm text-semantic-error-primary"
2687
3028
  >
2688
3029
  {error}
2689
3030
  </span>
2690
3031
  ) : helperText ? (
2691
- <span id={helperId} className="text-xs text-semantic-text-muted">
3032
+ <span id={helperId} className="text-sm text-semantic-text-muted">
2692
3033
  {helperText}
2693
3034
  </span>
2694
3035
  ) : (
@@ -2697,7 +3038,7 @@ const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2697
3038
  {showCount && maxLength && (
2698
3039
  <span
2699
3040
  className={cn(
2700
- "text-xs",
3041
+ "text-sm",
2701
3042
  charCount > maxLength
2702
3043
  ? "text-semantic-error-primary"
2703
3044
  : "text-semantic-text-muted"
@@ -2715,6 +3056,225 @@ const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
2715
3056
  TextField.displayName = "TextField";
2716
3057
 
2717
3058
  export { TextField, textFieldContainerVariants, textFieldInputVariants };
3059
+ `, prefix)
3060
+ }
3061
+ ]
3062
+ },
3063
+ "textarea": {
3064
+ name: "textarea",
3065
+ description: "A multi-line text input with label, error state, helper text, character counter, and resize control",
3066
+ category: "form",
3067
+ dependencies: [
3068
+ "class-variance-authority",
3069
+ "clsx",
3070
+ "tailwind-merge"
3071
+ ],
3072
+ files: [
3073
+ {
3074
+ name: "textarea.tsx",
3075
+ content: prefixTailwindClasses(`import * as React from "react";
3076
+ import { cva, type VariantProps } from "class-variance-authority";
3077
+
3078
+ import { cn } from "../../lib/utils";
3079
+
3080
+ /**
3081
+ * Textarea variants for different visual states
3082
+ */
3083
+ const textareaVariants = cva(
3084
+ "w-full rounded bg-semantic-bg-primary text-semantic-text-primary outline-none transition-all placeholder:text-semantic-text-placeholder disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-[var(--color-neutral-50)]",
3085
+ {
3086
+ variants: {
3087
+ state: {
3088
+ default:
3089
+ "border border-semantic-border-input focus:outline-none focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
3090
+ error:
3091
+ "border border-semantic-error-primary/40 focus:outline-none focus:border-semantic-error-primary focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
3092
+ },
3093
+ size: {
3094
+ default: "px-4 py-2.5 text-base",
3095
+ sm: "px-3 py-2 text-sm",
3096
+ },
3097
+ },
3098
+ defaultVariants: {
3099
+ state: "default",
3100
+ size: "default",
3101
+ },
3102
+ }
3103
+ );
3104
+
3105
+ /**
3106
+ * A multi-line text input with label, error state, helper text, character counter, and resize control.
3107
+ *
3108
+ * @example
3109
+ * \`\`\`tsx
3110
+ * <Textarea label="Description" placeholder="Enter description" />
3111
+ * <Textarea label="Notes" error="Too short" showCount maxLength={500} />
3112
+ * <Textarea label="JSON" rows={8} resize="vertical" />
3113
+ * \`\`\`
3114
+ */
3115
+ export interface TextareaProps
3116
+ extends Omit<React.ComponentProps<"textarea">, "size">,
3117
+ VariantProps<typeof textareaVariants> {
3118
+ /** Size of the textarea \u2014 \`default\` or \`sm\` (compact) */
3119
+ size?: "default" | "sm";
3120
+ /** Label text displayed above the textarea */
3121
+ label?: string;
3122
+ /** Shows red asterisk next to label when true */
3123
+ required?: boolean;
3124
+ /** Helper text displayed below the textarea */
3125
+ helperText?: string;
3126
+ /** Error message \u2014 shows error state with red styling */
3127
+ error?: string;
3128
+ /** Shows character count when maxLength is set */
3129
+ showCount?: boolean;
3130
+ /** Controls CSS resize behavior. Defaults to "none" */
3131
+ resize?: "none" | "vertical" | "horizontal" | "both";
3132
+ /** Additional class for the wrapper container */
3133
+ wrapperClassName?: string;
3134
+ /** Additional class for the label */
3135
+ labelClassName?: string;
3136
+ }
3137
+
3138
+ const Textarea = React.forwardRef(
3139
+ (
3140
+ {
3141
+ className,
3142
+ wrapperClassName,
3143
+ labelClassName,
3144
+ state,
3145
+ size,
3146
+ label,
3147
+ required,
3148
+ helperText,
3149
+ error,
3150
+ showCount,
3151
+ resize = "none",
3152
+ maxLength,
3153
+ rows = 4,
3154
+ value,
3155
+ defaultValue,
3156
+ onChange,
3157
+ disabled,
3158
+ id,
3159
+ ...props
3160
+ }: TextareaProps,
3161
+ ref: React.ForwardedRef<HTMLTextAreaElement>
3162
+ ) => {
3163
+ // Internal state for character count in uncontrolled mode
3164
+ const [internalValue, setInternalValue] = React.useState(
3165
+ defaultValue ?? ""
3166
+ );
3167
+
3168
+ // Determine if controlled
3169
+ const isControlled = value !== undefined;
3170
+ const currentValue = isControlled ? value : internalValue;
3171
+
3172
+ // Derive state from props
3173
+ const derivedState = error ? "error" : (state ?? "default");
3174
+
3175
+ // Handle change for both controlled and uncontrolled
3176
+ const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
3177
+ if (!isControlled) {
3178
+ setInternalValue(e.target.value);
3179
+ }
3180
+ onChange?.(e);
3181
+ };
3182
+
3183
+ // Character count
3184
+ const charCount = String(currentValue).length;
3185
+
3186
+ // Generate unique IDs for accessibility
3187
+ const generatedId = React.useId();
3188
+ const textareaId = id || generatedId;
3189
+ const helperId = \`\${textareaId}-helper\`;
3190
+ const errorId = \`\${textareaId}-error\`;
3191
+
3192
+ // Determine aria-describedby
3193
+ const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined;
3194
+
3195
+ // Resize class map
3196
+ const resizeClasses: Record<string, string> = {
3197
+ none: "resize-none",
3198
+ vertical: "resize-y",
3199
+ horizontal: "resize-x",
3200
+ both: "resize",
3201
+ };
3202
+
3203
+ return (
3204
+ <div className={cn("flex flex-col gap-1", wrapperClassName)}>
3205
+ {/* Label */}
3206
+ {label && (
3207
+ <label
3208
+ htmlFor={textareaId}
3209
+ className={cn(
3210
+ "text-sm font-medium text-semantic-text-muted",
3211
+ labelClassName
3212
+ )}
3213
+ >
3214
+ {label}
3215
+ {required && (
3216
+ <span className="text-semantic-error-primary ml-0.5">*</span>
3217
+ )}
3218
+ </label>
3219
+ )}
3220
+
3221
+ {/* Textarea */}
3222
+ <textarea
3223
+ ref={ref}
3224
+ id={textareaId}
3225
+ rows={rows}
3226
+ className={cn(
3227
+ textareaVariants({ state: derivedState, size, className }),
3228
+ resizeClasses[resize]
3229
+ )}
3230
+ disabled={disabled}
3231
+ maxLength={maxLength}
3232
+ value={isControlled ? value : undefined}
3233
+ defaultValue={!isControlled ? defaultValue : undefined}
3234
+ onChange={handleChange}
3235
+ aria-invalid={!!error}
3236
+ aria-describedby={ariaDescribedBy}
3237
+ {...props}
3238
+ />
3239
+
3240
+ {/* Helper text / Error message / Character count */}
3241
+ {(error || helperText || (showCount && maxLength)) && (
3242
+ <div className="flex justify-between items-start gap-2">
3243
+ {error ? (
3244
+ <span
3245
+ id={errorId}
3246
+ className="text-sm text-semantic-error-primary"
3247
+ >
3248
+ {error}
3249
+ </span>
3250
+ ) : helperText ? (
3251
+ <span id={helperId} className="text-sm text-semantic-text-muted">
3252
+ {helperText}
3253
+ </span>
3254
+ ) : (
3255
+ <span />
3256
+ )}
3257
+ {showCount && maxLength && (
3258
+ <span
3259
+ className={cn(
3260
+ "text-sm",
3261
+ charCount > maxLength
3262
+ ? "text-semantic-error-primary"
3263
+ : "text-semantic-text-muted"
3264
+ )}
3265
+ >
3266
+ {charCount}/{maxLength}
3267
+ </span>
3268
+ )}
3269
+ </div>
3270
+ )}
3271
+ </div>
3272
+ );
3273
+ }
3274
+ );
3275
+ Textarea.displayName = "Textarea";
3276
+
3277
+ export { Textarea, textareaVariants };
2718
3278
  `, prefix)
2719
3279
  }
2720
3280
  ]
@@ -2785,7 +3345,7 @@ export interface ReadableFieldProps
2785
3345
  * />
2786
3346
  * \`\`\`
2787
3347
  */
2788
- export const ReadableField = React.forwardRef<HTMLDivElement, ReadableFieldProps>(
3348
+ export const ReadableField = React.forwardRef(
2789
3349
  (
2790
3350
  {
2791
3351
  label,
@@ -2797,8 +3357,8 @@ export const ReadableField = React.forwardRef<HTMLDivElement, ReadableFieldProps
2797
3357
  className,
2798
3358
  inputClassName,
2799
3359
  ...props
2800
- },
2801
- ref
3360
+ }: ReadableFieldProps,
3361
+ ref: React.Ref<HTMLDivElement>
2802
3362
  ) => {
2803
3363
  const [copied, setCopied] = React.useState(false);
2804
3364
  const [isVisible, setIsVisible] = React.useState(!secret);
@@ -3052,7 +3612,7 @@ export interface SelectFieldProps {
3052
3612
  * />
3053
3613
  * \`\`\`
3054
3614
  */
3055
- const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
3615
+ const SelectField = React.forwardRef(
3056
3616
  (
3057
3617
  {
3058
3618
  label,
@@ -3075,8 +3635,8 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
3075
3635
  labelClassName,
3076
3636
  id,
3077
3637
  name,
3078
- },
3079
- ref
3638
+ }: SelectFieldProps,
3639
+ ref: React.Ref<HTMLButtonElement>
3080
3640
  ) => {
3081
3641
  // Internal state for search
3082
3642
  const [searchQuery, setSearchQuery] = React.useState("");
@@ -3404,7 +3964,7 @@ export interface MultiSelectProps extends VariantProps<
3404
3964
  * />
3405
3965
  * \`\`\`
3406
3966
  */
3407
- const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
3967
+ const MultiSelect = React.forwardRef(
3408
3968
  (
3409
3969
  {
3410
3970
  label,
@@ -3427,8 +3987,8 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
3427
3987
  state,
3428
3988
  id,
3429
3989
  name,
3430
- },
3431
- ref
3990
+ }: MultiSelectProps,
3991
+ ref: React.Ref<HTMLButtonElement>
3432
3992
  ) => {
3433
3993
  // Internal state for selected values (uncontrolled mode)
3434
3994
  const [internalValue, setInternalValue] =
@@ -3815,7 +4375,7 @@ export interface CreatableSelectProps
3815
4375
  maxLength?: number
3816
4376
  }
3817
4377
 
3818
- const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
4378
+ const CreatableSelect = React.forwardRef(
3819
4379
  (
3820
4380
  {
3821
4381
  className,
@@ -3828,8 +4388,8 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
3828
4388
  disabled = false,
3829
4389
  maxLength,
3830
4390
  ...props
3831
- },
3832
- ref
4391
+ }: CreatableSelectProps,
4392
+ ref: React.Ref<HTMLDivElement>
3833
4393
  ) => {
3834
4394
  const [open, setOpen] = React.useState(false)
3835
4395
  const [search, setSearch] = React.useState("")
@@ -4164,10 +4724,7 @@ export interface CreatableMultiSelectProps
4164
4724
  maxLengthPerItem?: number
4165
4725
  }
4166
4726
 
4167
- const CreatableMultiSelect = React.forwardRef<
4168
- HTMLDivElement,
4169
- CreatableMultiSelectProps
4170
- >(
4727
+ const CreatableMultiSelect = React.forwardRef(
4171
4728
  (
4172
4729
  {
4173
4730
  className,
@@ -4182,8 +4739,8 @@ const CreatableMultiSelect = React.forwardRef<
4182
4739
  maxItems,
4183
4740
  maxLengthPerItem,
4184
4741
  ...props
4185
- },
4186
- ref
4742
+ }: CreatableMultiSelectProps,
4743
+ ref: React.Ref<HTMLDivElement>
4187
4744
  ) => {
4188
4745
  const [isOpen, setIsOpen] = React.useState(false)
4189
4746
  const [inputValue, setInputValue] = React.useState("")
@@ -4480,8 +5037,8 @@ export interface TableProps
4480
5037
  wrapContent?: boolean;
4481
5038
  }
4482
5039
 
4483
- const Table = React.forwardRef<HTMLTableElement, TableProps>(
4484
- ({ className, size, withoutBorder, wrapContent, ...props }, ref) => (
5040
+ const Table = React.forwardRef(
5041
+ ({ className, size, withoutBorder, wrapContent, ...props }: TableProps, ref: React.Ref<HTMLTableElement>) => (
4485
5042
  <div
4486
5043
  className={cn(
4487
5044
  "relative w-full overflow-auto",
@@ -4502,10 +5059,7 @@ const Table = React.forwardRef<HTMLTableElement, TableProps>(
4502
5059
  );
4503
5060
  Table.displayName = "Table";
4504
5061
 
4505
- const TableHeader = React.forwardRef<
4506
- HTMLTableSectionElement,
4507
- React.HTMLAttributes<HTMLTableSectionElement>
4508
- >(({ className, ...props }, ref) => (
5062
+ const TableHeader = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>, ref: React.Ref<HTMLTableSectionElement>) => (
4509
5063
  <thead
4510
5064
  ref={ref}
4511
5065
  className={cn("bg-[var(--color-neutral-100)] [&_tr]:border-b", className)}
@@ -4524,8 +5078,8 @@ export interface TableBodyProps
4524
5078
  loadingColumns?: number;
4525
5079
  }
4526
5080
 
4527
- const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
4528
- ({ className, isLoading, loadingRows = 5, loadingColumns = 5, children, ...props }, ref) => (
5081
+ const TableBody = React.forwardRef(
5082
+ ({ className, isLoading, loadingRows = 5, loadingColumns = 5, children, ...props }: TableBodyProps, ref: React.Ref<HTMLTableSectionElement>) => (
4529
5083
  <tbody
4530
5084
  ref={ref}
4531
5085
  className={cn("[&_tr:last-child]:border-0", className)}
@@ -4541,10 +5095,7 @@ const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
4541
5095
  );
4542
5096
  TableBody.displayName = "TableBody";
4543
5097
 
4544
- const TableFooter = React.forwardRef<
4545
- HTMLTableSectionElement,
4546
- React.HTMLAttributes<HTMLTableSectionElement>
4547
- >(({ className, ...props }, ref) => (
5098
+ const TableFooter = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>, ref: React.Ref<HTMLTableSectionElement>) => (
4548
5099
  <tfoot
4549
5100
  ref={ref}
4550
5101
  className={cn(
@@ -4561,8 +5112,8 @@ export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement>
4561
5112
  highlighted?: boolean;
4562
5113
  }
4563
5114
 
4564
- const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
4565
- ({ className, highlighted, ...props }, ref) => (
5115
+ const TableRow = React.forwardRef(
5116
+ ({ className, highlighted, ...props }: TableRowProps, ref: React.Ref<HTMLTableRowElement>) => (
4566
5117
  <tr
4567
5118
  ref={ref}
4568
5119
  className={cn(
@@ -4587,10 +5138,10 @@ export interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElem
4587
5138
  infoTooltip?: string;
4588
5139
  }
4589
5140
 
4590
- const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
5141
+ const TableHead = React.forwardRef(
4591
5142
  (
4592
- { className, sticky, sortDirection, infoTooltip, children, ...props },
4593
- ref
5143
+ { className, sticky, sortDirection, infoTooltip, children, ...props }: TableHeadProps,
5144
+ ref: React.Ref<HTMLTableCellElement>
4594
5145
  ) => (
4595
5146
  <th
4596
5147
  ref={ref}
@@ -4628,8 +5179,8 @@ export interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElem
4628
5179
  sticky?: boolean;
4629
5180
  }
4630
5181
 
4631
- const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
4632
- ({ className, sticky, ...props }, ref) => (
5182
+ const TableCell = React.forwardRef(
5183
+ ({ className, sticky, ...props }: TableCellProps, ref: React.Ref<HTMLTableCellElement>) => (
4633
5184
  <td
4634
5185
  ref={ref}
4635
5186
  className={cn(
@@ -4643,10 +5194,7 @@ const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
4643
5194
  );
4644
5195
  TableCell.displayName = "TableCell";
4645
5196
 
4646
- const TableCaption = React.forwardRef<
4647
- HTMLTableCaptionElement,
4648
- React.HTMLAttributes<HTMLTableCaptionElement>
4649
- >(({ className, ...props }, ref) => (
5197
+ const TableCaption = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableCaptionElement>, ref: React.Ref<HTMLTableCaptionElement>) => (
4650
5198
  <caption
4651
5199
  ref={ref}
4652
5200
  className={cn("mt-4 text-sm text-semantic-text-muted", className)}
@@ -4735,8 +5283,8 @@ export interface TableToggleProps extends Omit<SwitchProps, "size"> {
4735
5283
  size?: "sm" | "default";
4736
5284
  }
4737
5285
 
4738
- const TableToggle = React.forwardRef<HTMLButtonElement, TableToggleProps>(
4739
- ({ size = "sm", ...props }, ref) => (
5286
+ const TableToggle = React.forwardRef(
5287
+ ({ size = "sm", ...props }: TableToggleProps, ref: React.Ref<HTMLButtonElement>) => (
4740
5288
  <Switch ref={ref} size={size} {...props} />
4741
5289
  )
4742
5290
  );
@@ -4801,10 +5349,7 @@ export interface TabsListProps
4801
5349
  fullWidth?: boolean
4802
5350
  }
4803
5351
 
4804
- const TabsList = React.forwardRef<
4805
- React.ComponentRef<typeof TabsPrimitive.List>,
4806
- TabsListProps
4807
- >(({ className, fullWidth, ...props }, ref) => (
5352
+ const TabsList = React.forwardRef(({ className, fullWidth, ...props }: TabsListProps, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.List>>) => (
4808
5353
  <TabsPrimitive.List
4809
5354
  ref={ref}
4810
5355
  className={cn(
@@ -4817,10 +5362,7 @@ const TabsList = React.forwardRef<
4817
5362
  ))
4818
5363
  TabsList.displayName = TabsPrimitive.List.displayName
4819
5364
 
4820
- const TabsTrigger = React.forwardRef<
4821
- React.ComponentRef<typeof TabsPrimitive.Trigger>,
4822
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
4823
- >(({ className, ...props }, ref) => (
5365
+ const TabsTrigger = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.Trigger>>) => (
4824
5366
  <TabsPrimitive.Trigger
4825
5367
  ref={ref}
4826
5368
  className={cn(
@@ -4835,10 +5377,7 @@ const TabsTrigger = React.forwardRef<
4835
5377
  ))
4836
5378
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
4837
5379
 
4838
- const TabsContent = React.forwardRef<
4839
- React.ComponentRef<typeof TabsPrimitive.Content>,
4840
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
4841
- >(({ className, ...props }, ref) => (
5380
+ const TabsContent = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.Content>>) => (
4842
5381
  <TabsPrimitive.Content
4843
5382
  ref={ref}
4844
5383
  className={cn(
@@ -4885,10 +5424,7 @@ const DialogPortal = DialogPrimitive.Portal;
4885
5424
 
4886
5425
  const DialogClose = DialogPrimitive.Close;
4887
5426
 
4888
- const DialogOverlay = React.forwardRef<
4889
- React.ElementRef<typeof DialogPrimitive.Overlay>,
4890
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
4891
- >(({ className, ...props }, ref) => (
5427
+ const DialogOverlay = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>) => (
4892
5428
  <DialogPrimitive.Overlay
4893
5429
  ref={ref}
4894
5430
  className={cn(
@@ -4946,10 +5482,7 @@ const hasDialogDescription = (children: React.ReactNode): boolean => {
4946
5482
  return found;
4947
5483
  };
4948
5484
 
4949
- const DialogContent = React.forwardRef<
4950
- React.ElementRef<typeof DialogPrimitive.Content>,
4951
- DialogContentProps
4952
- >(({ className, children, size, hideCloseButton = false, ...props }, ref) => {
5485
+ const DialogContent = React.forwardRef(({ className, children, size, hideCloseButton = false, ...props }: DialogContentProps, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Content>>) => {
4953
5486
  const hasDescription = hasDialogDescription(children);
4954
5487
 
4955
5488
  return (
@@ -5007,10 +5540,7 @@ const DialogFooter = ({
5007
5540
  );
5008
5541
  DialogFooter.displayName = "DialogFooter";
5009
5542
 
5010
- const DialogTitle = React.forwardRef<
5011
- React.ElementRef<typeof DialogPrimitive.Title>,
5012
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
5013
- >(({ className, ...props }, ref) => (
5543
+ const DialogTitle = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Title>>) => (
5014
5544
  <DialogPrimitive.Title
5015
5545
  ref={ref}
5016
5546
  className={cn(
@@ -5022,10 +5552,7 @@ const DialogTitle = React.forwardRef<
5022
5552
  ));
5023
5553
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5024
5554
 
5025
- const DialogDescription = React.forwardRef<
5026
- React.ElementRef<typeof DialogPrimitive.Description>,
5027
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
5028
- >(({ className, ...props }, ref) => (
5555
+ const DialogDescription = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Description>>) => (
5029
5556
  <DialogPrimitive.Description
5030
5557
  ref={ref}
5031
5558
  className={cn("text-sm text-muted-foreground", className)}
@@ -5073,10 +5600,7 @@ import { cn } from "../../lib/utils";
5073
5600
 
5074
5601
  const DropdownMenu = DropdownMenuPrimitive.Root;
5075
5602
 
5076
- const DropdownMenuTrigger = React.forwardRef<
5077
- React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
5078
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
5079
- >(({ className, ...props }, ref) => (
5603
+ const DropdownMenuTrigger = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Trigger>>) => (
5080
5604
  <DropdownMenuPrimitive.Trigger
5081
5605
  ref={ref}
5082
5606
  className={cn("focus-visible:outline-none focus-visible:ring-0", className)}
@@ -5093,12 +5617,9 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
5093
5617
 
5094
5618
  const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
5095
5619
 
5096
- const DropdownMenuSubTrigger = React.forwardRef<
5097
- React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
5098
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
5620
+ const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
5099
5621
  inset?: boolean;
5100
- }
5101
- >(({ className, inset, children, ...props }, ref) => (
5622
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>>) => (
5102
5623
  <DropdownMenuPrimitive.SubTrigger
5103
5624
  ref={ref}
5104
5625
  className={cn(
@@ -5115,10 +5636,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
5115
5636
  DropdownMenuSubTrigger.displayName =
5116
5637
  DropdownMenuPrimitive.SubTrigger.displayName;
5117
5638
 
5118
- const DropdownMenuSubContent = React.forwardRef<
5119
- React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
5120
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
5121
- >(({ className, ...props }, ref) => (
5639
+ const DropdownMenuSubContent = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.SubContent>>) => (
5122
5640
  <DropdownMenuPrimitive.SubContent
5123
5641
  ref={ref}
5124
5642
  className={cn(
@@ -5131,10 +5649,7 @@ const DropdownMenuSubContent = React.forwardRef<
5131
5649
  DropdownMenuSubContent.displayName =
5132
5650
  DropdownMenuPrimitive.SubContent.displayName;
5133
5651
 
5134
- const DropdownMenuContent = React.forwardRef<
5135
- React.ElementRef<typeof DropdownMenuPrimitive.Content>,
5136
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
5137
- >(({ className, sideOffset = 4, ...props }, ref) => (
5652
+ const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Content>>) => (
5138
5653
  <DropdownMenuPrimitive.Portal>
5139
5654
  <DropdownMenuPrimitive.Content
5140
5655
  ref={ref}
@@ -5150,20 +5665,17 @@ const DropdownMenuContent = React.forwardRef<
5150
5665
  ));
5151
5666
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
5152
5667
 
5153
- const DropdownMenuItem = React.forwardRef<
5154
- React.ElementRef<typeof DropdownMenuPrimitive.Item>,
5155
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
5668
+ const DropdownMenuItem = React.forwardRef(({ className, inset, children, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
5156
5669
  inset?: boolean;
5157
5670
  /** Secondary text displayed below children */
5158
5671
  description?: string;
5159
5672
  /** Content displayed at the right edge of the item */
5160
5673
  suffix?: React.ReactNode;
5161
- }
5162
- >(({ className, inset, children, description, suffix, ...props }, ref) => (
5674
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Item>>) => (
5163
5675
  <DropdownMenuPrimitive.Item
5164
5676
  ref={ref}
5165
5677
  className={cn(
5166
- "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-2 text-sm text-semantic-text-secondary outline-none transition-colors focus:bg-semantic-bg-ui focus:text-semantic-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
5678
+ "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm text-semantic-text-secondary outline-none transition-colors focus:bg-semantic-bg-ui focus:text-semantic-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
5167
5679
  inset && "pl-8",
5168
5680
  className
5169
5681
  )}
@@ -5184,15 +5696,12 @@ const DropdownMenuItem = React.forwardRef<
5184
5696
  ));
5185
5697
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
5186
5698
 
5187
- const DropdownMenuCheckboxItem = React.forwardRef<
5188
- React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
5189
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
5699
+ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
5190
5700
  /** Secondary text displayed below children */
5191
5701
  description?: string;
5192
5702
  /** Content displayed at the right edge of the item */
5193
5703
  suffix?: React.ReactNode;
5194
- }
5195
- >(({ className, children, checked, description, suffix, ...props }, ref) => (
5704
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>>) => (
5196
5705
  <DropdownMenuPrimitive.CheckboxItem
5197
5706
  ref={ref}
5198
5707
  className={cn(
@@ -5223,15 +5732,12 @@ const DropdownMenuCheckboxItem = React.forwardRef<
5223
5732
  DropdownMenuCheckboxItem.displayName =
5224
5733
  DropdownMenuPrimitive.CheckboxItem.displayName;
5225
5734
 
5226
- const DropdownMenuRadioItem = React.forwardRef<
5227
- React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
5228
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
5735
+ const DropdownMenuRadioItem = React.forwardRef(({ className, children, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
5229
5736
  /** Secondary text displayed below children */
5230
5737
  description?: string;
5231
5738
  /** Content displayed at the right edge of the item */
5232
5739
  suffix?: React.ReactNode;
5233
- }
5234
- >(({ className, children, description, suffix, ...props }, ref) => (
5740
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>>) => (
5235
5741
  <DropdownMenuPrimitive.RadioItem
5236
5742
  ref={ref}
5237
5743
  className={cn(
@@ -5260,12 +5766,9 @@ const DropdownMenuRadioItem = React.forwardRef<
5260
5766
  ));
5261
5767
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
5262
5768
 
5263
- const DropdownMenuLabel = React.forwardRef<
5264
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
5265
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
5769
+ const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
5266
5770
  inset?: boolean;
5267
- }
5268
- >(({ className, inset, ...props }, ref) => (
5771
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Label>>) => (
5269
5772
  <DropdownMenuPrimitive.Label
5270
5773
  ref={ref}
5271
5774
  className={cn(
@@ -5278,10 +5781,7 @@ const DropdownMenuLabel = React.forwardRef<
5278
5781
  ));
5279
5782
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
5280
5783
 
5281
- const DropdownMenuSeparator = React.forwardRef<
5282
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
5283
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
5284
- >(({ className, ...props }, ref) => (
5784
+ const DropdownMenuSeparator = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Separator>>) => (
5285
5785
  <DropdownMenuPrimitive.Separator
5286
5786
  ref={ref}
5287
5787
  className={cn("-mx-1 my-1 h-px bg-semantic-border-layout", className)}
@@ -5348,10 +5848,7 @@ const Tooltip = TooltipPrimitive.Root;
5348
5848
 
5349
5849
  const TooltipTrigger = TooltipPrimitive.Trigger;
5350
5850
 
5351
- const TooltipContent = React.forwardRef<
5352
- React.ElementRef<typeof TooltipPrimitive.Content>,
5353
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
5354
- >(({ className, sideOffset = 4, ...props }, ref) => (
5851
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>, ref: React.Ref<React.ElementRef<typeof TooltipPrimitive.Content>>) => (
5355
5852
  <TooltipPrimitive.Portal>
5356
5853
  <TooltipPrimitive.Content
5357
5854
  ref={ref}
@@ -5366,10 +5863,7 @@ const TooltipContent = React.forwardRef<
5366
5863
  ));
5367
5864
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
5368
5865
 
5369
- const TooltipArrow = React.forwardRef<
5370
- React.ElementRef<typeof TooltipPrimitive.Arrow>,
5371
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
5372
- >(({ className, ...props }, ref) => (
5866
+ const TooltipArrow = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>, ref: React.Ref<React.ElementRef<typeof TooltipPrimitive.Arrow>>) => (
5373
5867
  <TooltipPrimitive.Arrow
5374
5868
  ref={ref}
5375
5869
  className={cn("fill-semantic-primary", className)}
@@ -5473,10 +5967,7 @@ export interface DeleteConfirmationModalProps {
5473
5967
  * />
5474
5968
  * \`\`\`
5475
5969
  */
5476
- const DeleteConfirmationModal = React.forwardRef<
5477
- HTMLDivElement,
5478
- DeleteConfirmationModalProps
5479
- >(
5970
+ const DeleteConfirmationModal = React.forwardRef(
5480
5971
  (
5481
5972
  {
5482
5973
  open,
@@ -5492,8 +5983,8 @@ const DeleteConfirmationModal = React.forwardRef<
5492
5983
  cancelButtonText = "Cancel",
5493
5984
  trigger,
5494
5985
  className,
5495
- },
5496
- ref
5986
+ }: DeleteConfirmationModalProps,
5987
+ ref: React.Ref<HTMLDivElement>
5497
5988
  ) => {
5498
5989
  const [inputValue, setInputValue] = React.useState("");
5499
5990
  const isConfirmEnabled = inputValue === confirmText;
@@ -5661,10 +6152,7 @@ export interface ConfirmationModalProps {
5661
6152
  * />
5662
6153
  * \`\`\`
5663
6154
  */
5664
- const ConfirmationModal = React.forwardRef<
5665
- HTMLDivElement,
5666
- ConfirmationModalProps
5667
- >(
6155
+ const ConfirmationModal = React.forwardRef(
5668
6156
  (
5669
6157
  {
5670
6158
  open,
@@ -5679,8 +6167,8 @@ const ConfirmationModal = React.forwardRef<
5679
6167
  cancelButtonText = "Cancel",
5680
6168
  trigger,
5681
6169
  className,
5682
- },
5683
- ref
6170
+ }: ConfirmationModalProps,
6171
+ ref: React.Ref<HTMLDivElement>
5684
6172
  ) => {
5685
6173
  const handleConfirm = () => {
5686
6174
  onConfirm?.();
@@ -5812,7 +6300,7 @@ export interface FormModalProps {
5812
6300
  * </FormModal>
5813
6301
  * \`\`\`
5814
6302
  */
5815
- const FormModal = React.forwardRef<HTMLDivElement, FormModalProps>(
6303
+ const FormModal = React.forwardRef(
5816
6304
  (
5817
6305
  {
5818
6306
  open,
@@ -5828,8 +6316,8 @@ const FormModal = React.forwardRef<HTMLDivElement, FormModalProps>(
5828
6316
  disableSave = false,
5829
6317
  className,
5830
6318
  size = "sm",
5831
- },
5832
- ref
6319
+ }: FormModalProps,
6320
+ ref: React.Ref<HTMLDivElement>
5833
6321
  ) => {
5834
6322
  const handleSave = () => {
5835
6323
  onSave?.();
@@ -5944,8 +6432,8 @@ export interface TagProps
5944
6432
  label?: string;
5945
6433
  }
5946
6434
 
5947
- const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
5948
- ({ className, variant, size, label, children, ...props }, ref) => {
6435
+ const Tag = React.forwardRef(
6436
+ ({ className, variant, size, label, children, ...props }: TagProps, ref: React.Ref<HTMLSpanElement>) => {
5949
6437
  return (
5950
6438
  <span
5951
6439
  className={cn(tagVariants({ variant, size, className }))}
@@ -5953,7 +6441,7 @@ const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
5953
6441
  {...props}
5954
6442
  >
5955
6443
  {label && <span className="font-semibold mr-1">{label}</span>}
5956
- <span className="font-normal">{children}</span>
6444
+ <span className="font-normal inline-flex items-center gap-1">{children}</span>
5957
6445
  </span>
5958
6446
  );
5959
6447
  }
@@ -6141,7 +6629,7 @@ export interface AlertProps
6141
6629
  defaultOpen?: boolean;
6142
6630
  }
6143
6631
 
6144
- const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
6632
+ const Alert = React.forwardRef(
6145
6633
  (
6146
6634
  {
6147
6635
  className,
@@ -6156,8 +6644,8 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
6156
6644
  defaultOpen = true,
6157
6645
  children,
6158
6646
  ...props
6159
- },
6160
- ref
6647
+ }: AlertProps,
6648
+ ref: React.Ref<HTMLDivElement>
6161
6649
  ) => {
6162
6650
  const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
6163
6651
  const isControlled = controlledOpen !== undefined;
@@ -6229,10 +6717,7 @@ Alert.displayName = "Alert";
6229
6717
  /**
6230
6718
  * Alert title component for the heading text.
6231
6719
  */
6232
- const AlertTitle = React.forwardRef<
6233
- HTMLHeadingElement,
6234
- React.HTMLAttributes<HTMLHeadingElement>
6235
- >(({ className, children, ...props }, ref) => (
6720
+ const AlertTitle = React.forwardRef(({ className, children, ...props }: React.HTMLAttributes<HTMLHeadingElement>, ref: React.Ref<HTMLHeadingElement>) => (
6236
6721
  <h5
6237
6722
  ref={ref}
6238
6723
  className={cn("font-semibold leading-tight tracking-tight", className)}
@@ -6246,10 +6731,7 @@ AlertTitle.displayName = "AlertTitle";
6246
6731
  /**
6247
6732
  * Alert description component for the body text.
6248
6733
  */
6249
- const AlertDescription = React.forwardRef<
6250
- HTMLParagraphElement,
6251
- React.HTMLAttributes<HTMLParagraphElement>
6252
- >(({ className, ...props }, ref) => (
6734
+ const AlertDescription = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>, ref: React.Ref<HTMLParagraphElement>) => (
6253
6735
  <p ref={ref} className={cn("m-0 mt-1 text-sm", className)} {...props} />
6254
6736
  ));
6255
6737
  AlertDescription.displayName = "AlertDescription";
@@ -6283,10 +6765,7 @@ import { cn } from "../../lib/utils";
6283
6765
 
6284
6766
  const ToastProvider = ToastPrimitives.Provider;
6285
6767
 
6286
- const ToastViewport = React.forwardRef<
6287
- React.ElementRef<typeof ToastPrimitives.Viewport>,
6288
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
6289
- >(({ className, ...props }, ref) => (
6768
+ const ToastViewport = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Viewport>>) => (
6290
6769
  <ToastPrimitives.Viewport
6291
6770
  ref={ref}
6292
6771
  className={cn(
@@ -6320,11 +6799,8 @@ const toastVariants = cva(
6320
6799
  }
6321
6800
  );
6322
6801
 
6323
- const Toast = React.forwardRef<
6324
- React.ElementRef<typeof ToastPrimitives.Root>,
6325
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
6326
- VariantProps<typeof toastVariants>
6327
- >(({ className, variant, ...props }, ref) => {
6802
+ const Toast = React.forwardRef(({ className, variant, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
6803
+ VariantProps<typeof toastVariants>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Root>>) => {
6328
6804
  return (
6329
6805
  <ToastPrimitives.Root
6330
6806
  ref={ref}
@@ -6335,10 +6811,7 @@ const Toast = React.forwardRef<
6335
6811
  });
6336
6812
  Toast.displayName = ToastPrimitives.Root.displayName;
6337
6813
 
6338
- const ToastAction = React.forwardRef<
6339
- React.ElementRef<typeof ToastPrimitives.Action>,
6340
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
6341
- >(({ className, ...props }, ref) => (
6814
+ const ToastAction = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Action>>) => (
6342
6815
  <ToastPrimitives.Action
6343
6816
  ref={ref}
6344
6817
  className={cn(
@@ -6354,10 +6827,7 @@ const ToastAction = React.forwardRef<
6354
6827
  ));
6355
6828
  ToastAction.displayName = ToastPrimitives.Action.displayName;
6356
6829
 
6357
- const ToastClose = React.forwardRef<
6358
- React.ElementRef<typeof ToastPrimitives.Close>,
6359
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
6360
- >(({ className, ...props }, ref) => (
6830
+ const ToastClose = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Close>>) => (
6361
6831
  <ToastPrimitives.Close
6362
6832
  ref={ref}
6363
6833
  className={cn(
@@ -6372,10 +6842,7 @@ const ToastClose = React.forwardRef<
6372
6842
  ));
6373
6843
  ToastClose.displayName = ToastPrimitives.Close.displayName;
6374
6844
 
6375
- const ToastTitle = React.forwardRef<
6376
- React.ElementRef<typeof ToastPrimitives.Title>,
6377
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
6378
- >(({ className, ...props }, ref) => (
6845
+ const ToastTitle = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Title>>) => (
6379
6846
  <ToastPrimitives.Title
6380
6847
  ref={ref}
6381
6848
  className={cn("text-sm font-semibold tracking-[0.014px]", className)}
@@ -6384,10 +6851,7 @@ const ToastTitle = React.forwardRef<
6384
6851
  ));
6385
6852
  ToastTitle.displayName = ToastPrimitives.Title.displayName;
6386
6853
 
6387
- const ToastDescription = React.forwardRef<
6388
- React.ElementRef<typeof ToastPrimitives.Description>,
6389
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
6390
- >(({ className, ...props }, ref) => (
6854
+ const ToastDescription = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Description>>) => (
6391
6855
  <ToastPrimitives.Description
6392
6856
  ref={ref}
6393
6857
  className={cn("text-xs tracking-[0.048px]", className)}
@@ -6836,7 +7300,7 @@ export interface SpinnerProps
6836
7300
  "aria-label"?: string;
6837
7301
  }
6838
7302
 
6839
- const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
7303
+ const Spinner = React.forwardRef(
6840
7304
  (
6841
7305
  {
6842
7306
  className,
@@ -6844,8 +7308,8 @@ const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
6844
7308
  variant,
6845
7309
  "aria-label": ariaLabel = "Loading",
6846
7310
  ...props
6847
- },
6848
- ref
7311
+ }: SpinnerProps,
7312
+ ref: React.Ref<HTMLDivElement>
6849
7313
  ) => {
6850
7314
  const strokeWidth = strokeWidths[size || "default"] ?? 3;
6851
7315
  const radius = 10;
@@ -6965,8 +7429,8 @@ export interface SkeletonProps
6965
7429
  height?: number | string;
6966
7430
  }
6967
7431
 
6968
- const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
6969
- ({ className, variant, shape, width, height, style, ...props }, ref) => {
7432
+ const Skeleton = React.forwardRef(
7433
+ ({ className, variant, shape, width, height, style, ...props }: SkeletonProps, ref: React.Ref<HTMLDivElement>) => {
6970
7434
  const dimensionStyle: React.CSSProperties = {
6971
7435
  ...style,
6972
7436
  ...(width !== undefined
@@ -7209,7 +7673,7 @@ export interface AccordionProps
7209
7673
  onValueChange?: (value: string[]) => void;
7210
7674
  }
7211
7675
 
7212
- const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
7676
+ const Accordion = React.forwardRef(
7213
7677
  (
7214
7678
  {
7215
7679
  className,
@@ -7220,8 +7684,8 @@ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
7220
7684
  onValueChange,
7221
7685
  children,
7222
7686
  ...props
7223
- },
7224
- ref
7687
+ }: AccordionProps,
7688
+ ref: React.Ref<HTMLDivElement>
7225
7689
  ) => {
7226
7690
  const [internalValue, setInternalValue] =
7227
7691
  React.useState<string[]>(defaultValue);
@@ -7277,8 +7741,8 @@ export interface AccordionItemProps
7277
7741
  disabled?: boolean;
7278
7742
  }
7279
7743
 
7280
- const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
7281
- ({ className, value, disabled, children, ...props }, ref) => {
7744
+ const AccordionItem = React.forwardRef(
7745
+ ({ className, value, disabled, children, ...props }: AccordionItemProps, ref: React.Ref<HTMLDivElement>) => {
7282
7746
  const { value: openValues, variant } = useAccordionContext();
7283
7747
  const isOpen = openValues.includes(value);
7284
7748
 
@@ -7318,10 +7782,7 @@ export interface AccordionTriggerProps
7318
7782
  showChevron?: boolean;
7319
7783
  }
7320
7784
 
7321
- const AccordionTrigger = React.forwardRef<
7322
- HTMLButtonElement,
7323
- AccordionTriggerProps
7324
- >(({ className, showChevron = true, children, ...props }, ref) => {
7785
+ const AccordionTrigger = React.forwardRef(({ className, showChevron = true, children, ...props }: AccordionTriggerProps, ref: React.Ref<HTMLButtonElement>) => {
7325
7786
  const {
7326
7787
  type,
7327
7788
  value: openValues,
@@ -7380,10 +7841,7 @@ export interface AccordionContentProps
7380
7841
  React.HTMLAttributes<HTMLDivElement>,
7381
7842
  VariantProps<typeof accordionContentVariants> {}
7382
7843
 
7383
- const AccordionContent = React.forwardRef<
7384
- HTMLDivElement,
7385
- AccordionContentProps
7386
- >(({ className, children, ...props }, ref) => {
7844
+ const AccordionContent = React.forwardRef(({ className, children, ...props }: AccordionContentProps, ref: React.Ref<HTMLDivElement>) => {
7387
7845
  const { variant } = useAccordionContext();
7388
7846
  const { isOpen } = useAccordionItemContext();
7389
7847
  const contentRef = React.useRef<HTMLDivElement>(null);
@@ -7515,7 +7973,7 @@ export interface PageHeaderProps
7515
7973
  mobileOverflowLimit?: number;
7516
7974
  }
7517
7975
 
7518
- const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
7976
+ const PageHeader = React.forwardRef(
7519
7977
  (
7520
7978
  {
7521
7979
  className,
@@ -7531,8 +7989,8 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
7531
7989
  layout = "responsive",
7532
7990
  mobileOverflowLimit = 2,
7533
7991
  ...props
7534
- },
7535
- ref
7992
+ }: PageHeaderProps,
7993
+ ref: React.Ref<HTMLDivElement>
7536
7994
  ) => {
7537
7995
  // State for overflow expansion (moved to top level)
7538
7996
  const [isOverflowExpanded, setIsOverflowExpanded] = React.useState(false);
@@ -7820,7 +8278,7 @@ export interface PanelProps
7820
8278
  * </Panel>
7821
8279
  * \`\`\`
7822
8280
  */
7823
- const Panel = React.forwardRef<HTMLElement, PanelProps>(
8281
+ const Panel = React.forwardRef(
7824
8282
  (
7825
8283
  {
7826
8284
  open = true,
@@ -7834,8 +8292,8 @@ const Panel = React.forwardRef<HTMLElement, PanelProps>(
7834
8292
  "aria-label": ariaLabel,
7835
8293
  onKeyDown,
7836
8294
  ...props
7837
- },
7838
- ref
8295
+ }: PanelProps,
8296
+ ref: React.Ref<HTMLElement>
7839
8297
  ) => {
7840
8298
  const resolvedSize = size ?? "default";
7841
8299
  const widthClass = panelWidths[resolvedSize];
@@ -8279,10 +8737,7 @@ import type { EventSelectorProps, EventCategory, EventGroup } from "./types";
8279
8737
  * />
8280
8738
  * \`\`\`
8281
8739
  */
8282
- export const EventSelector = React.forwardRef<
8283
- HTMLDivElement,
8284
- EventSelectorProps
8285
- >(
8740
+ export const EventSelector = React.forwardRef(
8286
8741
  (
8287
8742
  {
8288
8743
  events,
@@ -8297,8 +8752,8 @@ export const EventSelector = React.forwardRef<
8297
8752
  renderEmptyGroup,
8298
8753
  className,
8299
8754
  ...props
8300
- },
8301
- ref
8755
+ }: EventSelectorProps,
8756
+ ref: React.Ref<HTMLDivElement>
8302
8757
  ) => {
8303
8758
  // Controlled vs uncontrolled state
8304
8759
  const [internalSelected, setInternalSelected] = React.useState<string[]>(
@@ -8459,10 +8914,7 @@ import type { EventGroupComponentProps } from "./types";
8459
8914
  /**
8460
8915
  * Event group with accordion section and group-level checkbox
8461
8916
  */
8462
- export const EventGroupComponent = React.forwardRef<
8463
- HTMLDivElement,
8464
- EventGroupComponentProps & React.HTMLAttributes<HTMLDivElement>
8465
- >(
8917
+ export const EventGroupComponent = React.forwardRef(
8466
8918
  (
8467
8919
  {
8468
8920
  group,
@@ -8474,8 +8926,8 @@ export const EventGroupComponent = React.forwardRef<
8474
8926
  defaultExpanded = false,
8475
8927
  className,
8476
8928
  ...props
8477
- },
8478
- ref
8929
+ }: EventGroupComponentProps & React.HTMLAttributes<HTMLDivElement>,
8930
+ ref: React.Ref<HTMLDivElement>
8479
8931
  ) => {
8480
8932
  // Calculate selection state for this group
8481
8933
  const groupEventIds = events.map((e) => e.id);
@@ -8638,10 +9090,7 @@ import type { EventItemComponentProps } from "./types";
8638
9090
  /**
8639
9091
  * Individual event item with checkbox
8640
9092
  */
8641
- export const EventItemComponent = React.forwardRef<
8642
- HTMLDivElement,
8643
- EventItemComponentProps & React.HTMLAttributes<HTMLDivElement>
8644
- >(({ event, isSelected, onSelectionChange, className, ...props }, ref) => {
9093
+ export const EventItemComponent = React.forwardRef(({ event, isSelected, onSelectionChange, className, ...props }: EventItemComponentProps & React.HTMLAttributes<HTMLDivElement>, ref: React.Ref<HTMLDivElement>) => {
8645
9094
  return (
8646
9095
  <div
8647
9096
  ref={ref}
@@ -8852,10 +9301,7 @@ const generateId = () =>
8852
9301
  * />
8853
9302
  * \`\`\`
8854
9303
  */
8855
- export const KeyValueInput = React.forwardRef<
8856
- HTMLDivElement,
8857
- KeyValueInputProps
8858
- >(
9304
+ export const KeyValueInput = React.forwardRef(
8859
9305
  (
8860
9306
  {
8861
9307
  title,
@@ -8873,8 +9319,8 @@ export const KeyValueInput = React.forwardRef<
8873
9319
  defaultValue = [],
8874
9320
  className,
8875
9321
  ...props
8876
- },
8877
- ref
9322
+ }: KeyValueInputProps,
9323
+ ref: React.Ref<HTMLDivElement>
8878
9324
  ) => {
8879
9325
  // Controlled vs uncontrolled state
8880
9326
  const [internalPairs, setInternalPairs] =
@@ -9071,10 +9517,7 @@ import type { KeyValueRowProps } from "./types";
9071
9517
  /**
9072
9518
  * Individual key-value pair row with inputs and delete button
9073
9519
  */
9074
- export const KeyValueRow = React.forwardRef<
9075
- HTMLDivElement,
9076
- KeyValueRowProps & React.HTMLAttributes<HTMLDivElement>
9077
- >(
9520
+ export const KeyValueRow = React.forwardRef(
9078
9521
  (
9079
9522
  {
9080
9523
  pair,
@@ -9090,8 +9533,8 @@ export const KeyValueRow = React.forwardRef<
9090
9533
  onDelete,
9091
9534
  className,
9092
9535
  ...props
9093
- },
9094
- ref
9536
+ }: KeyValueRowProps & React.HTMLAttributes<HTMLDivElement>,
9537
+ ref: React.Ref<HTMLDivElement>
9095
9538
  ) => {
9096
9539
  // Determine if inputs should show error state
9097
9540
  const keyHasError = isDuplicateKey || (keyRequired && isKeyEmpty);
@@ -9306,10 +9749,7 @@ export interface ApiFeatureCardProps
9306
9749
  * />
9307
9750
  * \`\`\`
9308
9751
  */
9309
- export const ApiFeatureCard = React.forwardRef<
9310
- HTMLDivElement,
9311
- ApiFeatureCardProps
9312
- >(
9752
+ export const ApiFeatureCard = React.forwardRef(
9313
9753
  (
9314
9754
  {
9315
9755
  icon,
@@ -9322,8 +9762,8 @@ export const ApiFeatureCard = React.forwardRef<
9322
9762
  capabilitiesLabel = "Key Capabilities",
9323
9763
  className,
9324
9764
  ...props
9325
- },
9326
- ref
9765
+ }: ApiFeatureCardProps,
9766
+ ref: React.Ref<HTMLDivElement>
9327
9767
  ) => {
9328
9768
  return (
9329
9769
  <div
@@ -9495,10 +9935,7 @@ export interface EndpointDetailsProps
9495
9935
  * />
9496
9936
  * \`\`\`
9497
9937
  */
9498
- export const EndpointDetails = React.forwardRef<
9499
- HTMLDivElement,
9500
- EndpointDetailsProps
9501
- >(
9938
+ export const EndpointDetails = React.forwardRef(
9502
9939
  (
9503
9940
  {
9504
9941
  title = "Endpoint Details",
@@ -9519,8 +9956,8 @@ export const EndpointDetails = React.forwardRef<
9519
9956
  revokeDescription = "Revoking access will immediately disable all integrations using these keys.",
9520
9957
  className,
9521
9958
  ...props
9522
- },
9523
- ref
9959
+ }: EndpointDetailsProps,
9960
+ ref: React.Ref<HTMLDivElement>
9524
9961
  ) => {
9525
9962
  const isCalling = variant === "calling";
9526
9963
 
@@ -9710,10 +10147,7 @@ export interface AlertConfigurationProps {
9710
10147
  * AlertConfiguration component displays current alert values for minimum balance and top-up.
9711
10148
  * Used in payment auto-pay setup to show notification thresholds.
9712
10149
  */
9713
- export const AlertConfiguration = React.forwardRef<
9714
- HTMLDivElement,
9715
- AlertConfigurationProps
9716
- >(
10150
+ export const AlertConfiguration = React.forwardRef(
9717
10151
  (
9718
10152
  {
9719
10153
  minimumBalance,
@@ -9721,8 +10155,8 @@ export const AlertConfiguration = React.forwardRef<
9721
10155
  currencySymbol = "\u20B9",
9722
10156
  onEdit,
9723
10157
  className,
9724
- },
9725
- ref
10158
+ }: AlertConfigurationProps,
10159
+ ref: React.Ref<HTMLDivElement>
9726
10160
  ) => {
9727
10161
  const formatCurrency = (amount: number) => {
9728
10162
  const formatted = amount.toLocaleString("en-IN", {
@@ -9857,10 +10291,7 @@ export interface AlertValuesModalProps {
9857
10291
  * AlertValuesModal component for editing alert configuration values.
9858
10292
  * Displays a form with inputs for minimum balance and minimum top-up.
9859
10293
  */
9860
- export const AlertValuesModal = React.forwardRef<
9861
- HTMLDivElement,
9862
- AlertValuesModalProps
9863
- >(
10294
+ export const AlertValuesModal = React.forwardRef(
9864
10295
  (
9865
10296
  {
9866
10297
  open,
@@ -9872,8 +10303,8 @@ export const AlertValuesModal = React.forwardRef<
9872
10303
  topupOptions,
9873
10304
  onSave,
9874
10305
  loading = false,
9875
- },
9876
- ref
10306
+ }: AlertValuesModalProps,
10307
+ ref: React.Ref<HTMLDivElement>
9877
10308
  ) => {
9878
10309
  const [minimumBalance, setMinimumBalance] = React.useState(
9879
10310
  initialMinimumBalance.toString()
@@ -10022,7 +10453,7 @@ import type { AutoPaySetupProps } from "./types";
10022
10453
  * />
10023
10454
  * \`\`\`
10024
10455
  */
10025
- export const AutoPaySetup = React.forwardRef<HTMLDivElement, AutoPaySetupProps>(
10456
+ export const AutoPaySetup = React.forwardRef(
10026
10457
  (
10027
10458
  {
10028
10459
  title = "Auto-pay setup",
@@ -10041,8 +10472,8 @@ export const AutoPaySetup = React.forwardRef<HTMLDivElement, AutoPaySetupProps>(
10041
10472
  open,
10042
10473
  onOpenChange,
10043
10474
  className,
10044
- },
10045
- ref
10475
+ }: AutoPaySetupProps,
10476
+ ref: React.Ref<HTMLDivElement>
10046
10477
  ) => {
10047
10478
  const isControlled = open !== undefined;
10048
10479
 
@@ -10233,7 +10664,7 @@ import type { BankDetailsProps, BankDetailItem } from "./types";
10233
10664
  * />
10234
10665
  * \`\`\`
10235
10666
  */
10236
- export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
10667
+ export const BankDetails = React.forwardRef(
10237
10668
  (
10238
10669
  {
10239
10670
  title = "Bank details",
@@ -10245,8 +10676,8 @@ export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
10245
10676
  onOpenChange,
10246
10677
  onCopy,
10247
10678
  className,
10248
- },
10249
- ref
10679
+ }: BankDetailsProps,
10680
+ ref: React.Ref<HTMLDivElement>
10250
10681
  ) => {
10251
10682
  const isControlled = open !== undefined;
10252
10683
 
@@ -11062,8 +11493,8 @@ const BreakdownCardRow = ({ item }: { item: BreakdownCardItem }) => (
11062
11493
  * />
11063
11494
  * \`\`\`
11064
11495
  */
11065
- export const PaymentSummary = React.forwardRef<HTMLDivElement, PaymentSummaryProps>(
11066
- ({ items = [], summaryItems, className, title, headerInfo, subtotal, breakdownCard, creditLimit }, ref) => {
11496
+ export const PaymentSummary = React.forwardRef(
11497
+ ({ items = [], summaryItems, className, title, headerInfo, subtotal, breakdownCard, creditLimit }: PaymentSummaryProps, ref: React.Ref<HTMLDivElement>) => {
11067
11498
  const hasItemsBorder =
11068
11499
  items.length > 0 &&
11069
11500
  (!!subtotal || !!breakdownCard || (summaryItems && summaryItems.length > 0));
@@ -11260,10 +11691,7 @@ import type { PaymentOptionCardProps } from "./types";
11260
11691
  * />
11261
11692
  * \`\`\`
11262
11693
  */
11263
- export const PaymentOptionCard = React.forwardRef<
11264
- HTMLDivElement,
11265
- PaymentOptionCardProps
11266
- >(
11694
+ export const PaymentOptionCard = React.forwardRef(
11267
11695
  (
11268
11696
  {
11269
11697
  title = "Select payment method",
@@ -11278,8 +11706,8 @@ export const PaymentOptionCard = React.forwardRef<
11278
11706
  loading = false,
11279
11707
  disabled = false,
11280
11708
  className,
11281
- },
11282
- ref
11709
+ }: PaymentOptionCardProps,
11710
+ ref: React.Ref<HTMLDivElement>
11283
11711
  ) => {
11284
11712
  const [internalSelected, setInternalSelected] = React.useState<
11285
11713
  string | undefined
@@ -11412,10 +11840,7 @@ export interface PaymentOptionCardModalProps
11412
11840
  * />
11413
11841
  * \`\`\`
11414
11842
  */
11415
- export const PaymentOptionCardModal = React.forwardRef<
11416
- HTMLDivElement,
11417
- PaymentOptionCardModalProps
11418
- >(
11843
+ export const PaymentOptionCardModal = React.forwardRef(
11419
11844
  (
11420
11845
  {
11421
11846
  open,
@@ -11431,8 +11856,8 @@ export const PaymentOptionCardModal = React.forwardRef<
11431
11856
  loading,
11432
11857
  disabled,
11433
11858
  className,
11434
- },
11435
- ref
11859
+ }: PaymentOptionCardModalProps,
11860
+ ref: React.Ref<HTMLDivElement>
11436
11861
  ) => {
11437
11862
  const handleClose = () => {
11438
11863
  onOpenChange(false);
@@ -11570,7 +11995,7 @@ const DEFAULT_FEATURES: PlanFeature[] = [
11570
11995
  { name: "Channel(s)", free: "1 Pair(s)", rate: "\u20B9 300.00" },
11571
11996
  ];
11572
11997
 
11573
- const PlanDetailModal = React.forwardRef<HTMLDivElement, PlanDetailModalProps>(
11998
+ const PlanDetailModal = React.forwardRef(
11574
11999
  (
11575
12000
  {
11576
12001
  open,
@@ -11581,8 +12006,8 @@ const PlanDetailModal = React.forwardRef<HTMLDivElement, PlanDetailModalProps>(
11581
12006
  onClose,
11582
12007
  className,
11583
12008
  ...props
11584
- },
11585
- ref
12009
+ }: PlanDetailModalProps,
12010
+ ref: React.Ref<HTMLDivElement>
11586
12011
  ) => {
11587
12012
  const handleClose = () => {
11588
12013
  onClose?.();
@@ -11791,7 +12216,7 @@ const renderOptionIcon = (icon: BillingCycleOption["icon"]) => {
11791
12216
  return icon;
11792
12217
  };
11793
12218
 
11794
- const PlanUpgradeModal = React.forwardRef<HTMLDivElement, PlanUpgradeModalProps>(
12219
+ const PlanUpgradeModal = React.forwardRef(
11795
12220
  (
11796
12221
  {
11797
12222
  open,
@@ -11808,8 +12233,8 @@ const PlanUpgradeModal = React.forwardRef<HTMLDivElement, PlanUpgradeModalProps>
11808
12233
  onClose,
11809
12234
  className,
11810
12235
  ...props
11811
- },
11812
- ref
12236
+ }: PlanUpgradeModalProps,
12237
+ ref: React.Ref<HTMLDivElement>
11813
12238
  ) => {
11814
12239
  const initialOptionId = defaultSelectedOptionId ?? options[0]?.id;
11815
12240
  const [internalSelectedOptionId, setInternalSelectedOptionId] = React.useState<
@@ -12087,10 +12512,7 @@ const getStatusIcon = (tone: PlanUpgradeSummaryTone) => {
12087
12512
  return <AlertCircle className="size-6 text-semantic-warning-text" aria-hidden="true" />;
12088
12513
  };
12089
12514
 
12090
- const PlanUpgradeSummaryModal = React.forwardRef<
12091
- HTMLDivElement,
12092
- PlanUpgradeSummaryModalProps
12093
- >(
12515
+ const PlanUpgradeSummaryModal = React.forwardRef(
12094
12516
  (
12095
12517
  {
12096
12518
  open,
@@ -12112,8 +12534,8 @@ const PlanUpgradeSummaryModal = React.forwardRef<
12112
12534
  closeAriaLabel = "Close plan summary modal",
12113
12535
  className,
12114
12536
  ...props
12115
- },
12116
- ref
12537
+ }: PlanUpgradeSummaryModalProps,
12538
+ ref: React.Ref<HTMLDivElement>
12117
12539
  ) => {
12118
12540
  const resolvedStatus = status ?? defaultStatusByMode[mode];
12119
12541
  const resolvedTone = resolvedStatus.tone ?? defaultStatusByMode[mode].tone ?? "warning";
@@ -12350,7 +12772,7 @@ import type { LetUsDriveCardProps } from "./types";
12350
12772
  * />
12351
12773
  * \`\`\`
12352
12774
  */
12353
- const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12775
+ const LetUsDriveCard = React.forwardRef(
12354
12776
  (
12355
12777
  {
12356
12778
  title,
@@ -12370,8 +12792,8 @@ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12370
12792
  onCtaClick,
12371
12793
  className,
12372
12794
  ...props
12373
- },
12374
- ref
12795
+ }: LetUsDriveCardProps,
12796
+ ref: React.Ref<HTMLDivElement>
12375
12797
  ) => {
12376
12798
  const [internalExpanded, setInternalExpanded] = React.useState(false);
12377
12799
  const isControlled = controlledExpanded !== undefined;
@@ -12395,7 +12817,7 @@ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12395
12817
  <div
12396
12818
  ref={ref}
12397
12819
  className={cn(
12398
- "flex h-full min-h-0 flex-col gap-6 rounded-[14px] border border-semantic-border-layout bg-card p-5 shadow-sm",
12820
+ "flex min-h-0 flex-col gap-6 rounded-[14px] border border-semantic-border-layout bg-card p-5 shadow-sm",
12399
12821
  className
12400
12822
  )}
12401
12823
  {...props}
@@ -12634,7 +13056,7 @@ import type { PowerUpCardProps } from "./types";
12634
13056
  * />
12635
13057
  * \`\`\`
12636
13058
  */
12637
- const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
13059
+ const PowerUpCard = React.forwardRef(
12638
13060
  (
12639
13061
  {
12640
13062
  icon,
@@ -12645,8 +13067,8 @@ const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
12645
13067
  onCtaClick,
12646
13068
  className,
12647
13069
  ...props
12648
- },
12649
- ref
13070
+ }: PowerUpCardProps,
13071
+ ref: React.Ref<HTMLDivElement>
12650
13072
  ) => {
12651
13073
  return (
12652
13074
  <div
@@ -12773,7 +13195,7 @@ import type { PricingCardProps } from "./types";
12773
13195
  * />
12774
13196
  * \`\`\`
12775
13197
  */
12776
- const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
13198
+ const PricingCard = React.forwardRef(
12777
13199
  (
12778
13200
  {
12779
13201
  planName,
@@ -12797,8 +13219,8 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12797
13219
  infoText,
12798
13220
  className,
12799
13221
  ...props
12800
- },
12801
- ref
13222
+ }: PricingCardProps,
13223
+ ref: React.Ref<HTMLDivElement>
12802
13224
  ) => {
12803
13225
  const buttonText =
12804
13226
  ctaText || (isCurrentPlan ? "Current plan" : "Select plan");
@@ -12820,9 +13242,6 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12820
13242
  {/* Header */}
12821
13243
  <div
12822
13244
  className="flex flex-col gap-4 rounded-t-xl rounded-b-lg p-4"
12823
- style={
12824
- headerBgColor ? { backgroundColor: headerBgColor } : undefined
12825
- }
12826
13245
  >
12827
13246
  {/* Plan name + badge */}
12828
13247
  <div className="flex items-center gap-4">
@@ -12880,11 +13299,11 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12880
13299
  </div>
12881
13300
  )}
12882
13301
  <Button
12883
- variant={isCurrentPlan ? "outline" : "default"}
13302
+ variant={isCurrentPlan ? "secondary" : "default"}
12884
13303
  className="w-full"
12885
13304
  onClick={onCtaClick}
12886
13305
  loading={ctaLoading}
12887
- disabled={ctaDisabled}
13306
+ disabled={ctaDisabled || isCurrentPlan}
12888
13307
  >
12889
13308
  {buttonText}
12890
13309
  </Button>
@@ -12931,29 +13350,34 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12931
13350
  </div>
12932
13351
  )}
12933
13352
 
12934
- {/* Addon */}
12935
- {addon && (
12936
- <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
12937
- {addon.icon && (
12938
- <div className="size-5 shrink-0">{addon.icon}</div>
12939
- )}
12940
- <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
12941
- {addon.text}
12942
- </span>
12943
- </div>
12944
- )}
12945
-
12946
- {/* Usage Details */}
12947
- {usageDetails && usageDetails.length > 0 && (
12948
- <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
12949
- {usageDetails.map((detail, index) => (
12950
- <div key={index} className="flex items-start gap-2">
12951
- <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
13353
+ {/* Bottom sections pushed to card bottom for grid alignment */}
13354
+ {(addon || (usageDetails && usageDetails.length > 0)) && (
13355
+ <div className="mt-auto flex flex-col gap-6">
13356
+ {/* Addon */}
13357
+ {addon && (
13358
+ <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
13359
+ {addon.icon && (
13360
+ <div className="size-5 shrink-0">{addon.icon}</div>
13361
+ )}
12952
13362
  <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
12953
- <strong>{detail.label}:</strong> {detail.value}
13363
+ {addon.text}
12954
13364
  </span>
12955
13365
  </div>
12956
- ))}
13366
+ )}
13367
+
13368
+ {/* Usage Details */}
13369
+ {usageDetails && usageDetails.length > 0 && (
13370
+ <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
13371
+ {usageDetails.map((detail, index) => (
13372
+ <div key={index} className="flex items-start gap-2">
13373
+ <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
13374
+ <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
13375
+ <strong>{detail.label}:</strong> {detail.value}
13376
+ </span>
13377
+ </div>
13378
+ ))}
13379
+ </div>
13380
+ )}
12957
13381
  </div>
12958
13382
  )}
12959
13383
  </div>
@@ -12974,8 +13398,8 @@ interface PlanIconProps extends React.SVGAttributes<SVGElement> {
12974
13398
  className?: string;
12975
13399
  }
12976
13400
 
12977
- const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
12978
- ({ className, ...props }, ref) => (
13401
+ const CompactCarIcon = React.forwardRef(
13402
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
12979
13403
  <svg
12980
13404
  ref={ref}
12981
13405
  className={className}
@@ -13014,8 +13438,8 @@ const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13014
13438
  );
13015
13439
  CompactCarIcon.displayName = "CompactCarIcon";
13016
13440
 
13017
- const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13018
- ({ className, ...props }, ref) => (
13441
+ const SedanCarIcon = React.forwardRef(
13442
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13019
13443
  <svg
13020
13444
  ref={ref}
13021
13445
  className={className}
@@ -13066,8 +13490,8 @@ const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13066
13490
  );
13067
13491
  SedanCarIcon.displayName = "SedanCarIcon";
13068
13492
 
13069
- const SuvCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13070
- ({ className, ...props }, ref) => (
13493
+ const SuvCarIcon = React.forwardRef(
13494
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13071
13495
  <svg
13072
13496
  ref={ref}
13073
13497
  className={className}
@@ -13280,7 +13704,7 @@ import type { PricingPageProps } from "./types";
13280
13704
  * />
13281
13705
  * \`\`\`
13282
13706
  */
13283
- const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13707
+ const PricingPage = React.forwardRef(
13284
13708
  (
13285
13709
  {
13286
13710
  title = "Select business plan",
@@ -13300,11 +13724,10 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13300
13724
  onFeatureComparisonClick,
13301
13725
  letUsDriveCards = [],
13302
13726
  letUsDriveTitle = "Let us drive \u2014 Full-service management",
13303
- letUsDriveExpandMode,
13304
13727
  className,
13305
- ...props
13306
- },
13307
- ref
13728
+ ...props
13729
+ }: PricingPageProps,
13730
+ ref: React.Ref<HTMLDivElement>
13308
13731
  ) => {
13309
13732
  // Internal state for uncontrolled mode
13310
13733
  const [internalTab, setInternalTab] = React.useState(
@@ -13313,9 +13736,6 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13313
13736
  const [internalBilling, setInternalBilling] = React.useState<
13314
13737
  "monthly" | "yearly"
13315
13738
  >("monthly");
13316
- const [expandedLetUsDriveIndices, setExpandedLetUsDriveIndices] =
13317
- React.useState<number[]>([]);
13318
-
13319
13739
  const currentTab = controlledTab ?? internalTab;
13320
13740
  const currentBilling = controlledBilling ?? internalBilling;
13321
13741
 
@@ -13329,30 +13749,6 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13329
13749
  onBillingPeriodChange?.(period);
13330
13750
  };
13331
13751
 
13332
- const cardCount = letUsDriveCards.length;
13333
-
13334
- const handleLetUsDriveExpandedChange = (index: number, expanded: boolean) => {
13335
- if (letUsDriveExpandMode === "all") {
13336
- if (expanded) {
13337
- setExpandedLetUsDriveIndices(
13338
- Array.from({ length: cardCount }, (_, i) => i)
13339
- );
13340
- } else {
13341
- setExpandedLetUsDriveIndices((prev) =>
13342
- prev.filter((i) => i !== index)
13343
- );
13344
- }
13345
- } else {
13346
- if (expanded) {
13347
- setExpandedLetUsDriveIndices([index]);
13348
- } else {
13349
- setExpandedLetUsDriveIndices((prev) =>
13350
- prev.filter((i) => i !== index)
13351
- );
13352
- }
13353
- }
13354
- };
13355
-
13356
13752
  const hasPowerUps = powerUpCards.length > 0;
13357
13753
  const hasLetUsDrive = letUsDriveCards.length > 0;
13358
13754
 
@@ -13448,22 +13844,11 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13448
13844
  {letUsDriveTitle}
13449
13845
  </h2>
13450
13846
 
13451
- {/* Service cards \u2014 items-stretch + card h-full + mt-auto on actions align Talk to us buttons */}
13452
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-stretch">
13453
- {letUsDriveCards.map((cardProps, index) => {
13454
- const hasDetailsContent =
13455
- cardProps.detailsContent &&
13456
- cardProps.detailsContent.items.length > 0;
13457
- const useControlledExpand =
13458
- letUsDriveExpandMode && hasDetailsContent;
13459
- const merged = { ...cardProps };
13460
- if (useControlledExpand) {
13461
- merged.expanded = expandedLetUsDriveIndices.includes(index);
13462
- merged.onExpandedChange = (expanded: boolean) =>
13463
- handleLetUsDriveExpandedChange(index, expanded);
13464
- }
13465
- return <LetUsDriveCard key={index} {...merged} />;
13466
- })}
13847
+ {/* Service cards \u2014 items-start so expanding one card doesn't stretch others */}
13848
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-start">
13849
+ {letUsDriveCards.map((cardProps, index) => (
13850
+ <LetUsDriveCard key={index} {...cardProps} />
13851
+ ))}
13467
13852
  </div>
13468
13853
  </div>
13469
13854
  </div>
@@ -13552,13 +13937,6 @@ export interface PricingPageProps
13552
13937
  letUsDriveCards?: LetUsDriveCardProps[];
13553
13938
  /** Let-us-drive section heading (default: "Let us drive \u2014 Full-service management") */
13554
13939
  letUsDriveTitle?: string;
13555
- /**
13556
- * When set, controls how "Show details" expands across cards.
13557
- * - "single": only the clicked card expands (accordion).
13558
- * - "all": clicking "Show details" on any card expands all cards that have detailsContent.
13559
- * Ignored when cards are used without detailsContent or without controlled expanded state.
13560
- */
13561
- letUsDriveExpandMode?: "single" | "all";
13562
13940
  }
13563
13941
  `, prefix)
13564
13942
  },
@@ -13615,7 +13993,7 @@ import type { PricingToggleProps } from "./types";
13615
13993
  * />
13616
13994
  * \`\`\`
13617
13995
  */
13618
- const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13996
+ const PricingToggle = React.forwardRef(
13619
13997
  (
13620
13998
  {
13621
13999
  tabs,
@@ -13628,8 +14006,8 @@ const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13628
14006
  yearlyLabel = "Yearly (Save 20%)",
13629
14007
  className,
13630
14008
  ...props
13631
- },
13632
- ref
14009
+ }: PricingToggleProps,
14010
+ ref: React.Ref<HTMLDivElement>
13633
14011
  ) => {
13634
14012
  const isYearly = billingPeriod === "yearly";
13635
14013
 
@@ -13874,8 +14252,8 @@ interface BrandIconProps extends React.SVGAttributes<SVGElement> {
13874
14252
  * Used in TalkToUsModal and available for any component that needs
13875
14253
  * the MyOperator contact/chat branding.
13876
14254
  */
13877
- const MyOperatorChatIcon = React.forwardRef<SVGSVGElement, BrandIconProps>(
13878
- ({ className, ...props }, ref) => (
14255
+ const MyOperatorChatIcon = React.forwardRef(
14256
+ ({ className, ...props }: BrandIconProps, ref: React.Ref<SVGSVGElement>) => (
13879
14257
  <svg
13880
14258
  ref={ref}
13881
14259
  className={className}
@@ -14008,8 +14386,8 @@ function getTypeLabel(
14008
14386
  * All displayed data (icon, badge, name, count, last published) comes from the \`bot\` prop.
14009
14387
  * Set bot.type to "chatbot" or "voicebot"; no separate card components needed.
14010
14388
  */
14011
- export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14012
- ({ bot, typeLabels, onEdit, onDelete, className, ...props }, ref) => {
14389
+ export const BotCard = React.forwardRef(
14390
+ ({ bot, typeLabels, onEdit, onDelete, className, ...props }: BotCardProps, ref: React.Ref<HTMLDivElement>) => {
14013
14391
  const typeLabel = getTypeLabel(bot, typeLabels);
14014
14392
  const isChatbot = bot.type === "chatbot";
14015
14393
 
@@ -14097,7 +14475,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14097
14475
  </div>
14098
14476
 
14099
14477
  {/* Bot name */}
14100
- <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary truncate mb-1 min-w-0">
14478
+ <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary line-clamp-1 mb-1 min-w-0">
14101
14479
  {bot.name}
14102
14480
  </h3>
14103
14481
 
@@ -14125,7 +14503,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14125
14503
  </span>
14126
14504
  )}
14127
14505
  {(bot.lastPublishedBy || bot.lastPublishedDate) ? (
14128
- <p className="m-0 text-xs sm:text-sm text-semantic-text-muted truncate">
14506
+ <p className="m-0 text-xs sm:text-sm text-semantic-text-muted line-clamp-1">
14129
14507
  {bot.lastPublishedBy
14130
14508
  ? \`\${bot.lastPublishedBy} | \${bot.lastPublishedDate ?? "\u2014"}\`
14131
14509
  : bot.lastPublishedDate}
@@ -14175,10 +14553,7 @@ const BOT_TYPE_OPTIONS: BotTypeOption[] = [
14175
14553
  },
14176
14554
  ];
14177
14555
 
14178
- export const CreateBotModal = React.forwardRef<
14179
- HTMLDivElement,
14180
- CreateBotModalProps
14181
- >(({ open, onOpenChange, onSubmit, isLoading, className }, ref) => {
14556
+ export const CreateBotModal = React.forwardRef(({ open, onOpenChange, onSubmit, isLoading, className }: CreateBotModalProps, ref: React.Ref<HTMLDivElement>) => {
14182
14557
  const [name, setName] = React.useState("");
14183
14558
  const [selectedType, setSelectedType] = React.useState<BotType>("chatbot");
14184
14559
 
@@ -14326,15 +14701,15 @@ import type { CreateBotFlowProps } from "./types";
14326
14701
  * Create bot flow: "Create new bot" card + Create Bot modal. No header (title/subtitle/search).
14327
14702
  * Use when you want the create-bot experience without the list header.
14328
14703
  */
14329
- export const CreateBotFlow = React.forwardRef<HTMLDivElement, CreateBotFlowProps>(
14704
+ export const CreateBotFlow = React.forwardRef(
14330
14705
  (
14331
14706
  {
14332
14707
  createCardLabel = "Create new bot",
14333
14708
  onSubmit,
14334
14709
  className,
14335
14710
  ...props
14336
- },
14337
- ref
14711
+ }: CreateBotFlowProps,
14712
+ ref: React.Ref<HTMLDivElement>
14338
14713
  ) => {
14339
14714
  const [modalOpen, setModalOpen] = React.useState(false);
14340
14715
 
@@ -14450,7 +14825,7 @@ import { BotListGrid } from "./bot-list-grid";
14450
14825
  import { CreateBotModal } from "./create-bot-modal";
14451
14826
  import type { BotListProps } from "./types";
14452
14827
 
14453
- export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14828
+ export const BotList = React.forwardRef(
14454
14829
  (
14455
14830
  {
14456
14831
  bots = [],
@@ -14466,8 +14841,8 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14466
14841
  createCardLabel = "Create new bot",
14467
14842
  className,
14468
14843
  ...props
14469
- },
14470
- ref
14844
+ }: BotListProps,
14845
+ ref: React.Ref<HTMLDivElement>
14471
14846
  ) => {
14472
14847
  const [searchQuery, setSearchQuery] = React.useState("");
14473
14848
  const [createModalOpen, setCreateModalOpen] = React.useState(false);
@@ -14577,10 +14952,10 @@ const botListHeaderVariants = cva("min-w-0", {
14577
14952
  },
14578
14953
  });
14579
14954
 
14580
- export const BotListHeader = React.forwardRef<HTMLDivElement, BotListHeaderProps>(
14955
+ export const BotListHeader = React.forwardRef(
14581
14956
  (
14582
- { title, subtitle, variant = "default", rightContent, className, ...props },
14583
- ref
14957
+ { title, subtitle, variant = "default", rightContent, className, ...props }: BotListHeaderProps,
14958
+ ref: React.Ref<HTMLDivElement>
14584
14959
  ) => {
14585
14960
  const rootClassName = cn(botListHeaderVariants({ variant }), className);
14586
14961
  const titleBlock = (
@@ -14627,7 +15002,7 @@ import { Search } from "lucide-react";
14627
15002
  import { cn } from "../../../lib/utils";
14628
15003
  import type { BotListSearchProps } from "./types";
14629
15004
 
14630
- export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps>(
15005
+ export const BotListSearch = React.forwardRef(
14631
15006
  (
14632
15007
  {
14633
15008
  value,
@@ -14636,8 +15011,8 @@ export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps
14636
15011
  defaultValue,
14637
15012
  className,
14638
15013
  ...props
14639
- },
14640
- ref
15014
+ }: BotListSearchProps,
15015
+ ref: React.Ref<HTMLDivElement>
14641
15016
  ) => {
14642
15017
  const [internalValue, setInternalValue] = React.useState(defaultValue ?? "");
14643
15018
  const isControlled = value !== undefined;
@@ -14684,18 +15059,15 @@ import { Plus } from "lucide-react";
14684
15059
  import { cn } from "../../../lib/utils";
14685
15060
  import type { BotListCreateCardProps } from "./types";
14686
15061
 
14687
- export const BotListCreateCard = React.forwardRef<
14688
- HTMLButtonElement,
14689
- BotListCreateCardProps
14690
- >(
15062
+ export const BotListCreateCard = React.forwardRef(
14691
15063
  (
14692
15064
  {
14693
15065
  label = "Create new bot",
14694
15066
  onClick,
14695
15067
  className,
14696
15068
  ...props
14697
- },
14698
- ref
15069
+ }: BotListCreateCardProps,
15070
+ ref: React.Ref<HTMLButtonElement>
14699
15071
  ) => (
14700
15072
  <button
14701
15073
  ref={ref}
@@ -14744,8 +15116,8 @@ BotListCreateCard.displayName = "BotListCreateCard";
14744
15116
  import { cn } from "../../../lib/utils";
14745
15117
  import type { BotListGridProps } from "./types";
14746
15118
 
14747
- export const BotListGrid = React.forwardRef<HTMLDivElement, BotListGridProps>(
14748
- ({ children, className, ...props }, ref) => (
15119
+ export const BotListGrid = React.forwardRef(
15120
+ ({ children, className, ...props }: BotListGridProps, ref: React.Ref<HTMLDivElement>) => (
14749
15121
  <div
14750
15122
  ref={ref}
14751
15123
  className={cn(
@@ -15047,7 +15419,7 @@ function getTimeRemaining(progress: number) {
15047
15419
  : \`\${secs} seconds remaining\`;
15048
15420
  }
15049
15421
 
15050
- const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15422
+ const FileUploadModal = React.forwardRef(
15051
15423
  (
15052
15424
  {
15053
15425
  open,
@@ -15070,8 +15442,8 @@ const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15070
15442
  loading = false,
15071
15443
  className,
15072
15444
  ...props
15073
- },
15074
- ref
15445
+ }: FileUploadModalProps,
15446
+ ref: React.Ref<HTMLDivElement>
15075
15447
  ) => {
15076
15448
  const [items, setItems] = React.useState<UploadItem[]>([]);
15077
15449
  const fileInputRef = React.useRef<HTMLInputElement>(null);
@@ -15441,8 +15813,8 @@ import { X, Play, File } from "lucide-react";
15441
15813
  import { cn } from "../../../lib/utils";
15442
15814
  import type { AttachmentPreviewProps } from "./types";
15443
15815
 
15444
- const AttachmentPreview = React.forwardRef<HTMLDivElement, AttachmentPreviewProps>(
15445
- ({ className, file, onRemove, ...props }, ref) => {
15816
+ const AttachmentPreview = React.forwardRef(
15817
+ ({ className, file, onRemove, ...props }: AttachmentPreviewProps, ref: React.Ref<HTMLDivElement>) => {
15446
15818
  const url = React.useMemo(() => URL.createObjectURL(file), [file]);
15447
15819
 
15448
15820
  const isImage = file.type.startsWith("image/");
@@ -15600,7 +15972,7 @@ const BAR_WIDTH = 2;
15600
15972
  const BAR_GAP = 1.5;
15601
15973
  const SVG_HEIGHT = 32;
15602
15974
 
15603
- const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15975
+ const AudioMedia = React.forwardRef(
15604
15976
  (
15605
15977
  {
15606
15978
  className,
@@ -15614,8 +15986,8 @@ const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15614
15986
  onPlayChange,
15615
15987
  onSpeedChange,
15616
15988
  ...props
15617
- },
15618
- ref
15989
+ }: AudioMediaProps,
15990
+ ref: React.Ref<HTMLDivElement>
15619
15991
  ) => {
15620
15992
  const [playing, setPlaying] = React.useState(false);
15621
15993
  const [speed, setSpeed] = React.useState(1);
@@ -15815,8 +16187,8 @@ import { Reply, ExternalLink, ChevronLeft, ChevronRight } from "lucide-react";
15815
16187
  import { cn } from "../../../lib/utils";
15816
16188
  import type { CarouselMediaProps } from "./types";
15817
16189
 
15818
- const CarouselMedia = React.forwardRef<HTMLDivElement, CarouselMediaProps>(
15819
- ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }, ref) => {
16190
+ const CarouselMedia = React.forwardRef(
16191
+ ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }: CarouselMediaProps, ref: React.Ref<HTMLDivElement>) => {
15820
16192
  const scrollRef = useRef<HTMLDivElement>(null);
15821
16193
  const [canScrollLeft, setCanScrollLeft] = useState(false);
15822
16194
  const [canScrollRight, setCanScrollRight] = useState(
@@ -16070,7 +16442,7 @@ function DeliveryFooter({
16070
16442
  * </ChatBubble>
16071
16443
  * \`\`\`
16072
16444
  */
16073
- const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16445
+ const ChatBubble = React.forwardRef(
16074
16446
  (
16075
16447
  {
16076
16448
  variant,
@@ -16085,8 +16457,8 @@ const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16085
16457
  children,
16086
16458
  className,
16087
16459
  ...props
16088
- },
16089
- ref
16460
+ }: ChatBubbleProps,
16461
+ ref: React.Ref<HTMLDivElement>
16090
16462
  ) => {
16091
16463
  const hasMedia = !!media;
16092
16464
 
@@ -16204,6 +16576,126 @@ export interface ChatBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
16204
16576
  name: "index.ts",
16205
16577
  content: prefixTailwindClasses(`export { ChatBubble } from "./chat-bubble";
16206
16578
  export type { ChatBubbleProps, ChatBubbleReply, DeliveryStatus } from "./types";
16579
+ `, prefix)
16580
+ }
16581
+ ]
16582
+ },
16583
+ "chat-timeline-divider": {
16584
+ name: "chat-timeline-divider",
16585
+ description: "A timeline divider for chat message lists \u2014 renders centered content between horizontal lines with date, unread, and system event variants",
16586
+ category: "custom",
16587
+ dependencies: [
16588
+ "clsx",
16589
+ "tailwind-merge"
16590
+ ],
16591
+ internalDependencies: [],
16592
+ isMultiFile: true,
16593
+ directory: "chat-timeline-divider",
16594
+ mainFile: "chat-timeline-divider.tsx",
16595
+ files: [
16596
+ {
16597
+ name: "chat-timeline-divider.tsx",
16598
+ content: prefixTailwindClasses(`import * as React from "react";
16599
+ import { cn } from "../../../lib/utils";
16600
+
16601
+ /* \u2500\u2500 Types \u2500\u2500 */
16602
+
16603
+ export type ChatTimelineDividerVariant = "default" | "unread" | "system";
16604
+
16605
+ export interface ChatTimelineDividerProps
16606
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
16607
+ /**
16608
+ * Visual style of the divider.
16609
+ * - \`default\`: plain centered text between lines (e.g. "Today", "Yesterday")
16610
+ * - \`unread\`: bold text in a white pill with border (e.g. "3 unread messages")
16611
+ * - \`system\`: muted text in a white pill with border (e.g. "Assigned to Alex Smith")
16612
+ */
16613
+ variant?: ChatTimelineDividerVariant;
16614
+ /** Content to display \u2014 text or ReactNode for rich content (e.g. linked names) */
16615
+ children: React.ReactNode;
16616
+ }
16617
+
16618
+ /* \u2500\u2500 Variant styles \u2500\u2500 */
16619
+
16620
+ const containerStyles: Record<ChatTimelineDividerVariant, string> = {
16621
+ default: "",
16622
+ unread:
16623
+ "bg-white px-2.5 py-0.5 rounded-full border border-semantic-border-layout shadow-sm",
16624
+ system:
16625
+ "bg-white px-2.5 py-1 rounded-full border border-semantic-border-layout shadow-[0px_1px_2px_0px_rgba(10,13,18,0.05)]",
16626
+ };
16627
+
16628
+ const textStyles: Record<ChatTimelineDividerVariant, string> = {
16629
+ default: "text-[13px] text-semantic-text-muted",
16630
+ unread: "text-[12px] font-semibold text-semantic-text-primary",
16631
+ system: "text-[13px] text-semantic-text-muted",
16632
+ };
16633
+
16634
+ /* \u2500\u2500 Component \u2500\u2500 */
16635
+
16636
+ /**
16637
+ * ChatTimelineDivider renders a centered label between two horizontal lines
16638
+ * in a chat message timeline.
16639
+ *
16640
+ * Use it to separate messages by date, mark unread boundaries,
16641
+ * or display system/action events (assignments, resolutions, etc.).
16642
+ *
16643
+ * @example
16644
+ * \`\`\`tsx
16645
+ * // Date separator
16646
+ * <ChatTimelineDivider>Today</ChatTimelineDivider>
16647
+ *
16648
+ * // Unread count
16649
+ * <ChatTimelineDivider variant="unread">3 unread messages</ChatTimelineDivider>
16650
+ *
16651
+ * // System event with linked names
16652
+ * <ChatTimelineDivider variant="system">
16653
+ * Assigned to <span className="text-semantic-text-link font-medium">Alex Smith</span>
16654
+ * </ChatTimelineDivider>
16655
+ * \`\`\`
16656
+ */
16657
+ const ChatTimelineDivider = React.forwardRef<
16658
+ HTMLDivElement,
16659
+ ChatTimelineDividerProps
16660
+ >(
16661
+ (
16662
+ { variant = "default", children, className, ...props },
16663
+ ref
16664
+ ) => {
16665
+ const showLines = true;
16666
+
16667
+ return (
16668
+ <div
16669
+ ref={ref}
16670
+ role="separator"
16671
+ className={cn("flex items-center gap-4 my-2", className)}
16672
+ {...props}
16673
+ >
16674
+ {showLines && (
16675
+ <div className="flex-1 h-px bg-semantic-border-layout" />
16676
+ )}
16677
+ <div className={cn(containerStyles[variant])}>
16678
+ <span className={cn(textStyles[variant])}>{children}</span>
16679
+ </div>
16680
+ {showLines && (
16681
+ <div className="flex-1 h-px bg-semantic-border-layout" />
16682
+ )}
16683
+ </div>
16684
+ );
16685
+ }
16686
+ );
16687
+ ChatTimelineDivider.displayName = "ChatTimelineDivider";
16688
+
16689
+ export { ChatTimelineDivider };
16690
+ `, prefix)
16691
+ },
16692
+ {
16693
+ name: "index.ts",
16694
+ content: prefixTailwindClasses(`export {
16695
+ ChatTimelineDivider,
16696
+ type ChatTimelineDividerProps,
16697
+ type ChatTimelineDividerVariant,
16698
+ } from "./chat-timeline-divider";
16207
16699
  `, prefix)
16208
16700
  }
16209
16701
  ]
@@ -16259,7 +16751,7 @@ import type { ChatComposerProps } from "./types";
16259
16751
  * />
16260
16752
  * \`\`\`
16261
16753
  */
16262
- const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16754
+ const ChatComposer = React.forwardRef(
16263
16755
  (
16264
16756
  {
16265
16757
  className,
@@ -16283,8 +16775,8 @@ const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16283
16775
  expiredMessage = "This chat has expired. Send a template to continue.",
16284
16776
  onTemplateClick,
16285
16777
  ...props
16286
- },
16287
- ref
16778
+ }: ChatComposerProps,
16779
+ ref: React.Ref<HTMLDivElement>
16288
16780
  ) => {
16289
16781
  const textareaRef = React.useRef<HTMLTextAreaElement>(null);
16290
16782
 
@@ -16459,8 +16951,8 @@ export interface ChatComposerProps extends Omit<React.HTMLAttributes<HTMLDivElem
16459
16951
  leftActions?: React.ReactNode;
16460
16952
  /** Slot for right action buttons (rendered inside textarea container, bottom-right) */
16461
16953
  rightActions?: React.ReactNode;
16462
- /** Send button label. Defaults to "Send" */
16463
- sendLabel?: string;
16954
+ /** Send button label. Accepts text or JSX (e.g. icon + text). Defaults to "Send" */
16955
+ sendLabel?: React.ReactNode;
16464
16956
  /** Whether to show the send dropdown chevron. Defaults to false */
16465
16957
  showSendDropdown?: boolean;
16466
16958
  /** Whether the chat is expired (shows template prompt instead of composer) */
@@ -16501,7 +16993,7 @@ import { cn } from "../../../lib/utils";
16501
16993
  import { File, FileSpreadsheet, ArrowDownToLine } from "lucide-react";
16502
16994
  import type { DocMediaProps } from "./types";
16503
16995
 
16504
- const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16996
+ const DocMedia = React.forwardRef(
16505
16997
  (
16506
16998
  {
16507
16999
  className,
@@ -16514,8 +17006,8 @@ const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16514
17006
  caption,
16515
17007
  onDownload,
16516
17008
  ...props
16517
- },
16518
- ref
17009
+ }: DocMediaProps,
17010
+ ref: React.Ref<HTMLDivElement>
16519
17011
  ) => {
16520
17012
  if (variant === "preview") {
16521
17013
  return (
@@ -16554,12 +17046,35 @@ const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16554
17046
 
16555
17047
  if (variant === "download") {
16556
17048
  return (
16557
- <div ref={ref} className={cn("relative", className)} {...props}>
17049
+ <div
17050
+ ref={ref}
17051
+ className={cn("relative rounded-t overflow-hidden", className)}
17052
+ {...props}
17053
+ >
16558
17054
  <img
16559
17055
  src={thumbnailUrl}
16560
17056
  alt={caption || filename || "Document"}
16561
- className="w-full rounded-t object-cover max-h-[280px]"
17057
+ className="w-full object-cover"
17058
+ style={{ aspectRatio: "442/308" }}
16562
17059
  />
17060
+ <div className="absolute inset-0 bg-gradient-to-t from-[#1d222f] via-[#1d222f]/30 to-transparent" />
17061
+ <div className="absolute bottom-0 left-0 right-0 px-4 py-3">
17062
+ <p className="m-0 text-[14px] font-semibold text-white truncate">
17063
+ {filename || "Document"}
17064
+ </p>
17065
+ <div className="flex items-center gap-1.5 mt-1">
17066
+ <File className="size-3.5 text-white/80" />
17067
+ <span className="text-[12px] text-white/80">
17068
+ {[
17069
+ fileType,
17070
+ pageCount && \`\${pageCount} pages\`,
17071
+ fileSize,
17072
+ ]
17073
+ .filter(Boolean)
17074
+ .join(" \\u00B7 ")}
17075
+ </span>
17076
+ </div>
17077
+ </div>
16563
17078
  </div>
16564
17079
  );
16565
17080
  }
@@ -16702,7 +17217,7 @@ import type { VideoMediaProps } from "./types";
16702
17217
 
16703
17218
  const DEFAULT_SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
16704
17219
 
16705
- const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
17220
+ const VideoMedia = React.forwardRef(
16706
17221
  (
16707
17222
  {
16708
17223
  className,
@@ -16714,8 +17229,8 @@ const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
16714
17229
  onSpeedChange,
16715
17230
  onClick,
16716
17231
  ...props
16717
- },
16718
- ref
17232
+ }: VideoMediaProps,
17233
+ ref: React.Ref<HTMLDivElement>
16719
17234
  ) => {
16720
17235
  const [playing, setPlaying] = useState(false);
16721
17236
  const [muted, setMuted] = useState(false);
@@ -16948,7 +17463,10 @@ export type { VideoMediaProps } from "./types";
16948
17463
  "creatable-multi-select",
16949
17464
  "page-header",
16950
17465
  "tag",
16951
- "file-upload-modal"
17466
+ "file-upload-modal",
17467
+ "form-modal",
17468
+ "text-field",
17469
+ "textarea"
16952
17470
  ],
16953
17471
  isMultiFile: true,
16954
17472
  directory: "ivr-bot",
@@ -17000,7 +17518,7 @@ const DEFAULT_DATA: IvrBotConfigData = {
17000
17518
  };
17001
17519
 
17002
17520
  // \u2500\u2500\u2500 Main IvrBotConfig \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17003
- export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
17521
+ export const IvrBotConfig = React.forwardRef(
17004
17522
  (
17005
17523
  {
17006
17524
  botTitle = "IVR bot",
@@ -17047,8 +17565,8 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
17047
17565
  callEndThresholdMin,
17048
17566
  callEndThresholdMax,
17049
17567
  className,
17050
- },
17051
- ref
17568
+ }: IvrBotConfigProps,
17569
+ ref: React.Ref<HTMLDivElement>
17052
17570
  ) => {
17053
17571
  const [data, setData] = React.useState<IvrBotConfigData>({
17054
17572
  ...DEFAULT_DATA,
@@ -17251,7 +17769,7 @@ IvrBotConfig.displayName = "IvrBotConfig";
17251
17769
  {
17252
17770
  name: "create-function-modal.tsx",
17253
17771
  content: prefixTailwindClasses(`import * as React from "react";
17254
- import { Trash2, ChevronDown, X, Plus } from "lucide-react";
17772
+ import { Trash2, ChevronDown, X, Plus, Pencil } from "lucide-react";
17255
17773
  import { cn } from "../../../lib/utils";
17256
17774
  import {
17257
17775
  Dialog,
@@ -17259,6 +17777,9 @@ import {
17259
17777
  DialogTitle,
17260
17778
  } from "../dialog";
17261
17779
  import { Button } from "../button";
17780
+ import { FormModal } from "../form-modal";
17781
+ import { TextField } from "../text-field";
17782
+ import { Textarea } from "../textarea";
17262
17783
  import type {
17263
17784
  CreateFunctionModalProps,
17264
17785
  CreateFunctionData,
@@ -17266,10 +17787,12 @@ import type {
17266
17787
  FunctionTabType,
17267
17788
  HttpMethod,
17268
17789
  KeyValuePair,
17790
+ VariableGroup,
17791
+ VariableItem,
17792
+ VariableFormData,
17269
17793
  } from "./types";
17270
17794
 
17271
17795
  const HTTP_METHODS: HttpMethod[] = ["GET", "POST", "PUT", "DELETE", "PATCH"];
17272
- const METHODS_WITH_BODY: HttpMethod[] = ["POST", "PUT", "PATCH"];
17273
17796
  const FUNCTION_NAME_MAX = 100;
17274
17797
  const BODY_MAX = 4000;
17275
17798
  const URL_MAX = 500;
@@ -17277,6 +17800,8 @@ const HEADER_KEY_MAX = 512;
17277
17800
  const HEADER_VALUE_MAX = 2048;
17278
17801
 
17279
17802
  const FUNCTION_NAME_REGEX = /^(?!_+$)(?=.*[a-zA-Z])[a-zA-Z][a-zA-Z0-9_]*$/;
17803
+ const VARIABLE_NAME_MAX = 30;
17804
+ const VARIABLE_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;
17280
17805
  const URL_REGEX = /^https?:\\/\\//;
17281
17806
  const HEADER_KEY_REGEX = /^[!#$%&'*+\\-.^_\`|~0-9a-zA-Z]+$/;
17282
17807
  // Query parameter validation (aligned with apiIntegrationSchema.queryParams)
@@ -17332,120 +17857,395 @@ function extractVarRefs(texts: string[]): string[] {
17332
17857
  return Array.from(new Set(all));
17333
17858
  }
17334
17859
 
17335
- /** Mirror-div technique \u2014 returns { top, left } relative to the element's top-left corner. */
17336
- function getCaretPixelPos(
17337
- el: HTMLTextAreaElement | HTMLInputElement,
17338
- position: number
17339
- ): { top: number; left: number } {
17340
- const cs = window.getComputedStyle(el);
17341
- const mirror = document.createElement("div");
17342
-
17343
- (
17344
- [
17345
- "boxSizing", "width", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft",
17346
- "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth",
17347
- "fontFamily", "fontSize", "fontWeight", "fontStyle", "fontVariant",
17348
- "letterSpacing", "lineHeight", "textTransform", "wordSpacing", "tabSize",
17349
- ] as (keyof CSSStyleDeclaration)[]
17350
- ).forEach((prop) => {
17351
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17352
- (mirror.style as any)[prop] = cs[prop];
17353
- });
17860
+ // \u2500\u2500 Value segment parser \u2014 splits "text {{var}} text" into typed segments \u2500\u2500\u2500\u2500\u2500
17861
+
17862
+ type ValueSegment =
17863
+ | { type: "text"; content: string }
17864
+ | { type: "var"; name: string; raw: string };
17865
+
17866
+ function parseValueSegments(value: string): ValueSegment[] {
17867
+ const segments: ValueSegment[] = [];
17868
+ const regex = /\\{\\{([^}]+)\\}\\}/g;
17869
+ let lastIndex = 0;
17870
+ let match;
17871
+ while ((match = regex.exec(value)) !== null) {
17872
+ if (match.index > lastIndex) {
17873
+ segments.push({ type: "text", content: value.slice(lastIndex, match.index) });
17874
+ }
17875
+ segments.push({ type: "var", name: match[1], raw: match[0] });
17876
+ lastIndex = regex.lastIndex;
17877
+ }
17878
+ if (lastIndex < value.length) {
17879
+ segments.push({ type: "text", content: value.slice(lastIndex) });
17880
+ }
17881
+ return segments;
17882
+ }
17883
+
17884
+ /** Mirror-div technique \u2014 returns { top, left } relative to the element's top-left corner. */
17885
+ function getCaretPixelPos(
17886
+ el: HTMLTextAreaElement | HTMLInputElement,
17887
+ position: number
17888
+ ): { top: number; left: number } {
17889
+ const cs = window.getComputedStyle(el);
17890
+ const mirror = document.createElement("div");
17891
+
17892
+ (
17893
+ [
17894
+ "boxSizing", "width", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft",
17895
+ "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth",
17896
+ "fontFamily", "fontSize", "fontWeight", "fontStyle", "fontVariant",
17897
+ "letterSpacing", "lineHeight", "textTransform", "wordSpacing", "tabSize",
17898
+ ] as (keyof CSSStyleDeclaration)[]
17899
+ ).forEach((prop) => {
17900
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17901
+ (mirror.style as any)[prop] = cs[prop];
17902
+ });
17903
+
17904
+ mirror.style.whiteSpace = el.tagName === "TEXTAREA" ? "pre-wrap" : "pre";
17905
+ mirror.style.wordWrap = el.tagName === "TEXTAREA" ? "break-word" : "normal";
17906
+ mirror.style.position = "absolute";
17907
+ mirror.style.visibility = "hidden";
17908
+ mirror.style.overflow = "hidden";
17909
+ mirror.style.top = "0";
17910
+ mirror.style.left = "0";
17911
+ mirror.style.width = el.offsetWidth + "px";
17912
+
17913
+ document.body.appendChild(mirror);
17914
+ mirror.appendChild(document.createTextNode(el.value.substring(0, position)));
17915
+
17916
+ const marker = document.createElement("span");
17917
+ marker.textContent = "\\u200b";
17918
+ mirror.appendChild(marker);
17919
+
17920
+ const markerRect = marker.getBoundingClientRect();
17921
+ const mirrorRect = mirror.getBoundingClientRect();
17922
+ document.body.removeChild(mirror);
17923
+
17924
+ const scrollTop = el instanceof HTMLTextAreaElement ? el.scrollTop : 0;
17925
+ return {
17926
+ top: markerRect.top - mirrorRect.top - scrollTop,
17927
+ left: markerRect.left - mirrorRect.left,
17928
+ };
17929
+ }
17930
+
17931
+ // Uses same visual classes as DropdownMenuContent + DropdownMenuItem.
17932
+ // Position is cursor-anchored via getCaretPixelPos.
17933
+ // No search bar \u2014 typing after {{ already filters via filterQuery.
17934
+ function VarPopup({
17935
+ variables,
17936
+ variableGroups,
17937
+ filterQuery = "",
17938
+ onSelect,
17939
+ onAddVariable,
17940
+ onEditVariable,
17941
+ style,
17942
+ }: {
17943
+ variables: string[];
17944
+ variableGroups?: VariableGroup[];
17945
+ filterQuery?: string;
17946
+ onSelect: (v: string) => void;
17947
+ onAddVariable?: () => void;
17948
+ onEditVariable?: (variable: string) => void;
17949
+ style?: React.CSSProperties;
17950
+ }) {
17951
+ const hasGroups = variableGroups && variableGroups.length > 0;
17952
+
17953
+ if (!hasGroups && variables.length === 0) return null;
17954
+
17955
+ // Flat mode \u2014 variables are already pre-filtered by VariableInput
17956
+ if (!hasGroups) {
17957
+ return (
17958
+ <div
17959
+ role="listbox"
17960
+ style={style}
17961
+ className="absolute z-[9999] min-w-[14rem] max-w-sm rounded-md border border-semantic-border-layout bg-semantic-bg-primary py-1 text-semantic-text-primary shadow-md"
17962
+ >
17963
+ {/* Add new variable */}
17964
+ {onAddVariable && (
17965
+ <button
17966
+ type="button"
17967
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
17968
+ className="flex w-full items-center gap-2 px-3 py-2 text-sm font-medium text-semantic-text-primary hover:bg-semantic-bg-ui transition-colors"
17969
+ >
17970
+ <Plus className="size-3.5 shrink-0" />
17971
+ Add new variable
17972
+ </button>
17973
+ )}
17974
+
17975
+ {/* Variable list */}
17976
+ <div className="max-h-48 overflow-y-auto p-1">
17977
+ {variables.map((v) => (
17978
+ <button
17979
+ key={v}
17980
+ type="button"
17981
+ role="option"
17982
+ aria-selected={false}
17983
+ onMouseDown={(e) => { e.preventDefault(); onSelect(v); }}
17984
+ className="relative flex w-full cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-semantic-bg-ui"
17985
+ >
17986
+ {v}
17987
+ </button>
17988
+ ))}
17989
+ {variables.length === 0 && (
17990
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
17991
+ )}
17992
+ </div>
17993
+ </div>
17994
+ );
17995
+ }
17996
+
17997
+ // Grouped mode \u2014 filter by the {{ trigger query
17998
+ const lowerQuery = filterQuery.toLowerCase();
17999
+ const filteredGroups = variableGroups.map((g) => ({
18000
+ ...g,
18001
+ items: g.items.filter((item) =>
18002
+ item.name.toLowerCase().includes(lowerQuery)
18003
+ ),
18004
+ })).filter((g) => g.items.length > 0);
18005
+
18006
+ return (
18007
+ <div
18008
+ role="listbox"
18009
+ style={style}
18010
+ className="absolute z-[9999] min-w-[14rem] max-w-sm rounded-md border border-semantic-border-layout bg-semantic-bg-primary py-1 text-semantic-text-primary shadow-md"
18011
+ >
18012
+ {/* Add new variable */}
18013
+ {onAddVariable && (
18014
+ <>
18015
+ <button
18016
+ type="button"
18017
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
18018
+ className="flex w-full items-center gap-2 px-3 py-2 text-sm font-medium text-semantic-text-primary hover:bg-semantic-bg-ui transition-colors"
18019
+ >
18020
+ <Plus className="size-3.5 shrink-0" />
18021
+ Add new variable
18022
+ </button>
18023
+ <div className="border-t border-semantic-border-layout" />
18024
+ </>
18025
+ )}
18026
+
18027
+ {/* Grouped variable list */}
18028
+ <div className="max-h-48 overflow-y-auto p-1">
18029
+ {filteredGroups.map((group) => (
18030
+ <div key={group.label}>
18031
+ <p className="m-0 px-2 pt-2 pb-1 text-sm font-medium text-semantic-text-muted">
18032
+ {group.label}
18033
+ </p>
18034
+ {group.items.map((item) => {
18035
+ const insertValue = item.value ?? \`{{\${item.name}}}\`;
18036
+ return (
18037
+ <div key={item.name} className="flex items-center rounded-sm transition-colors hover:bg-semantic-bg-ui">
18038
+ <button
18039
+ type="button"
18040
+ role="option"
18041
+ aria-selected={false}
18042
+ onMouseDown={(e) => { e.preventDefault(); onSelect(insertValue); }}
18043
+ className="relative flex flex-1 min-w-0 cursor-pointer select-none items-center px-2 py-1.5 text-sm outline-none"
18044
+ >
18045
+ {\`{{\${item.name}}}\`}
18046
+ </button>
18047
+ {item.editable && onEditVariable && (
18048
+ <button
18049
+ type="button"
18050
+ onMouseDown={(e) => { e.preventDefault(); onEditVariable(item.name); }}
18051
+ className="shrink-0 p-1.5 rounded text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
18052
+ aria-label={\`Edit \${item.name}\`}
18053
+ >
18054
+ <Pencil className="size-3.5" />
18055
+ </button>
18056
+ )}
18057
+ </div>
18058
+ );
18059
+ })}
18060
+ </div>
18061
+ ))}
18062
+ {filteredGroups.length === 0 && (
18063
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
18064
+ )}
18065
+ </div>
18066
+ </div>
18067
+ );
18068
+ }
18069
+
18070
+ // \u2500\u2500 VariableFormModal \u2014 create/edit a variable \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17354
18071
 
17355
- mirror.style.whiteSpace = el.tagName === "TEXTAREA" ? "pre-wrap" : "pre";
17356
- mirror.style.wordWrap = el.tagName === "TEXTAREA" ? "break-word" : "normal";
17357
- mirror.style.position = "absolute";
17358
- mirror.style.visibility = "hidden";
17359
- mirror.style.overflow = "hidden";
17360
- mirror.style.top = "0";
17361
- mirror.style.left = "0";
17362
- mirror.style.width = el.offsetWidth + "px";
18072
+ function VariableFormModal({
18073
+ open,
18074
+ onOpenChange,
18075
+ mode,
18076
+ initialData,
18077
+ onSave,
18078
+ }: {
18079
+ open: boolean;
18080
+ onOpenChange: (open: boolean) => void;
18081
+ mode: "create" | "edit";
18082
+ initialData?: VariableItem;
18083
+ onSave: (data: VariableFormData) => void;
18084
+ }) {
18085
+ const [name, setName] = React.useState("");
18086
+ const [description, setDescription] = React.useState("");
18087
+ const [required, setRequired] = React.useState(false);
18088
+ const [nameError, setNameError] = React.useState("");
17363
18089
 
17364
- document.body.appendChild(mirror);
17365
- mirror.appendChild(document.createTextNode(el.value.substring(0, position)));
18090
+ // Reset form when modal opens
18091
+ React.useEffect(() => {
18092
+ if (open) {
18093
+ setName(initialData?.name ?? "");
18094
+ setDescription(initialData?.description ?? "");
18095
+ setRequired(initialData?.required ?? false);
18096
+ setNameError("");
18097
+ }
18098
+ }, [open, initialData]);
17366
18099
 
17367
- const marker = document.createElement("span");
17368
- marker.textContent = "\\u200b";
17369
- mirror.appendChild(marker);
18100
+ const validateName = (v: string) => {
18101
+ if (!v.trim()) return "";
18102
+ if (!VARIABLE_NAME_REGEX.test(v)) {
18103
+ return "Variable name should start with alphabet; Cannot have special characters except underscore (_)";
18104
+ }
18105
+ return "";
18106
+ };
17370
18107
 
17371
- const markerRect = marker.getBoundingClientRect();
17372
- const mirrorRect = mirror.getBoundingClientRect();
17373
- document.body.removeChild(mirror);
18108
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
18109
+ const v = e.target.value;
18110
+ setName(v);
18111
+ setNameError(validateName(v));
18112
+ };
17374
18113
 
17375
- const scrollTop = el instanceof HTMLTextAreaElement ? el.scrollTop : 0;
17376
- return {
17377
- top: markerRect.top - mirrorRect.top - scrollTop,
17378
- left: markerRect.left - mirrorRect.left,
18114
+ const handleSave = () => {
18115
+ const error = validateName(name);
18116
+ if (error || !name.trim()) {
18117
+ setNameError(error || "Variable name is required");
18118
+ return;
18119
+ }
18120
+ onSave({ name: name.trim(), description: description.trim() || undefined, required });
17379
18121
  };
17380
- }
17381
18122
 
17382
- // Uses same visual classes as DropdownMenuContent + DropdownMenuItem.
17383
- // Position is cursor-anchored via getCaretPixelPos.
17384
- function VarPopup({
17385
- variables,
17386
- onSelect,
17387
- style,
17388
- }: {
17389
- variables: string[];
17390
- onSelect: (v: string) => void;
17391
- style?: React.CSSProperties;
17392
- }) {
17393
- if (variables.length === 0) return null;
17394
18123
  return (
17395
- <div
17396
- role="listbox"
17397
- style={style}
17398
- className="absolute z-[9999] min-w-[8rem] max-w-xs overflow-hidden rounded-md border border-semantic-border-layout bg-semantic-bg-primary p-1 text-semantic-text-primary shadow-md"
18124
+ <FormModal
18125
+ open={open}
18126
+ onOpenChange={onOpenChange}
18127
+ title={mode === "create" ? "Create new variable" : "Edit variable"}
18128
+ saveButtonText={mode === "create" ? "Save" : "Save Changes"}
18129
+ disableSave={!name.trim() || !!nameError}
18130
+ onSave={handleSave}
18131
+ size="default"
17399
18132
  >
17400
- {variables.map((v) => (
17401
- <button
17402
- key={v}
17403
- type="button"
17404
- role="option"
17405
- aria-selected={false}
17406
- onMouseDown={(e) => {
17407
- e.preventDefault(); // keep input focused so blur doesn't close popup first
17408
- onSelect(v);
17409
- }}
17410
- className="relative flex w-full cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-semantic-bg-ui focus:bg-semantic-bg-ui"
17411
- >
17412
- {v}
17413
- </button>
17414
- ))}
17415
- </div>
18133
+ <div className="flex flex-col gap-4">
18134
+ <div className="flex flex-col gap-1.5">
18135
+ <label className="text-sm font-medium text-semantic-text-muted">
18136
+ Variable name{" "}
18137
+ <span className="text-semantic-error-primary">*</span>
18138
+ </label>
18139
+ <div className="relative">
18140
+ <input
18141
+ type="text"
18142
+ value={name}
18143
+ onChange={handleNameChange}
18144
+ placeholder="e.g., customer_name"
18145
+ maxLength={VARIABLE_NAME_MAX}
18146
+ className={cn(inputCls, "pr-16")}
18147
+ />
18148
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18149
+ {name.length}/{VARIABLE_NAME_MAX}
18150
+ </span>
18151
+ </div>
18152
+ <span className={cn("text-sm", nameError ? "text-semantic-error-primary" : "text-semantic-text-muted")}>
18153
+ {nameError || "Variable name should start with alphabet; Cannot have special characters except underscore (_)"}
18154
+ </span>
18155
+ </div>
18156
+ <TextField
18157
+ label="Description (optional)"
18158
+ placeholder="What this variable represents"
18159
+ value={description}
18160
+ onChange={(e) => setDescription(e.target.value)}
18161
+ />
18162
+ <div className="flex flex-col gap-1.5">
18163
+ <span className="text-sm font-medium text-semantic-text-muted">Required</span>
18164
+ <div className="flex items-center gap-6">
18165
+ <label className="flex items-center gap-2 cursor-pointer">
18166
+ <input
18167
+ type="radio"
18168
+ name="variable-required"
18169
+ checked={required}
18170
+ onChange={() => setRequired(true)}
18171
+ className="size-4 accent-semantic-primary"
18172
+ />
18173
+ <span className="text-base text-semantic-text-primary">Yes</span>
18174
+ </label>
18175
+ <label className="flex items-center gap-2 cursor-pointer">
18176
+ <input
18177
+ type="radio"
18178
+ name="variable-required"
18179
+ checked={!required}
18180
+ onChange={() => setRequired(false)}
18181
+ className="size-4 accent-semantic-primary"
18182
+ />
18183
+ <span className="text-base text-semantic-text-primary">No</span>
18184
+ </label>
18185
+ </div>
18186
+ </div>
18187
+ </div>
18188
+ </FormModal>
17416
18189
  );
17417
18190
  }
17418
18191
 
17419
- // \u2500\u2500 VariableInput \u2014 input with {{ autocomplete \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18192
+ // \u2500\u2500 VariableInput \u2014 input with {{ autocomplete + badge display \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17420
18193
 
17421
18194
  function VariableInput({
17422
18195
  value,
17423
18196
  onChange,
17424
18197
  sessionVariables,
18198
+ variableGroups,
18199
+ onAddVariable,
18200
+ onEditVariable,
17425
18201
  placeholder,
17426
18202
  maxLength,
17427
18203
  className,
17428
18204
  inputRef: externalInputRef,
18205
+ disabled,
17429
18206
  ...inputProps
17430
18207
  }: {
17431
18208
  value: string;
17432
18209
  onChange: (v: string) => void;
17433
18210
  sessionVariables: string[];
18211
+ variableGroups?: VariableGroup[];
18212
+ onAddVariable?: () => void;
18213
+ onEditVariable?: (variable: string) => void;
17434
18214
  placeholder?: string;
17435
18215
  maxLength?: number;
17436
18216
  className?: string;
17437
18217
  inputRef?: React.RefObject<HTMLInputElement>;
18218
+ disabled?: boolean;
17438
18219
  [k: string]: unknown;
17439
18220
  }) {
17440
18221
  const internalRef = React.useRef<HTMLInputElement>(null);
17441
18222
  const inputRef = externalInputRef ?? internalRef;
18223
+ const displayRef = React.useRef<HTMLDivElement>(null);
17442
18224
  const [trigger, setTrigger] = React.useState<TriggerState | null>(null);
17443
18225
  const [popupStyle, setPopupStyle] = React.useState<React.CSSProperties | undefined>();
18226
+ const [isEditing, setIsEditing] = React.useState(false);
18227
+ const [isExpanded, setIsExpanded] = React.useState(false);
18228
+ const [isOverflowing, setIsOverflowing] = React.useState(false);
17444
18229
 
17445
18230
  const filtered = trigger
17446
18231
  ? sessionVariables.filter((v) => v.toLowerCase().includes(trigger.query))
17447
18232
  : [];
17448
18233
 
18234
+ // Parse value into text + variable segments
18235
+ const segments = React.useMemo(() => parseValueSegments(value), [value]);
18236
+ const hasVariables = segments.some((s) => s.type === "var");
18237
+ const showDisplay = !isEditing && value.length > 0 && hasVariables;
18238
+
18239
+ // Check overflow in display mode
18240
+ React.useEffect(() => {
18241
+ if (showDisplay && displayRef.current && !isExpanded) {
18242
+ const el = displayRef.current;
18243
+ setIsOverflowing(el.scrollWidth > el.clientWidth);
18244
+ } else {
18245
+ setIsOverflowing(false);
18246
+ }
18247
+ }, [showDisplay, value, isExpanded]);
18248
+
17449
18249
  const updatePopupPos = (el: HTMLInputElement, cursor: number) => {
17450
18250
  const caret = getCaretPixelPos(el, cursor);
17451
18251
  const lineHeight = parseFloat(window.getComputedStyle(el).lineHeight) || 20;
@@ -17474,13 +18274,15 @@ function VariableInput({
17474
18274
 
17475
18275
  return (
17476
18276
  <div className="relative w-full">
18277
+ {/* Input \u2014 always in DOM, hidden when display mode is active */}
17477
18278
  <input
17478
18279
  ref={inputRef}
17479
18280
  type="text"
17480
18281
  value={value}
17481
18282
  placeholder={placeholder}
17482
18283
  maxLength={maxLength}
17483
- className={className}
18284
+ disabled={disabled}
18285
+ className={cn(className, showDisplay && "opacity-0 pointer-events-none")}
17484
18286
  onChange={(e) => {
17485
18287
  onChange(e.target.value);
17486
18288
  const cursor = e.target.selectionStart ?? e.target.value.length;
@@ -17492,10 +18294,88 @@ function VariableInput({
17492
18294
  onKeyDown={(e) => {
17493
18295
  if (e.key === "Escape") clearTrigger();
17494
18296
  }}
17495
- onBlur={() => clearTrigger()}
18297
+ onFocus={() => setIsEditing(true)}
18298
+ onBlur={() => {
18299
+ clearTrigger();
18300
+ setIsEditing(false);
18301
+ setIsExpanded(false);
18302
+ }}
17496
18303
  {...inputProps}
17497
18304
  />
17498
- <VarPopup variables={filtered} onSelect={handleSelect} style={popupStyle} />
18305
+
18306
+ {/* Display mode \u2014 variable badges + text + overflow */}
18307
+ {showDisplay && (
18308
+ <div
18309
+ className={cn(
18310
+ "absolute cursor-text",
18311
+ !isExpanded && "inset-0 flex items-center",
18312
+ isExpanded && "inset-x-0 top-0 z-10",
18313
+ disabled && "opacity-50 cursor-not-allowed"
18314
+ )}
18315
+ onClick={() => {
18316
+ if (!disabled) inputRef.current?.focus();
18317
+ }}
18318
+ >
18319
+ <div
18320
+ ref={displayRef}
18321
+ className={cn(
18322
+ "flex items-center gap-1 px-2",
18323
+ !isExpanded && "flex-1 min-w-0 overflow-hidden",
18324
+ isExpanded && "flex-wrap bg-semantic-bg-primary border border-semantic-border-input rounded py-1.5 shadow-sm"
18325
+ )}
18326
+ >
18327
+ {segments.map((seg, i) =>
18328
+ seg.type === "text" ? (
18329
+ <span key={i} className="text-sm text-semantic-text-primary whitespace-pre shrink-0">{seg.content}</span>
18330
+ ) : (
18331
+ <span
18332
+ key={i}
18333
+ className="inline-flex items-center gap-1 shrink-0 rounded px-1.5 py-0.5 text-sm bg-semantic-info-surface text-semantic-text-primary"
18334
+ >
18335
+ {seg.name}
18336
+ {onEditVariable && (
18337
+ <button
18338
+ type="button"
18339
+ onMouseDown={(e) => {
18340
+ e.preventDefault();
18341
+ e.stopPropagation();
18342
+ onEditVariable(seg.name);
18343
+ }}
18344
+ className="p-0.5 text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
18345
+ >
18346
+ <Pencil className="size-3" />
18347
+ </button>
18348
+ )}
18349
+ </span>
18350
+ )
18351
+ )}
18352
+ </div>
18353
+ {isOverflowing && !isExpanded && (
18354
+ <button
18355
+ type="button"
18356
+ onMouseDown={(e) => {
18357
+ e.preventDefault();
18358
+ e.stopPropagation();
18359
+ setIsExpanded(true);
18360
+ }}
18361
+ className="shrink-0 px-1 text-sm font-medium text-semantic-text-muted hover:text-semantic-text-primary"
18362
+ >
18363
+ ...
18364
+ </button>
18365
+ )}
18366
+ </div>
18367
+ )}
18368
+
18369
+ {/* VarPopup */}
18370
+ <VarPopup
18371
+ variables={filtered}
18372
+ variableGroups={trigger ? variableGroups : undefined}
18373
+ filterQuery={trigger?.query ?? ""}
18374
+ onSelect={handleSelect}
18375
+ onAddVariable={onAddVariable}
18376
+ onEditVariable={onEditVariable}
18377
+ style={popupStyle}
18378
+ />
17499
18379
  </div>
17500
18380
  );
17501
18381
  }
@@ -17505,7 +18385,7 @@ const inputCls = cn(
17505
18385
  "w-full h-[42px] px-4 text-base rounded border",
17506
18386
  "border-semantic-border-input bg-semantic-bg-primary",
17507
18387
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17508
- "outline-none hover:border-semantic-border-input-focus",
18388
+ "outline-none",
17509
18389
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17510
18390
  "disabled:opacity-50 disabled:cursor-not-allowed"
17511
18391
  );
@@ -17514,7 +18394,7 @@ const textareaCls = cn(
17514
18394
  "w-full px-4 py-2.5 text-base rounded border resize-none",
17515
18395
  "border-semantic-border-input bg-semantic-bg-primary",
17516
18396
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17517
- "outline-none hover:border-semantic-border-input-focus",
18397
+ "outline-none",
17518
18398
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17519
18399
  "disabled:opacity-50 disabled:cursor-not-allowed"
17520
18400
  );
@@ -17532,6 +18412,9 @@ function KeyValueTable({
17532
18412
  keyRegex,
17533
18413
  keyRegexError,
17534
18414
  sessionVariables = [],
18415
+ variableGroups,
18416
+ onAddVariable,
18417
+ onEditVariable,
17535
18418
  disabled = false,
17536
18419
  }: {
17537
18420
  rows: KeyValuePair[];
@@ -17543,6 +18426,9 @@ function KeyValueTable({
17543
18426
  keyRegex?: RegExp;
17544
18427
  keyRegexError?: string;
17545
18428
  sessionVariables?: string[];
18429
+ variableGroups?: VariableGroup[];
18430
+ onAddVariable?: () => void;
18431
+ onEditVariable?: (variable: string) => void;
17546
18432
  disabled?: boolean;
17547
18433
  }) {
17548
18434
  const update = (id: string, patch: Partial<KeyValuePair>) => {
@@ -17574,14 +18460,14 @@ function KeyValueTable({
17574
18460
 
17575
18461
  return (
17576
18462
  <div className="flex flex-col gap-1.5">
17577
- <span className="text-xs text-semantic-text-muted">{label}</span>
17578
- <div className="border border-semantic-border-layout rounded overflow-hidden">
18463
+ <span className="text-sm text-semantic-text-muted">{label}</span>
18464
+ <div className="border border-semantic-border-layout rounded">
17579
18465
  {/* Column headers \u2014 desktop only; border-r on Key cell defines column boundary */}
17580
- <div className="hidden sm:flex bg-semantic-bg-ui border-b border-semantic-border-layout">
17581
- <div className="flex-1 min-w-0 px-3 py-2 text-xs font-semibold text-semantic-text-muted border-r border-semantic-border-layout">
18466
+ <div className="hidden sm:flex border-b border-semantic-border-layout rounded-t">
18467
+ <div className="flex-1 min-w-0 px-3 py-2 text-sm font-semibold text-semantic-text-muted border-r border-semantic-border-layout">
17582
18468
  Key
17583
18469
  </div>
17584
- <div className="flex-[2] min-w-0 px-3 py-2 text-xs font-semibold text-semantic-text-muted">
18470
+ <div className="flex-[2] min-w-0 px-3 py-2 text-sm font-semibold text-semantic-text-muted">
17585
18471
  Value
17586
18472
  </div>
17587
18473
  <div className="w-10 shrink-0" aria-hidden="true" />
@@ -17597,7 +18483,7 @@ function KeyValueTable({
17597
18483
  >
17598
18484
  {/* Key column \u2014 border-r on column (not input) so it aligns with header */}
17599
18485
  <div className="flex-1 flex flex-col min-w-0 sm:border-r sm:border-semantic-border-layout">
17600
- <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-[10px] font-semibold text-semantic-text-muted uppercase tracking-wide">
18486
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17601
18487
  Key
17602
18488
  </span>
17603
18489
  <input
@@ -17608,45 +18494,36 @@ function KeyValueTable({
17608
18494
  maxLength={keyMaxLength}
17609
18495
  disabled={disabled}
17610
18496
  className={cn(
17611
- "w-full px-3 py-2.5 text-base text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none focus:bg-semantic-bg-hover",
18497
+ "w-full px-3 py-2.5 text-base text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none",
17612
18498
  "disabled:opacity-50 disabled:cursor-not-allowed",
17613
- errors.key && "border-semantic-error-primary"
18499
+ errors.key && "text-semantic-error-primary"
17614
18500
  )}
17615
18501
  aria-invalid={Boolean(errors.key)}
17616
- aria-describedby={errors.key ? \`err-key-\${row.id}\` : undefined}
17617
18502
  />
17618
- {errors.key && (
17619
- <p id={\`err-key-\${row.id}\`} className="m-0 px-3 pt-0.5 text-xs text-semantic-error-primary">
17620
- {errors.key}
17621
- </p>
17622
- )}
17623
18503
  </div>
17624
18504
 
17625
18505
  {/* Value column \u2014 uses VariableInput for {{ autocomplete */}
17626
18506
  <div className="flex-[2] flex flex-col min-w-0">
17627
- <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-[10px] font-semibold text-semantic-text-muted uppercase tracking-wide">
18507
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17628
18508
  Value
17629
18509
  </span>
17630
18510
  <VariableInput
17631
18511
  value={row.value}
17632
18512
  onChange={(v) => update(row.id, { value: v })}
17633
18513
  sessionVariables={sessionVariables}
18514
+ variableGroups={variableGroups}
18515
+ onAddVariable={onAddVariable}
18516
+ onEditVariable={onEditVariable}
17634
18517
  placeholder="Type {{ to add variables"
17635
18518
  maxLength={valueMaxLength}
17636
18519
  disabled={disabled}
17637
18520
  className={cn(
17638
- "w-full px-3 py-2.5 text-base text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none focus:bg-semantic-bg-hover",
18521
+ "w-full px-3 py-2.5 text-base text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none",
17639
18522
  "disabled:opacity-50 disabled:cursor-not-allowed",
17640
- errors.value && "border-semantic-error-primary"
18523
+ errors.value && "text-semantic-error-primary"
17641
18524
  )}
17642
18525
  aria-invalid={Boolean(errors.value)}
17643
- aria-describedby={errors.value ? \`err-value-\${row.id}\` : undefined}
17644
18526
  />
17645
- {errors.value && (
17646
- <p id={\`err-value-\${row.id}\`} className="m-0 px-3 pt-0.5 text-xs text-semantic-error-primary">
17647
- {errors.value}
17648
- </p>
17649
- )}
17650
18527
  </div>
17651
18528
 
17652
18529
  {/* Action column \u2014 delete aligned with row (same as KeyValueRow / knowledge-base-card) */}
@@ -17673,7 +18550,7 @@ function KeyValueTable({
17673
18550
  onClick={add}
17674
18551
  disabled={disabled}
17675
18552
  className={cn(
17676
- "w-full flex items-center gap-2 px-3 py-2.5 text-sm text-semantic-text-muted hover:bg-semantic-bg-hover transition-colors",
18553
+ "w-full flex items-center gap-2 px-3 py-2.5 text-sm text-semantic-text-muted hover:bg-semantic-bg-ui transition-colors",
17677
18554
  disabled && "opacity-50 cursor-not-allowed"
17678
18555
  )}
17679
18556
  >
@@ -17681,15 +18558,35 @@ function KeyValueTable({
17681
18558
  <span>Add row</span>
17682
18559
  </button>
17683
18560
  </div>
18561
+
18562
+ {/* Collected row errors \u2014 shown below the table */}
18563
+ {(() => {
18564
+ const allErrors = rows
18565
+ .map((row) => {
18566
+ const errs = getErrors(row);
18567
+ const msgs: string[] = [];
18568
+ if (errs.key) msgs.push(errs.key);
18569
+ if (errs.value) msgs.push(errs.value);
18570
+ return msgs;
18571
+ })
18572
+ .flat();
18573
+ if (allErrors.length === 0) return null;
18574
+ // Deduplicate
18575
+ const unique = Array.from(new Set(allErrors));
18576
+ return (
18577
+ <div className="flex flex-col gap-0.5">
18578
+ {unique.map((msg) => (
18579
+ <p key={msg} className="m-0 text-sm text-semantic-error-primary">{msg}</p>
18580
+ ))}
18581
+ </div>
18582
+ );
18583
+ })()}
17684
18584
  </div>
17685
18585
  );
17686
18586
  }
17687
18587
 
17688
18588
  // \u2500\u2500 Modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17689
- export const CreateFunctionModal = React.forwardRef<
17690
- HTMLDivElement,
17691
- CreateFunctionModalProps
17692
- >(
18589
+ export const CreateFunctionModal = React.forwardRef(
17693
18590
  (
17694
18591
  {
17695
18592
  open,
@@ -17703,10 +18600,13 @@ export const CreateFunctionModal = React.forwardRef<
17703
18600
  initialStep = 1,
17704
18601
  initialTab = "header",
17705
18602
  sessionVariables = DEFAULT_SESSION_VARIABLES,
18603
+ variableGroups,
18604
+ onAddVariable,
18605
+ onEditVariable,
17706
18606
  disabled = false,
17707
18607
  className,
17708
- },
17709
- ref
18608
+ }: CreateFunctionModalProps,
18609
+ ref: React.Ref<HTMLDivElement>
17710
18610
  ) => {
17711
18611
  const [step, setStep] = React.useState<1 | 2>(initialStep);
17712
18612
 
@@ -17727,6 +18627,35 @@ export const CreateFunctionModal = React.forwardRef<
17727
18627
  const [urlError, setUrlError] = React.useState("");
17728
18628
  const [bodyError, setBodyError] = React.useState("");
17729
18629
 
18630
+ // Variable modal state
18631
+ const [varModalOpen, setVarModalOpen] = React.useState(false);
18632
+ const [varModalMode, setVarModalMode] = React.useState<"create" | "edit">("create");
18633
+ const [varModalInitialData, setVarModalInitialData] = React.useState<VariableItem | undefined>();
18634
+
18635
+ const handleAddVariableClick = () => {
18636
+ setVarModalMode("create");
18637
+ setVarModalInitialData(undefined);
18638
+ setVarModalOpen(true);
18639
+ };
18640
+
18641
+ const handleEditVariableClick = (variableName: string) => {
18642
+ const variable = variableGroups
18643
+ ?.flatMap((g) => g.items)
18644
+ .find((item) => item.name === variableName);
18645
+ setVarModalMode("edit");
18646
+ setVarModalInitialData(variable ?? { name: variableName, editable: true });
18647
+ setVarModalOpen(true);
18648
+ };
18649
+
18650
+ const handleVariableSave = (data: VariableFormData) => {
18651
+ if (varModalMode === "create") {
18652
+ onAddVariable?.(data);
18653
+ } else {
18654
+ onEditVariable?.(varModalInitialData?.name ?? "", data);
18655
+ }
18656
+ setVarModalOpen(false);
18657
+ };
18658
+
17730
18659
  // Variable trigger state for URL and body
17731
18660
  const urlInputRef = React.useRef<HTMLInputElement>(null);
17732
18661
  const bodyTextareaRef = React.useRef<HTMLTextAreaElement>(null);
@@ -17821,14 +18750,7 @@ export const CreateFunctionModal = React.forwardRef<
17821
18750
  onOpenChange(false);
17822
18751
  }, [reset, onOpenChange]);
17823
18752
 
17824
- const supportsBody = METHODS_WITH_BODY.includes(method);
17825
-
17826
- // When switching to a method without body, reset to header tab if body was active
17827
- React.useEffect(() => {
17828
- if (!supportsBody && activeTab === "body") {
17829
- setActiveTab("header");
17830
- }
17831
- }, [supportsBody, activeTab]);
18753
+ // Body tab is always visible regardless of HTTP method
17832
18754
 
17833
18755
  const validateName = (value: string) => {
17834
18756
  if (value.trim() && !FUNCTION_NAME_REGEX.test(value.trim())) {
@@ -17963,11 +18885,10 @@ export const CreateFunctionModal = React.forwardRef<
17963
18885
  body: "Body",
17964
18886
  };
17965
18887
 
17966
- const visibleTabs: FunctionTabType[] = supportsBody
17967
- ? ["header", "queryParams", "body"]
17968
- : ["header", "queryParams"];
18888
+ const visibleTabs: FunctionTabType[] = ["header", "queryParams", "body"];
17969
18889
 
17970
18890
  return (
18891
+ <>
17971
18892
  <Dialog open={open} onOpenChange={onOpenChange}>
17972
18893
  <DialogContent
17973
18894
  ref={ref}
@@ -17975,7 +18896,7 @@ export const CreateFunctionModal = React.forwardRef<
17975
18896
  hideCloseButton
17976
18897
  className={cn(
17977
18898
  "flex flex-col gap-0 p-0 w-[calc(100vw-2rem)] sm:w-full",
17978
- "max-h-[calc(100svh-2rem)] overflow-hidden",
18899
+ "max-h-[calc(100vh-2rem)] overflow-hidden",
17979
18900
  className
17980
18901
  )}
17981
18902
  >
@@ -17995,7 +18916,7 @@ export const CreateFunctionModal = React.forwardRef<
17995
18916
  </div>
17996
18917
 
17997
18918
  {/* \u2500\u2500 Scrollable body \u2500\u2500 */}
17998
- <div className="flex-1 overflow-y-auto min-h-0 px-4 py-5 sm:px-6">
18919
+ <div className="flex-1 overflow-y-auto min-h-0 overscroll-contain px-4 py-5 sm:px-6">
17999
18920
  {/* \u2500 Step 1 \u2500 */}
18000
18921
  {step === 1 && (
18001
18922
  <div className="flex flex-col gap-5">
@@ -18022,44 +18943,33 @@ export const CreateFunctionModal = React.forwardRef<
18022
18943
  placeholder="Enter name of the function"
18023
18944
  className={cn(inputCls, "pr-16")}
18024
18945
  />
18025
- <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs italic text-semantic-text-muted pointer-events-none">
18946
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18026
18947
  {name.length}/{FUNCTION_NAME_MAX}
18027
18948
  </span>
18028
18949
  </div>
18029
18950
  {nameError && (
18030
- <p className="m-0 text-xs text-semantic-error-primary">{nameError}</p>
18951
+ <p className="m-0 text-sm text-semantic-error-primary">{nameError}</p>
18031
18952
  )}
18032
18953
  </div>
18033
18954
 
18034
- <div className="flex flex-col gap-1.5">
18035
- <label
18036
- htmlFor="fn-prompt"
18037
- className="text-sm font-semibold text-semantic-text-primary"
18038
- >
18039
- Prompt{" "}
18040
- <span className="text-semantic-error-primary">*</span>
18041
- </label>
18042
- <div className="relative">
18043
- <textarea
18044
- id="fn-prompt"
18045
- value={prompt}
18046
- maxLength={promptMaxLength}
18047
- disabled={disabled}
18048
- onChange={(e) => setPrompt(e.target.value)}
18049
- placeholder="Enter the description of the function"
18050
- rows={5}
18051
- className={cn(textareaCls, "pb-7")}
18052
- />
18053
- <span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted pointer-events-none">
18054
- {prompt.length}/{promptMaxLength}
18055
- </span>
18056
- </div>
18057
- {prompt.length > 0 && prompt.trim().length < promptMinLength && (
18058
- <p className="m-0 text-xs text-semantic-error-primary">
18059
- Minimum {promptMinLength} characters required
18060
- </p>
18061
- )}
18062
- </div>
18955
+ <Textarea
18956
+ id="fn-prompt"
18957
+ label="Prompt"
18958
+ required
18959
+ value={prompt}
18960
+ maxLength={promptMaxLength}
18961
+ showCount
18962
+ disabled={disabled}
18963
+ onChange={(e) => setPrompt(e.target.value)}
18964
+ placeholder="Enter the description of the function"
18965
+ rows={5}
18966
+ labelClassName="font-semibold text-semantic-text-primary"
18967
+ error={
18968
+ prompt.length > 0 && prompt.trim().length < promptMinLength
18969
+ ? \`Minimum \${promptMinLength} characters required\`
18970
+ : undefined
18971
+ }
18972
+ />
18063
18973
  </div>
18064
18974
  )}
18065
18975
 
@@ -18068,13 +18978,12 @@ export const CreateFunctionModal = React.forwardRef<
18068
18978
  <div className="flex flex-col gap-5">
18069
18979
  {/* API URL \u2014 always a single combined row */}
18070
18980
  <div className="flex flex-col gap-1.5">
18071
- <span className="text-xs text-semantic-text-muted tracking-[0.048px]">
18981
+ <span className="text-sm text-semantic-text-muted tracking-[0.048px]">
18072
18982
  API URL
18073
18983
  </span>
18074
18984
  <div
18075
18985
  className={cn(
18076
18986
  "flex h-[42px] rounded border border-semantic-border-input overflow-visible bg-semantic-bg-primary",
18077
- "hover:border-semantic-border-input-focus",
18078
18987
  "focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
18079
18988
  "transition-shadow"
18080
18989
  )}
@@ -18135,11 +19044,19 @@ export const CreateFunctionModal = React.forwardRef<
18135
19044
  disabled && "opacity-50 cursor-not-allowed"
18136
19045
  )}
18137
19046
  />
18138
- <VarPopup variables={filteredUrlVars} onSelect={handleUrlVarSelect} style={urlPopupStyle} />
19047
+ <VarPopup
19048
+ variables={filteredUrlVars}
19049
+ variableGroups={urlTrigger ? variableGroups : undefined}
19050
+ filterQuery={urlTrigger?.query ?? ""}
19051
+ onSelect={handleUrlVarSelect}
19052
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
19053
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
19054
+ style={urlPopupStyle}
19055
+ />
18139
19056
  </div>
18140
19057
  </div>
18141
19058
  {urlError && (
18142
- <p className="m-0 text-xs text-semantic-error-primary">{urlError}</p>
19059
+ <p className="m-0 text-sm text-semantic-error-primary">{urlError}</p>
18143
19060
  )}
18144
19061
  </div>
18145
19062
 
@@ -18179,6 +19096,9 @@ export const CreateFunctionModal = React.forwardRef<
18179
19096
  keyRegex={HEADER_KEY_REGEX}
18180
19097
  keyRegexError="Invalid header key. Use only alphanumeric and !#$%&'*+-.^_\`|~ characters."
18181
19098
  sessionVariables={sessionVariables}
19099
+ variableGroups={variableGroups}
19100
+ onAddVariable={handleAddVariableClick}
19101
+ onEditVariable={handleEditVariableClick}
18182
19102
  disabled={disabled}
18183
19103
  />
18184
19104
  )}
@@ -18198,12 +19118,15 @@ export const CreateFunctionModal = React.forwardRef<
18198
19118
  };
18199
19119
  }}
18200
19120
  sessionVariables={sessionVariables}
19121
+ variableGroups={variableGroups}
19122
+ onAddVariable={handleAddVariableClick}
19123
+ onEditVariable={handleEditVariableClick}
18201
19124
  disabled={disabled}
18202
19125
  />
18203
19126
  )}
18204
19127
  {activeTab === "body" && (
18205
19128
  <div className="flex flex-col gap-1.5">
18206
- <span className="text-xs text-semantic-text-muted">
19129
+ <span className="text-sm text-semantic-text-muted">
18207
19130
  Body
18208
19131
  </span>
18209
19132
  <div className={cn("relative")}>
@@ -18233,13 +19156,21 @@ export const CreateFunctionModal = React.forwardRef<
18233
19156
  rows={6}
18234
19157
  className={cn(textareaCls, "pb-7")}
18235
19158
  />
18236
- <span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted pointer-events-none">
19159
+ <span className="absolute bottom-2 right-3 text-sm text-semantic-text-muted pointer-events-none">
18237
19160
  {body.length}/{BODY_MAX}
18238
19161
  </span>
18239
- <VarPopup variables={filteredBodyVars} onSelect={handleBodyVarSelect} style={bodyPopupStyle} />
19162
+ <VarPopup
19163
+ variables={filteredBodyVars}
19164
+ variableGroups={bodyTrigger ? variableGroups : undefined}
19165
+ filterQuery={bodyTrigger?.query ?? ""}
19166
+ onSelect={handleBodyVarSelect}
19167
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
19168
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
19169
+ style={bodyPopupStyle}
19170
+ />
18240
19171
  </div>
18241
19172
  {bodyError && (
18242
- <p className="m-0 text-xs text-semantic-error-primary">{bodyError}</p>
19173
+ <p className="m-0 text-sm text-semantic-error-primary">{bodyError}</p>
18243
19174
  )}
18244
19175
  </div>
18245
19176
  )}
@@ -18248,7 +19179,7 @@ export const CreateFunctionModal = React.forwardRef<
18248
19179
  {/* Test Your API */}
18249
19180
  <div className="flex flex-col gap-4">
18250
19181
  <div className="flex flex-col gap-1.5">
18251
- <span className="text-xs font-semibold text-semantic-text-muted tracking-[0.048px]">
19182
+ <span className="text-sm font-semibold text-semantic-text-muted tracking-[0.048px]">
18252
19183
  Test Your API
18253
19184
  </span>
18254
19185
  <div className="border-t border-semantic-border-layout" />
@@ -18257,12 +19188,12 @@ export const CreateFunctionModal = React.forwardRef<
18257
19188
  {/* Variable test values \u2014 shown when URL/body/params contain {{variables}} */}
18258
19189
  {testableVars.length > 0 && (
18259
19190
  <div className="flex flex-col gap-2">
18260
- <span className="text-xs text-semantic-text-muted">
19191
+ <span className="text-sm text-semantic-text-muted">
18261
19192
  Variable values for testing
18262
19193
  </span>
18263
19194
  {testableVars.map((variable) => (
18264
19195
  <div key={variable} className="flex items-center gap-3">
18265
- <span className="text-xs text-semantic-text-muted font-mono shrink-0 min-w-[120px]">
19196
+ <span className="text-sm text-semantic-text-muted font-mono shrink-0 min-w-[120px]">
18266
19197
  {variable}
18267
19198
  </span>
18268
19199
  <input
@@ -18292,7 +19223,7 @@ export const CreateFunctionModal = React.forwardRef<
18292
19223
  </button>
18293
19224
 
18294
19225
  <div className="flex flex-col gap-1.5">
18295
- <span className="text-xs text-semantic-text-muted">
19226
+ <span className="text-sm text-semantic-text-muted">
18296
19227
  Response from API
18297
19228
  </span>
18298
19229
  <textarea
@@ -18350,6 +19281,15 @@ export const CreateFunctionModal = React.forwardRef<
18350
19281
  </div>
18351
19282
  </DialogContent>
18352
19283
  </Dialog>
19284
+
19285
+ <VariableFormModal
19286
+ open={varModalOpen}
19287
+ onOpenChange={setVarModalOpen}
19288
+ mode={varModalMode}
19289
+ initialData={varModalInitialData}
19290
+ onSave={handleVariableSave}
19291
+ />
19292
+ </>
18353
19293
  );
18354
19294
  }
18355
19295
  );
@@ -18561,7 +19501,7 @@ const DEFAULT_LANGUAGE_OPTIONS: LanguageOption[] = [
18561
19501
 
18562
19502
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18563
19503
 
18564
- const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
19504
+ const BotIdentityCard = React.forwardRef(
18565
19505
  (
18566
19506
  {
18567
19507
  data,
@@ -18575,8 +19515,8 @@ const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
18575
19515
  playingVoice,
18576
19516
  disabled,
18577
19517
  className,
18578
- },
18579
- ref
19518
+ }: BotIdentityCardProps,
19519
+ ref: React.Ref<HTMLDivElement>
18580
19520
  ) => {
18581
19521
  return (
18582
19522
  <div
@@ -18922,7 +19862,7 @@ function SectionCard({
18922
19862
 
18923
19863
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18924
19864
 
18925
- const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
19865
+ const BotBehaviorCard = React.forwardRef(
18926
19866
  (
18927
19867
  {
18928
19868
  data,
@@ -18932,8 +19872,8 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
18932
19872
  maxLength = 5000,
18933
19873
  disabled,
18934
19874
  className,
18935
- },
18936
- ref
19875
+ }: BotBehaviorCardProps,
19876
+ ref: React.Ref<HTMLDivElement>
18937
19877
  ) => {
18938
19878
  const prompt = data.systemPrompt ?? "";
18939
19879
  const MAX = maxLength;
@@ -19160,7 +20100,7 @@ const STATUS_CONFIG: Record<KnowledgeFileStatus, { label: string; variant: Badge
19160
20100
 
19161
20101
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19162
20102
 
19163
- const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProps>(
20103
+ const KnowledgeBaseCard = React.forwardRef(
19164
20104
  (
19165
20105
  {
19166
20106
  files,
@@ -19172,8 +20112,8 @@ const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProp
19172
20112
  downloadDisabled,
19173
20113
  deleteDisabled,
19174
20114
  className,
19175
- },
19176
- ref
20115
+ }: KnowledgeBaseCardProps,
20116
+ ref: React.Ref<HTMLDivElement>
19177
20117
  ) => {
19178
20118
  return (
19179
20119
  <div
@@ -19325,8 +20265,8 @@ export interface FunctionsCardProps {
19325
20265
 
19326
20266
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19327
20267
 
19328
- const FunctionsCard = React.forwardRef<HTMLDivElement, FunctionsCardProps>(
19329
- ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }, ref) => {
20268
+ const FunctionsCard = React.forwardRef(
20269
+ ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }: FunctionsCardProps, ref: React.Ref<HTMLDivElement>) => {
19330
20270
  return (
19331
20271
  <div
19332
20272
  ref={ref}
@@ -19512,8 +20452,8 @@ function Field({
19512
20452
 
19513
20453
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19514
20454
 
19515
- const FrustrationHandoverCard = React.forwardRef<HTMLDivElement, FrustrationHandoverCardProps>(
19516
- ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }, ref) => {
20455
+ const FrustrationHandoverCard = React.forwardRef(
20456
+ ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }: FrustrationHandoverCardProps, ref: React.Ref<HTMLDivElement>) => {
19517
20457
  return (
19518
20458
  <div
19519
20459
  ref={ref}
@@ -19686,7 +20626,7 @@ function NumberSpinner({
19686
20626
 
19687
20627
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19688
20628
 
19689
- const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCardProps>(
20629
+ const AdvancedSettingsCard = React.forwardRef(
19690
20630
  (
19691
20631
  {
19692
20632
  data,
@@ -19697,8 +20637,8 @@ const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCa
19697
20637
  callEndThresholdMax = 10,
19698
20638
  disabled,
19699
20639
  className,
19700
- },
19701
- ref
20640
+ }: AdvancedSettingsCardProps,
20641
+ ref: React.Ref<HTMLDivElement>
19702
20642
  ) => {
19703
20643
  return (
19704
20644
  <div
@@ -19864,10 +20804,7 @@ function PromptField({
19864
20804
 
19865
20805
  // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19866
20806
 
19867
- const FallbackPromptsCard = React.forwardRef<
19868
- HTMLDivElement,
19869
- FallbackPromptsCardProps
19870
- >(
20807
+ const FallbackPromptsCard = React.forwardRef(
19871
20808
  (
19872
20809
  {
19873
20810
  data,
@@ -19878,8 +20815,8 @@ const FallbackPromptsCard = React.forwardRef<
19878
20815
  disabled,
19879
20816
  defaultOpen = false,
19880
20817
  className,
19881
- },
19882
- ref
20818
+ }: FallbackPromptsCardProps,
20819
+ ref: React.Ref<HTMLDivElement>
19883
20820
  ) => {
19884
20821
  return (
19885
20822
  <div
@@ -19958,6 +20895,35 @@ export interface KeyValuePair {
19958
20895
  value: string;
19959
20896
  }
19960
20897
 
20898
+ /** A single variable shown in the {{ autocomplete popup */
20899
+ export interface VariableItem {
20900
+ /** Display name (e.g., "Order_id") */
20901
+ name: string;
20902
+ /** Value inserted into the input. Defaults to \`{{name}}\` if omitted */
20903
+ value?: string;
20904
+ /** When true, an edit icon is shown next to this variable */
20905
+ editable?: boolean;
20906
+ /** Description of what this variable represents */
20907
+ description?: string;
20908
+ /** Whether this variable is required */
20909
+ required?: boolean;
20910
+ }
20911
+
20912
+ /** Data shape for creating or editing a variable */
20913
+ export interface VariableFormData {
20914
+ name: string;
20915
+ description?: string;
20916
+ required?: boolean;
20917
+ }
20918
+
20919
+ /** A labelled group of variables in the autocomplete popup */
20920
+ export interface VariableGroup {
20921
+ /** Group header text (e.g., "Function variables", "Session variables") */
20922
+ label: string;
20923
+ /** Variables in this group */
20924
+ items: VariableItem[];
20925
+ }
20926
+
19961
20927
  export interface FunctionItem {
19962
20928
  id: string;
19963
20929
  name: string;
@@ -20008,6 +20974,12 @@ export interface CreateFunctionModalProps {
20008
20974
  initialTab?: FunctionTabType;
20009
20975
  /** Session variables available for {{ autocomplete in URL, body, header values, and query param values */
20010
20976
  sessionVariables?: string[];
20977
+ /** Grouped variables shown in the {{ autocomplete popup (overrides flat list display when provided) */
20978
+ variableGroups?: VariableGroup[];
20979
+ /** Called when user saves a new variable from the autocomplete popup */
20980
+ onAddVariable?: (data: VariableFormData) => void;
20981
+ /** Called when user edits a variable from the autocomplete popup */
20982
+ onEditVariable?: (originalName: string, data: VariableFormData) => void;
20011
20983
  /** When true, all form fields are disabled (view mode) but Next is enabled so user can browse steps */
20012
20984
  disabled?: boolean;
20013
20985
  className?: string;
@@ -20168,6 +21140,9 @@ export type {
20168
21140
  HttpMethod,
20169
21141
  FunctionTabType,
20170
21142
  SelectOption,
21143
+ VariableItem,
21144
+ VariableGroup,
21145
+ VariableFormData,
20171
21146
  } from "./types";
20172
21147
  `, prefix)
20173
21148
  }
@@ -20237,7 +21212,7 @@ function formatCurrency(amount: number, symbol: string = "\u20B9"): string {
20237
21212
  * />
20238
21213
  * \`\`\`
20239
21214
  */
20240
- export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
21215
+ export const WalletTopup = React.forwardRef(
20241
21216
  (
20242
21217
  {
20243
21218
  title = "Instant wallet top-up",
@@ -20284,8 +21259,8 @@ export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
20284
21259
  open,
20285
21260
  onOpenChange,
20286
21261
  className,
20287
- },
20288
- ref
21262
+ }: WalletTopupProps,
21263
+ ref: React.Ref<HTMLDivElement>
20289
21264
  ) => {
20290
21265
  const isOpenControlled = open !== undefined;
20291
21266
 
@@ -22287,22 +23262,99 @@ async function sync(options) {
22287
23262
  }
22288
23263
  let selectedToAdd = toAdd;
22289
23264
  let selectedToUpdate = toUpdate;
23265
+ const CUSTOM_GROUPS = {
23266
+ "attachment-preview": "Chat",
23267
+ "audio-media": "Chat",
23268
+ "carousel-media": "Chat",
23269
+ "chat-bubble": "Chat",
23270
+ "chat-composer": "Chat",
23271
+ "contact-list-item": "Chat",
23272
+ "date-divider": "Chat",
23273
+ "doc-media": "Chat",
23274
+ "image-media": "Chat",
23275
+ "reply-quote": "Chat",
23276
+ "system-message": "Chat",
23277
+ "unread-separator": "Chat",
23278
+ "video-media": "Chat",
23279
+ "event-selector": "Webhook",
23280
+ "key-value-input": "Webhook",
23281
+ "api-feature-card": "Webhook",
23282
+ "endpoint-details": "Webhook",
23283
+ "alert-configuration": "Webhook",
23284
+ "auto-pay-setup": "Plan & Payment",
23285
+ "bank-details": "Plan & Payment",
23286
+ "date-range-modal": "Plan & Payment",
23287
+ "payment-option-card": "Plan & Payment",
23288
+ "plan-upgrade-modal": "Plan & Payment",
23289
+ "plan-upgrade-summary-modal": "Plan & Payment",
23290
+ "payment-summary": "Plan & Payment",
23291
+ "let-us-drive-card": "Plan & Payment",
23292
+ "power-up-card": "Plan & Payment",
23293
+ "pricing-card": "Plan & Payment",
23294
+ "pricing-page": "Plan & Payment",
23295
+ "pricing-toggle": "Plan & Payment",
23296
+ "talk-to-us-modal": "Plan & Payment",
23297
+ "wallet-topup": "Plan & Payment",
23298
+ "file-upload-modal": "Plan & Payment",
23299
+ "plan-detail-modal": "Plan & Payment",
23300
+ "bots": "AI Bot",
23301
+ "ivr-bot": "AI Bot"
23302
+ };
22290
23303
  if (!options.yes && toAdd.length > 0) {
22291
- const { selected } = await prompts3({
22292
- type: "multiselect",
22293
- name: "selected",
22294
- message: "Select new components to add",
22295
- choices: toAdd.map((c) => {
22296
- const comp = registry[c];
22297
- const fileCount = comp.isMultiFile ? ` (${comp.files.length} files)` : "";
22298
- return { title: `${c}${fileCount}`, value: c, selected: true };
22299
- })
22300
- });
22301
- if (!selected) {
22302
- console.log(chalk5.yellow("\n Sync cancelled.\n"));
22303
- process.exit(0);
23304
+ const uiToAdd = toAdd.filter((c) => !CUSTOM_GROUPS[c]);
23305
+ const customToAdd = toAdd.filter((c) => !!CUSTOM_GROUPS[c]);
23306
+ const picked = [];
23307
+ if (uiToAdd.length > 0) {
23308
+ console.log(chalk5.cyan.bold(" \u2500\u2500 Components \u2500\u2500\n"));
23309
+ const { selected } = await prompts3({
23310
+ type: "multiselect",
23311
+ name: "selected",
23312
+ message: "Select new components to add",
23313
+ choices: uiToAdd.map((c) => ({
23314
+ title: c,
23315
+ value: c,
23316
+ selected: false
23317
+ }))
23318
+ });
23319
+ if (!selected) {
23320
+ console.log(chalk5.yellow("\n Sync cancelled.\n"));
23321
+ process.exit(0);
23322
+ }
23323
+ picked.push(...selected);
23324
+ }
23325
+ if (customToAdd.length > 0) {
23326
+ const grouped = /* @__PURE__ */ new Map();
23327
+ for (const c of customToAdd) {
23328
+ const group = CUSTOM_GROUPS[c] || "Other";
23329
+ if (!grouped.has(group)) grouped.set(group, []);
23330
+ grouped.get(group).push(c);
23331
+ }
23332
+ const sortedGroups = [...grouped.keys()].sort();
23333
+ console.log(chalk5.cyan.bold("\n \u2500\u2500 Custom \u2500\u2500\n"));
23334
+ const { selected } = await prompts3({
23335
+ type: "multiselect",
23336
+ name: "selected",
23337
+ message: "Select custom component folders to add",
23338
+ choices: sortedGroups.map((group) => {
23339
+ const components = grouped.get(group);
23340
+ const count = components.length;
23341
+ return {
23342
+ title: group,
23343
+ value: group,
23344
+ selected: false,
23345
+ description: `${count} component${count === 1 ? "" : "s"}`
23346
+ };
23347
+ })
23348
+ });
23349
+ if (!selected) {
23350
+ console.log(chalk5.yellow("\n Sync cancelled.\n"));
23351
+ process.exit(0);
23352
+ }
23353
+ for (const group of selected) {
23354
+ picked.push(...grouped.get(group));
23355
+ }
22304
23356
  }
22305
- selectedToAdd = selected;
23357
+ selectedToAdd = picked;
22306
23358
  }
22307
23359
  if (!options.yes && toUpdate.length > 0) {
22308
23360
  const { selected } = await prompts3({