myoperator-ui 0.0.218-beta.1 → 0.0.218

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 +1815 -777
  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] =
@@ -3451,7 +4011,6 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
3451
4011
  // Generate unique IDs for accessibility
3452
4012
  const generatedId = React.useId();
3453
4013
  const selectId = id || generatedId;
3454
- const listboxId = \`\${selectId}-listbox\`;
3455
4014
  const helperId = \`\${selectId}-helper\`;
3456
4015
  const errorId = \`\${selectId}-error\`;
3457
4016
 
@@ -3565,7 +4124,6 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
3565
4124
  role="combobox"
3566
4125
  aria-expanded={isOpen}
3567
4126
  aria-haspopup="listbox"
3568
- aria-controls={listboxId}
3569
4127
  aria-invalid={!!error}
3570
4128
  aria-describedby={ariaDescribedBy}
3571
4129
  disabled={disabled || loading}
@@ -3645,7 +4203,6 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
3645
4203
  {/* Dropdown */}
3646
4204
  {isOpen && (
3647
4205
  <div
3648
- id={listboxId}
3649
4206
  className={cn(
3650
4207
  "absolute z-50 mt-1 w-full rounded bg-semantic-bg-primary border border-semantic-border-layout shadow-md",
3651
4208
  "top-full"
@@ -3815,7 +4372,7 @@ export interface CreatableSelectProps
3815
4372
  maxLength?: number
3816
4373
  }
3817
4374
 
3818
- const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
4375
+ const CreatableSelect = React.forwardRef(
3819
4376
  (
3820
4377
  {
3821
4378
  className,
@@ -3828,8 +4385,8 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
3828
4385
  disabled = false,
3829
4386
  maxLength,
3830
4387
  ...props
3831
- },
3832
- ref
4388
+ }: CreatableSelectProps,
4389
+ ref: React.Ref<HTMLDivElement>
3833
4390
  ) => {
3834
4391
  const [open, setOpen] = React.useState(false)
3835
4392
  const [search, setSearch] = React.useState("")
@@ -3837,7 +4394,6 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
3837
4394
  const containerRef = React.useRef<HTMLDivElement>(null)
3838
4395
  const inputRef = React.useRef<HTMLInputElement>(null)
3839
4396
  const listRef = React.useRef<HTMLDivElement>(null)
3840
- const listboxId = React.useId()
3841
4397
 
3842
4398
  // Merge forwarded ref with internal ref
3843
4399
  React.useImperativeHandle(ref, () => containerRef.current!)
@@ -3980,7 +4536,6 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
3980
4536
  placeholder={selectedLabel || placeholder}
3981
4537
  aria-expanded="true"
3982
4538
  aria-haspopup="listbox"
3983
- aria-controls={listboxId}
3984
4539
  role="combobox"
3985
4540
  aria-autocomplete="list"
3986
4541
  />
@@ -3997,7 +4552,6 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
3997
4552
  )}
3998
4553
  aria-haspopup="listbox"
3999
4554
  aria-expanded="false"
4000
- aria-controls={listboxId}
4001
4555
  >
4002
4556
  <span
4003
4557
  className={cn(
@@ -4027,7 +4581,6 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
4027
4581
  {/* Options list */}
4028
4582
  <div
4029
4583
  ref={listRef}
4030
- id={listboxId}
4031
4584
  role="listbox"
4032
4585
  className="max-h-60 overflow-y-auto p-1"
4033
4586
  >
@@ -4164,10 +4717,7 @@ export interface CreatableMultiSelectProps
4164
4717
  maxLengthPerItem?: number
4165
4718
  }
4166
4719
 
4167
- const CreatableMultiSelect = React.forwardRef<
4168
- HTMLDivElement,
4169
- CreatableMultiSelectProps
4170
- >(
4720
+ const CreatableMultiSelect = React.forwardRef(
4171
4721
  (
4172
4722
  {
4173
4723
  className,
@@ -4182,14 +4732,13 @@ const CreatableMultiSelect = React.forwardRef<
4182
4732
  maxItems,
4183
4733
  maxLengthPerItem,
4184
4734
  ...props
4185
- },
4186
- ref
4735
+ }: CreatableMultiSelectProps,
4736
+ ref: React.Ref<HTMLDivElement>
4187
4737
  ) => {
4188
4738
  const [isOpen, setIsOpen] = React.useState(false)
4189
4739
  const [inputValue, setInputValue] = React.useState("")
4190
4740
  const containerRef = React.useRef<HTMLDivElement>(null)
4191
4741
  const inputRef = React.useRef<HTMLInputElement>(null)
4192
- const listboxId = React.useId()
4193
4742
 
4194
4743
  React.useImperativeHandle(ref, () => containerRef.current!)
4195
4744
 
@@ -4327,7 +4876,6 @@ const CreatableMultiSelect = React.forwardRef<
4327
4876
  className="flex-1 min-w-[100px] text-base bg-transparent outline-none text-semantic-text-primary placeholder:text-semantic-text-muted"
4328
4877
  role="combobox"
4329
4878
  aria-expanded={isOpen}
4330
- aria-controls={listboxId}
4331
4879
  aria-haspopup="listbox"
4332
4880
  />
4333
4881
 
@@ -4341,7 +4889,7 @@ const CreatableMultiSelect = React.forwardRef<
4341
4889
 
4342
4890
  {/* Dropdown panel */}
4343
4891
  {isOpen && (
4344
- <div id={listboxId} role="listbox" className="absolute z-[9999] top-full mt-1 w-full bg-semantic-bg-primary border border-semantic-border-layout rounded shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-200">
4892
+ <div className="absolute z-[9999] top-full mt-1 w-full bg-semantic-bg-primary border border-semantic-border-layout rounded shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-200">
4345
4893
  {/* Creatable hint \u2014 Enter key */}
4346
4894
  <div className="flex items-center justify-between px-4 py-2 border-b border-semantic-border-layout">
4347
4895
  <span className="text-sm text-semantic-text-muted">
@@ -4480,8 +5028,8 @@ export interface TableProps
4480
5028
  wrapContent?: boolean;
4481
5029
  }
4482
5030
 
4483
- const Table = React.forwardRef<HTMLTableElement, TableProps>(
4484
- ({ className, size, withoutBorder, wrapContent, ...props }, ref) => (
5031
+ const Table = React.forwardRef(
5032
+ ({ className, size, withoutBorder, wrapContent, ...props }: TableProps, ref: React.Ref<HTMLTableElement>) => (
4485
5033
  <div
4486
5034
  className={cn(
4487
5035
  "relative w-full overflow-auto",
@@ -4502,10 +5050,7 @@ const Table = React.forwardRef<HTMLTableElement, TableProps>(
4502
5050
  );
4503
5051
  Table.displayName = "Table";
4504
5052
 
4505
- const TableHeader = React.forwardRef<
4506
- HTMLTableSectionElement,
4507
- React.HTMLAttributes<HTMLTableSectionElement>
4508
- >(({ className, ...props }, ref) => (
5053
+ const TableHeader = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>, ref: React.Ref<HTMLTableSectionElement>) => (
4509
5054
  <thead
4510
5055
  ref={ref}
4511
5056
  className={cn("bg-[var(--color-neutral-100)] [&_tr]:border-b", className)}
@@ -4524,8 +5069,8 @@ export interface TableBodyProps
4524
5069
  loadingColumns?: number;
4525
5070
  }
4526
5071
 
4527
- const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
4528
- ({ className, isLoading, loadingRows = 5, loadingColumns = 5, children, ...props }, ref) => (
5072
+ const TableBody = React.forwardRef(
5073
+ ({ className, isLoading, loadingRows = 5, loadingColumns = 5, children, ...props }: TableBodyProps, ref: React.Ref<HTMLTableSectionElement>) => (
4529
5074
  <tbody
4530
5075
  ref={ref}
4531
5076
  className={cn("[&_tr:last-child]:border-0", className)}
@@ -4541,10 +5086,7 @@ const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
4541
5086
  );
4542
5087
  TableBody.displayName = "TableBody";
4543
5088
 
4544
- const TableFooter = React.forwardRef<
4545
- HTMLTableSectionElement,
4546
- React.HTMLAttributes<HTMLTableSectionElement>
4547
- >(({ className, ...props }, ref) => (
5089
+ const TableFooter = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>, ref: React.Ref<HTMLTableSectionElement>) => (
4548
5090
  <tfoot
4549
5091
  ref={ref}
4550
5092
  className={cn(
@@ -4561,8 +5103,8 @@ export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement>
4561
5103
  highlighted?: boolean;
4562
5104
  }
4563
5105
 
4564
- const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
4565
- ({ className, highlighted, ...props }, ref) => (
5106
+ const TableRow = React.forwardRef(
5107
+ ({ className, highlighted, ...props }: TableRowProps, ref: React.Ref<HTMLTableRowElement>) => (
4566
5108
  <tr
4567
5109
  ref={ref}
4568
5110
  className={cn(
@@ -4587,10 +5129,10 @@ export interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElem
4587
5129
  infoTooltip?: string;
4588
5130
  }
4589
5131
 
4590
- const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
5132
+ const TableHead = React.forwardRef(
4591
5133
  (
4592
- { className, sticky, sortDirection, infoTooltip, children, ...props },
4593
- ref
5134
+ { className, sticky, sortDirection, infoTooltip, children, ...props }: TableHeadProps,
5135
+ ref: React.Ref<HTMLTableCellElement>
4594
5136
  ) => (
4595
5137
  <th
4596
5138
  ref={ref}
@@ -4628,8 +5170,8 @@ export interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElem
4628
5170
  sticky?: boolean;
4629
5171
  }
4630
5172
 
4631
- const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
4632
- ({ className, sticky, ...props }, ref) => (
5173
+ const TableCell = React.forwardRef(
5174
+ ({ className, sticky, ...props }: TableCellProps, ref: React.Ref<HTMLTableCellElement>) => (
4633
5175
  <td
4634
5176
  ref={ref}
4635
5177
  className={cn(
@@ -4643,10 +5185,7 @@ const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
4643
5185
  );
4644
5186
  TableCell.displayName = "TableCell";
4645
5187
 
4646
- const TableCaption = React.forwardRef<
4647
- HTMLTableCaptionElement,
4648
- React.HTMLAttributes<HTMLTableCaptionElement>
4649
- >(({ className, ...props }, ref) => (
5188
+ const TableCaption = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableCaptionElement>, ref: React.Ref<HTMLTableCaptionElement>) => (
4650
5189
  <caption
4651
5190
  ref={ref}
4652
5191
  className={cn("mt-4 text-sm text-semantic-text-muted", className)}
@@ -4735,8 +5274,8 @@ export interface TableToggleProps extends Omit<SwitchProps, "size"> {
4735
5274
  size?: "sm" | "default";
4736
5275
  }
4737
5276
 
4738
- const TableToggle = React.forwardRef<HTMLButtonElement, TableToggleProps>(
4739
- ({ size = "sm", ...props }, ref) => (
5277
+ const TableToggle = React.forwardRef(
5278
+ ({ size = "sm", ...props }: TableToggleProps, ref: React.Ref<HTMLButtonElement>) => (
4740
5279
  <Switch ref={ref} size={size} {...props} />
4741
5280
  )
4742
5281
  );
@@ -4801,10 +5340,7 @@ export interface TabsListProps
4801
5340
  fullWidth?: boolean
4802
5341
  }
4803
5342
 
4804
- const TabsList = React.forwardRef<
4805
- React.ComponentRef<typeof TabsPrimitive.List>,
4806
- TabsListProps
4807
- >(({ className, fullWidth, ...props }, ref) => (
5343
+ const TabsList = React.forwardRef(({ className, fullWidth, ...props }: TabsListProps, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.List>>) => (
4808
5344
  <TabsPrimitive.List
4809
5345
  ref={ref}
4810
5346
  className={cn(
@@ -4817,10 +5353,7 @@ const TabsList = React.forwardRef<
4817
5353
  ))
4818
5354
  TabsList.displayName = TabsPrimitive.List.displayName
4819
5355
 
4820
- const TabsTrigger = React.forwardRef<
4821
- React.ComponentRef<typeof TabsPrimitive.Trigger>,
4822
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
4823
- >(({ className, ...props }, ref) => (
5356
+ const TabsTrigger = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.Trigger>>) => (
4824
5357
  <TabsPrimitive.Trigger
4825
5358
  ref={ref}
4826
5359
  className={cn(
@@ -4835,10 +5368,7 @@ const TabsTrigger = React.forwardRef<
4835
5368
  ))
4836
5369
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
4837
5370
 
4838
- const TabsContent = React.forwardRef<
4839
- React.ComponentRef<typeof TabsPrimitive.Content>,
4840
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
4841
- >(({ className, ...props }, ref) => (
5371
+ const TabsContent = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.Content>>) => (
4842
5372
  <TabsPrimitive.Content
4843
5373
  ref={ref}
4844
5374
  className={cn(
@@ -4885,10 +5415,7 @@ const DialogPortal = DialogPrimitive.Portal;
4885
5415
 
4886
5416
  const DialogClose = DialogPrimitive.Close;
4887
5417
 
4888
- const DialogOverlay = React.forwardRef<
4889
- React.ElementRef<typeof DialogPrimitive.Overlay>,
4890
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
4891
- >(({ className, ...props }, ref) => (
5418
+ const DialogOverlay = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>) => (
4892
5419
  <DialogPrimitive.Overlay
4893
5420
  ref={ref}
4894
5421
  className={cn(
@@ -4946,10 +5473,7 @@ const hasDialogDescription = (children: React.ReactNode): boolean => {
4946
5473
  return found;
4947
5474
  };
4948
5475
 
4949
- const DialogContent = React.forwardRef<
4950
- React.ElementRef<typeof DialogPrimitive.Content>,
4951
- DialogContentProps
4952
- >(({ className, children, size, hideCloseButton = false, ...props }, ref) => {
5476
+ const DialogContent = React.forwardRef(({ className, children, size, hideCloseButton = false, ...props }: DialogContentProps, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Content>>) => {
4953
5477
  const hasDescription = hasDialogDescription(children);
4954
5478
 
4955
5479
  return (
@@ -5007,10 +5531,7 @@ const DialogFooter = ({
5007
5531
  );
5008
5532
  DialogFooter.displayName = "DialogFooter";
5009
5533
 
5010
- const DialogTitle = React.forwardRef<
5011
- React.ElementRef<typeof DialogPrimitive.Title>,
5012
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
5013
- >(({ className, ...props }, ref) => (
5534
+ const DialogTitle = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Title>>) => (
5014
5535
  <DialogPrimitive.Title
5015
5536
  ref={ref}
5016
5537
  className={cn(
@@ -5022,10 +5543,7 @@ const DialogTitle = React.forwardRef<
5022
5543
  ));
5023
5544
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5024
5545
 
5025
- const DialogDescription = React.forwardRef<
5026
- React.ElementRef<typeof DialogPrimitive.Description>,
5027
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
5028
- >(({ className, ...props }, ref) => (
5546
+ const DialogDescription = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Description>>) => (
5029
5547
  <DialogPrimitive.Description
5030
5548
  ref={ref}
5031
5549
  className={cn("text-sm text-muted-foreground", className)}
@@ -5073,10 +5591,7 @@ import { cn } from "../../lib/utils";
5073
5591
 
5074
5592
  const DropdownMenu = DropdownMenuPrimitive.Root;
5075
5593
 
5076
- const DropdownMenuTrigger = React.forwardRef<
5077
- React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
5078
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
5079
- >(({ className, ...props }, ref) => (
5594
+ const DropdownMenuTrigger = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Trigger>>) => (
5080
5595
  <DropdownMenuPrimitive.Trigger
5081
5596
  ref={ref}
5082
5597
  className={cn("focus-visible:outline-none focus-visible:ring-0", className)}
@@ -5093,12 +5608,9 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
5093
5608
 
5094
5609
  const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
5095
5610
 
5096
- const DropdownMenuSubTrigger = React.forwardRef<
5097
- React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
5098
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
5611
+ const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
5099
5612
  inset?: boolean;
5100
- }
5101
- >(({ className, inset, children, ...props }, ref) => (
5613
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>>) => (
5102
5614
  <DropdownMenuPrimitive.SubTrigger
5103
5615
  ref={ref}
5104
5616
  className={cn(
@@ -5115,10 +5627,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
5115
5627
  DropdownMenuSubTrigger.displayName =
5116
5628
  DropdownMenuPrimitive.SubTrigger.displayName;
5117
5629
 
5118
- const DropdownMenuSubContent = React.forwardRef<
5119
- React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
5120
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
5121
- >(({ className, ...props }, ref) => (
5630
+ const DropdownMenuSubContent = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.SubContent>>) => (
5122
5631
  <DropdownMenuPrimitive.SubContent
5123
5632
  ref={ref}
5124
5633
  className={cn(
@@ -5131,10 +5640,7 @@ const DropdownMenuSubContent = React.forwardRef<
5131
5640
  DropdownMenuSubContent.displayName =
5132
5641
  DropdownMenuPrimitive.SubContent.displayName;
5133
5642
 
5134
- const DropdownMenuContent = React.forwardRef<
5135
- React.ElementRef<typeof DropdownMenuPrimitive.Content>,
5136
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
5137
- >(({ className, sideOffset = 4, ...props }, ref) => (
5643
+ const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Content>>) => (
5138
5644
  <DropdownMenuPrimitive.Portal>
5139
5645
  <DropdownMenuPrimitive.Content
5140
5646
  ref={ref}
@@ -5150,20 +5656,17 @@ const DropdownMenuContent = React.forwardRef<
5150
5656
  ));
5151
5657
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
5152
5658
 
5153
- const DropdownMenuItem = React.forwardRef<
5154
- React.ElementRef<typeof DropdownMenuPrimitive.Item>,
5155
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
5659
+ const DropdownMenuItem = React.forwardRef(({ className, inset, children, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
5156
5660
  inset?: boolean;
5157
5661
  /** Secondary text displayed below children */
5158
5662
  description?: string;
5159
5663
  /** Content displayed at the right edge of the item */
5160
5664
  suffix?: React.ReactNode;
5161
- }
5162
- >(({ className, inset, children, description, suffix, ...props }, ref) => (
5665
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Item>>) => (
5163
5666
  <DropdownMenuPrimitive.Item
5164
5667
  ref={ref}
5165
5668
  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",
5669
+ "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
5670
  inset && "pl-8",
5168
5671
  className
5169
5672
  )}
@@ -5184,15 +5687,12 @@ const DropdownMenuItem = React.forwardRef<
5184
5687
  ));
5185
5688
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
5186
5689
 
5187
- const DropdownMenuCheckboxItem = React.forwardRef<
5188
- React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
5189
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
5690
+ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
5190
5691
  /** Secondary text displayed below children */
5191
5692
  description?: string;
5192
5693
  /** Content displayed at the right edge of the item */
5193
5694
  suffix?: React.ReactNode;
5194
- }
5195
- >(({ className, children, checked, description, suffix, ...props }, ref) => (
5695
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>>) => (
5196
5696
  <DropdownMenuPrimitive.CheckboxItem
5197
5697
  ref={ref}
5198
5698
  className={cn(
@@ -5223,15 +5723,12 @@ const DropdownMenuCheckboxItem = React.forwardRef<
5223
5723
  DropdownMenuCheckboxItem.displayName =
5224
5724
  DropdownMenuPrimitive.CheckboxItem.displayName;
5225
5725
 
5226
- const DropdownMenuRadioItem = React.forwardRef<
5227
- React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
5228
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
5726
+ const DropdownMenuRadioItem = React.forwardRef(({ className, children, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
5229
5727
  /** Secondary text displayed below children */
5230
5728
  description?: string;
5231
5729
  /** Content displayed at the right edge of the item */
5232
5730
  suffix?: React.ReactNode;
5233
- }
5234
- >(({ className, children, description, suffix, ...props }, ref) => (
5731
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>>) => (
5235
5732
  <DropdownMenuPrimitive.RadioItem
5236
5733
  ref={ref}
5237
5734
  className={cn(
@@ -5260,12 +5757,9 @@ const DropdownMenuRadioItem = React.forwardRef<
5260
5757
  ));
5261
5758
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
5262
5759
 
5263
- const DropdownMenuLabel = React.forwardRef<
5264
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
5265
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
5760
+ const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
5266
5761
  inset?: boolean;
5267
- }
5268
- >(({ className, inset, ...props }, ref) => (
5762
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Label>>) => (
5269
5763
  <DropdownMenuPrimitive.Label
5270
5764
  ref={ref}
5271
5765
  className={cn(
@@ -5278,10 +5772,7 @@ const DropdownMenuLabel = React.forwardRef<
5278
5772
  ));
5279
5773
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
5280
5774
 
5281
- const DropdownMenuSeparator = React.forwardRef<
5282
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
5283
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
5284
- >(({ className, ...props }, ref) => (
5775
+ const DropdownMenuSeparator = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Separator>>) => (
5285
5776
  <DropdownMenuPrimitive.Separator
5286
5777
  ref={ref}
5287
5778
  className={cn("-mx-1 my-1 h-px bg-semantic-border-layout", className)}
@@ -5348,10 +5839,7 @@ const Tooltip = TooltipPrimitive.Root;
5348
5839
 
5349
5840
  const TooltipTrigger = TooltipPrimitive.Trigger;
5350
5841
 
5351
- const TooltipContent = React.forwardRef<
5352
- React.ElementRef<typeof TooltipPrimitive.Content>,
5353
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
5354
- >(({ className, sideOffset = 4, ...props }, ref) => (
5842
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>, ref: React.Ref<React.ElementRef<typeof TooltipPrimitive.Content>>) => (
5355
5843
  <TooltipPrimitive.Portal>
5356
5844
  <TooltipPrimitive.Content
5357
5845
  ref={ref}
@@ -5366,10 +5854,7 @@ const TooltipContent = React.forwardRef<
5366
5854
  ));
5367
5855
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
5368
5856
 
5369
- const TooltipArrow = React.forwardRef<
5370
- React.ElementRef<typeof TooltipPrimitive.Arrow>,
5371
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
5372
- >(({ className, ...props }, ref) => (
5857
+ const TooltipArrow = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>, ref: React.Ref<React.ElementRef<typeof TooltipPrimitive.Arrow>>) => (
5373
5858
  <TooltipPrimitive.Arrow
5374
5859
  ref={ref}
5375
5860
  className={cn("fill-semantic-primary", className)}
@@ -5473,10 +5958,7 @@ export interface DeleteConfirmationModalProps {
5473
5958
  * />
5474
5959
  * \`\`\`
5475
5960
  */
5476
- const DeleteConfirmationModal = React.forwardRef<
5477
- HTMLDivElement,
5478
- DeleteConfirmationModalProps
5479
- >(
5961
+ const DeleteConfirmationModal = React.forwardRef(
5480
5962
  (
5481
5963
  {
5482
5964
  open,
@@ -5492,8 +5974,8 @@ const DeleteConfirmationModal = React.forwardRef<
5492
5974
  cancelButtonText = "Cancel",
5493
5975
  trigger,
5494
5976
  className,
5495
- },
5496
- ref
5977
+ }: DeleteConfirmationModalProps,
5978
+ ref: React.Ref<HTMLDivElement>
5497
5979
  ) => {
5498
5980
  const [inputValue, setInputValue] = React.useState("");
5499
5981
  const isConfirmEnabled = inputValue === confirmText;
@@ -5661,10 +6143,7 @@ export interface ConfirmationModalProps {
5661
6143
  * />
5662
6144
  * \`\`\`
5663
6145
  */
5664
- const ConfirmationModal = React.forwardRef<
5665
- HTMLDivElement,
5666
- ConfirmationModalProps
5667
- >(
6146
+ const ConfirmationModal = React.forwardRef(
5668
6147
  (
5669
6148
  {
5670
6149
  open,
@@ -5679,8 +6158,8 @@ const ConfirmationModal = React.forwardRef<
5679
6158
  cancelButtonText = "Cancel",
5680
6159
  trigger,
5681
6160
  className,
5682
- },
5683
- ref
6161
+ }: ConfirmationModalProps,
6162
+ ref: React.Ref<HTMLDivElement>
5684
6163
  ) => {
5685
6164
  const handleConfirm = () => {
5686
6165
  onConfirm?.();
@@ -5812,7 +6291,7 @@ export interface FormModalProps {
5812
6291
  * </FormModal>
5813
6292
  * \`\`\`
5814
6293
  */
5815
- const FormModal = React.forwardRef<HTMLDivElement, FormModalProps>(
6294
+ const FormModal = React.forwardRef(
5816
6295
  (
5817
6296
  {
5818
6297
  open,
@@ -5828,8 +6307,8 @@ const FormModal = React.forwardRef<HTMLDivElement, FormModalProps>(
5828
6307
  disableSave = false,
5829
6308
  className,
5830
6309
  size = "sm",
5831
- },
5832
- ref
6310
+ }: FormModalProps,
6311
+ ref: React.Ref<HTMLDivElement>
5833
6312
  ) => {
5834
6313
  const handleSave = () => {
5835
6314
  onSave?.();
@@ -5944,8 +6423,8 @@ export interface TagProps
5944
6423
  label?: string;
5945
6424
  }
5946
6425
 
5947
- const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
5948
- ({ className, variant, size, label, children, ...props }, ref) => {
6426
+ const Tag = React.forwardRef(
6427
+ ({ className, variant, size, label, children, ...props }: TagProps, ref: React.Ref<HTMLSpanElement>) => {
5949
6428
  return (
5950
6429
  <span
5951
6430
  className={cn(tagVariants({ variant, size, className }))}
@@ -5953,7 +6432,7 @@ const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
5953
6432
  {...props}
5954
6433
  >
5955
6434
  {label && <span className="font-semibold mr-1">{label}</span>}
5956
- <span className="font-normal">{children}</span>
6435
+ <span className="font-normal inline-flex items-center gap-1">{children}</span>
5957
6436
  </span>
5958
6437
  );
5959
6438
  }
@@ -6141,7 +6620,7 @@ export interface AlertProps
6141
6620
  defaultOpen?: boolean;
6142
6621
  }
6143
6622
 
6144
- const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
6623
+ const Alert = React.forwardRef(
6145
6624
  (
6146
6625
  {
6147
6626
  className,
@@ -6156,8 +6635,8 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
6156
6635
  defaultOpen = true,
6157
6636
  children,
6158
6637
  ...props
6159
- },
6160
- ref
6638
+ }: AlertProps,
6639
+ ref: React.Ref<HTMLDivElement>
6161
6640
  ) => {
6162
6641
  const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
6163
6642
  const isControlled = controlledOpen !== undefined;
@@ -6229,27 +6708,19 @@ Alert.displayName = "Alert";
6229
6708
  /**
6230
6709
  * Alert title component for the heading text.
6231
6710
  */
6232
- const AlertTitle = React.forwardRef<
6233
- HTMLHeadingElement,
6234
- React.HTMLAttributes<HTMLHeadingElement>
6235
- >(({ className, children, ...props }, ref) => (
6711
+ const AlertTitle = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>, ref: React.Ref<HTMLHeadingElement>) => (
6236
6712
  <h5
6237
6713
  ref={ref}
6238
6714
  className={cn("font-semibold leading-tight tracking-tight", className)}
6239
6715
  {...props}
6240
- >
6241
- {children}
6242
- </h5>
6716
+ />
6243
6717
  ));
6244
6718
  AlertTitle.displayName = "AlertTitle";
6245
6719
 
6246
6720
  /**
6247
6721
  * Alert description component for the body text.
6248
6722
  */
6249
- const AlertDescription = React.forwardRef<
6250
- HTMLParagraphElement,
6251
- React.HTMLAttributes<HTMLParagraphElement>
6252
- >(({ className, ...props }, ref) => (
6723
+ const AlertDescription = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>, ref: React.Ref<HTMLParagraphElement>) => (
6253
6724
  <p ref={ref} className={cn("m-0 mt-1 text-sm", className)} {...props} />
6254
6725
  ));
6255
6726
  AlertDescription.displayName = "AlertDescription";
@@ -6283,10 +6754,7 @@ import { cn } from "../../lib/utils";
6283
6754
 
6284
6755
  const ToastProvider = ToastPrimitives.Provider;
6285
6756
 
6286
- const ToastViewport = React.forwardRef<
6287
- React.ElementRef<typeof ToastPrimitives.Viewport>,
6288
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
6289
- >(({ className, ...props }, ref) => (
6757
+ const ToastViewport = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Viewport>>) => (
6290
6758
  <ToastPrimitives.Viewport
6291
6759
  ref={ref}
6292
6760
  className={cn(
@@ -6320,11 +6788,8 @@ const toastVariants = cva(
6320
6788
  }
6321
6789
  );
6322
6790
 
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) => {
6791
+ const Toast = React.forwardRef(({ className, variant, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
6792
+ VariantProps<typeof toastVariants>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Root>>) => {
6328
6793
  return (
6329
6794
  <ToastPrimitives.Root
6330
6795
  ref={ref}
@@ -6335,10 +6800,7 @@ const Toast = React.forwardRef<
6335
6800
  });
6336
6801
  Toast.displayName = ToastPrimitives.Root.displayName;
6337
6802
 
6338
- const ToastAction = React.forwardRef<
6339
- React.ElementRef<typeof ToastPrimitives.Action>,
6340
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
6341
- >(({ className, ...props }, ref) => (
6803
+ const ToastAction = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Action>>) => (
6342
6804
  <ToastPrimitives.Action
6343
6805
  ref={ref}
6344
6806
  className={cn(
@@ -6354,10 +6816,7 @@ const ToastAction = React.forwardRef<
6354
6816
  ));
6355
6817
  ToastAction.displayName = ToastPrimitives.Action.displayName;
6356
6818
 
6357
- const ToastClose = React.forwardRef<
6358
- React.ElementRef<typeof ToastPrimitives.Close>,
6359
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
6360
- >(({ className, ...props }, ref) => (
6819
+ const ToastClose = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Close>>) => (
6361
6820
  <ToastPrimitives.Close
6362
6821
  ref={ref}
6363
6822
  className={cn(
@@ -6372,10 +6831,7 @@ const ToastClose = React.forwardRef<
6372
6831
  ));
6373
6832
  ToastClose.displayName = ToastPrimitives.Close.displayName;
6374
6833
 
6375
- const ToastTitle = React.forwardRef<
6376
- React.ElementRef<typeof ToastPrimitives.Title>,
6377
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
6378
- >(({ className, ...props }, ref) => (
6834
+ const ToastTitle = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Title>>) => (
6379
6835
  <ToastPrimitives.Title
6380
6836
  ref={ref}
6381
6837
  className={cn("text-sm font-semibold tracking-[0.014px]", className)}
@@ -6384,10 +6840,7 @@ const ToastTitle = React.forwardRef<
6384
6840
  ));
6385
6841
  ToastTitle.displayName = ToastPrimitives.Title.displayName;
6386
6842
 
6387
- const ToastDescription = React.forwardRef<
6388
- React.ElementRef<typeof ToastPrimitives.Description>,
6389
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
6390
- >(({ className, ...props }, ref) => (
6843
+ const ToastDescription = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Description>>) => (
6391
6844
  <ToastPrimitives.Description
6392
6845
  ref={ref}
6393
6846
  className={cn("text-xs tracking-[0.048px]", className)}
@@ -6836,7 +7289,7 @@ export interface SpinnerProps
6836
7289
  "aria-label"?: string;
6837
7290
  }
6838
7291
 
6839
- const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
7292
+ const Spinner = React.forwardRef(
6840
7293
  (
6841
7294
  {
6842
7295
  className,
@@ -6844,8 +7297,8 @@ const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
6844
7297
  variant,
6845
7298
  "aria-label": ariaLabel = "Loading",
6846
7299
  ...props
6847
- },
6848
- ref
7300
+ }: SpinnerProps,
7301
+ ref: React.Ref<HTMLDivElement>
6849
7302
  ) => {
6850
7303
  const strokeWidth = strokeWidths[size || "default"] ?? 3;
6851
7304
  const radius = 10;
@@ -6965,8 +7418,8 @@ export interface SkeletonProps
6965
7418
  height?: number | string;
6966
7419
  }
6967
7420
 
6968
- const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
6969
- ({ className, variant, shape, width, height, style, ...props }, ref) => {
7421
+ const Skeleton = React.forwardRef(
7422
+ ({ className, variant, shape, width, height, style, ...props }: SkeletonProps, ref: React.Ref<HTMLDivElement>) => {
6970
7423
  const dimensionStyle: React.CSSProperties = {
6971
7424
  ...style,
6972
7425
  ...(width !== undefined
@@ -7209,7 +7662,7 @@ export interface AccordionProps
7209
7662
  onValueChange?: (value: string[]) => void;
7210
7663
  }
7211
7664
 
7212
- const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
7665
+ const Accordion = React.forwardRef(
7213
7666
  (
7214
7667
  {
7215
7668
  className,
@@ -7220,8 +7673,8 @@ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
7220
7673
  onValueChange,
7221
7674
  children,
7222
7675
  ...props
7223
- },
7224
- ref
7676
+ }: AccordionProps,
7677
+ ref: React.Ref<HTMLDivElement>
7225
7678
  ) => {
7226
7679
  const [internalValue, setInternalValue] =
7227
7680
  React.useState<string[]>(defaultValue);
@@ -7277,8 +7730,8 @@ export interface AccordionItemProps
7277
7730
  disabled?: boolean;
7278
7731
  }
7279
7732
 
7280
- const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
7281
- ({ className, value, disabled, children, ...props }, ref) => {
7733
+ const AccordionItem = React.forwardRef(
7734
+ ({ className, value, disabled, children, ...props }: AccordionItemProps, ref: React.Ref<HTMLDivElement>) => {
7282
7735
  const { value: openValues, variant } = useAccordionContext();
7283
7736
  const isOpen = openValues.includes(value);
7284
7737
 
@@ -7318,10 +7771,7 @@ export interface AccordionTriggerProps
7318
7771
  showChevron?: boolean;
7319
7772
  }
7320
7773
 
7321
- const AccordionTrigger = React.forwardRef<
7322
- HTMLButtonElement,
7323
- AccordionTriggerProps
7324
- >(({ className, showChevron = true, children, ...props }, ref) => {
7774
+ const AccordionTrigger = React.forwardRef(({ className, showChevron = true, children, ...props }: AccordionTriggerProps, ref: React.Ref<HTMLButtonElement>) => {
7325
7775
  const {
7326
7776
  type,
7327
7777
  value: openValues,
@@ -7380,10 +7830,7 @@ export interface AccordionContentProps
7380
7830
  React.HTMLAttributes<HTMLDivElement>,
7381
7831
  VariantProps<typeof accordionContentVariants> {}
7382
7832
 
7383
- const AccordionContent = React.forwardRef<
7384
- HTMLDivElement,
7385
- AccordionContentProps
7386
- >(({ className, children, ...props }, ref) => {
7833
+ const AccordionContent = React.forwardRef(({ className, children, ...props }: AccordionContentProps, ref: React.Ref<HTMLDivElement>) => {
7387
7834
  const { variant } = useAccordionContext();
7388
7835
  const { isOpen } = useAccordionItemContext();
7389
7836
  const contentRef = React.useRef<HTMLDivElement>(null);
@@ -7515,7 +7962,7 @@ export interface PageHeaderProps
7515
7962
  mobileOverflowLimit?: number;
7516
7963
  }
7517
7964
 
7518
- const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
7965
+ const PageHeader = React.forwardRef(
7519
7966
  (
7520
7967
  {
7521
7968
  className,
@@ -7531,8 +7978,8 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
7531
7978
  layout = "responsive",
7532
7979
  mobileOverflowLimit = 2,
7533
7980
  ...props
7534
- },
7535
- ref
7981
+ }: PageHeaderProps,
7982
+ ref: React.Ref<HTMLDivElement>
7536
7983
  ) => {
7537
7984
  // State for overflow expansion (moved to top level)
7538
7985
  const [isOverflowExpanded, setIsOverflowExpanded] = React.useState(false);
@@ -7820,7 +8267,7 @@ export interface PanelProps
7820
8267
  * </Panel>
7821
8268
  * \`\`\`
7822
8269
  */
7823
- const Panel = React.forwardRef<HTMLElement, PanelProps>(
8270
+ const Panel = React.forwardRef(
7824
8271
  (
7825
8272
  {
7826
8273
  open = true,
@@ -7834,8 +8281,8 @@ const Panel = React.forwardRef<HTMLElement, PanelProps>(
7834
8281
  "aria-label": ariaLabel,
7835
8282
  onKeyDown,
7836
8283
  ...props
7837
- },
7838
- ref
8284
+ }: PanelProps,
8285
+ ref: React.Ref<HTMLElement>
7839
8286
  ) => {
7840
8287
  const resolvedSize = size ?? "default";
7841
8288
  const widthClass = panelWidths[resolvedSize];
@@ -8279,10 +8726,7 @@ import type { EventSelectorProps, EventCategory, EventGroup } from "./types";
8279
8726
  * />
8280
8727
  * \`\`\`
8281
8728
  */
8282
- export const EventSelector = React.forwardRef<
8283
- HTMLDivElement,
8284
- EventSelectorProps
8285
- >(
8729
+ export const EventSelector = React.forwardRef(
8286
8730
  (
8287
8731
  {
8288
8732
  events,
@@ -8297,8 +8741,8 @@ export const EventSelector = React.forwardRef<
8297
8741
  renderEmptyGroup,
8298
8742
  className,
8299
8743
  ...props
8300
- },
8301
- ref
8744
+ }: EventSelectorProps,
8745
+ ref: React.Ref<HTMLDivElement>
8302
8746
  ) => {
8303
8747
  // Controlled vs uncontrolled state
8304
8748
  const [internalSelected, setInternalSelected] = React.useState<string[]>(
@@ -8459,10 +8903,7 @@ import type { EventGroupComponentProps } from "./types";
8459
8903
  /**
8460
8904
  * Event group with accordion section and group-level checkbox
8461
8905
  */
8462
- export const EventGroupComponent = React.forwardRef<
8463
- HTMLDivElement,
8464
- EventGroupComponentProps & React.HTMLAttributes<HTMLDivElement>
8465
- >(
8906
+ export const EventGroupComponent = React.forwardRef(
8466
8907
  (
8467
8908
  {
8468
8909
  group,
@@ -8474,8 +8915,8 @@ export const EventGroupComponent = React.forwardRef<
8474
8915
  defaultExpanded = false,
8475
8916
  className,
8476
8917
  ...props
8477
- },
8478
- ref
8918
+ }: EventGroupComponentProps & React.HTMLAttributes<HTMLDivElement>,
8919
+ ref: React.Ref<HTMLDivElement>
8479
8920
  ) => {
8480
8921
  // Calculate selection state for this group
8481
8922
  const groupEventIds = events.map((e) => e.id);
@@ -8638,10 +9079,7 @@ import type { EventItemComponentProps } from "./types";
8638
9079
  /**
8639
9080
  * Individual event item with checkbox
8640
9081
  */
8641
- export const EventItemComponent = React.forwardRef<
8642
- HTMLDivElement,
8643
- EventItemComponentProps & React.HTMLAttributes<HTMLDivElement>
8644
- >(({ event, isSelected, onSelectionChange, className, ...props }, ref) => {
9082
+ export const EventItemComponent = React.forwardRef(({ event, isSelected, onSelectionChange, className, ...props }: EventItemComponentProps & React.HTMLAttributes<HTMLDivElement>, ref: React.Ref<HTMLDivElement>) => {
8645
9083
  return (
8646
9084
  <div
8647
9085
  ref={ref}
@@ -8852,10 +9290,7 @@ const generateId = () =>
8852
9290
  * />
8853
9291
  * \`\`\`
8854
9292
  */
8855
- export const KeyValueInput = React.forwardRef<
8856
- HTMLDivElement,
8857
- KeyValueInputProps
8858
- >(
9293
+ export const KeyValueInput = React.forwardRef(
8859
9294
  (
8860
9295
  {
8861
9296
  title,
@@ -8873,8 +9308,8 @@ export const KeyValueInput = React.forwardRef<
8873
9308
  defaultValue = [],
8874
9309
  className,
8875
9310
  ...props
8876
- },
8877
- ref
9311
+ }: KeyValueInputProps,
9312
+ ref: React.Ref<HTMLDivElement>
8878
9313
  ) => {
8879
9314
  // Controlled vs uncontrolled state
8880
9315
  const [internalPairs, setInternalPairs] =
@@ -9071,10 +9506,7 @@ import type { KeyValueRowProps } from "./types";
9071
9506
  /**
9072
9507
  * Individual key-value pair row with inputs and delete button
9073
9508
  */
9074
- export const KeyValueRow = React.forwardRef<
9075
- HTMLDivElement,
9076
- KeyValueRowProps & React.HTMLAttributes<HTMLDivElement>
9077
- >(
9509
+ export const KeyValueRow = React.forwardRef(
9078
9510
  (
9079
9511
  {
9080
9512
  pair,
@@ -9090,8 +9522,8 @@ export const KeyValueRow = React.forwardRef<
9090
9522
  onDelete,
9091
9523
  className,
9092
9524
  ...props
9093
- },
9094
- ref
9525
+ }: KeyValueRowProps & React.HTMLAttributes<HTMLDivElement>,
9526
+ ref: React.Ref<HTMLDivElement>
9095
9527
  ) => {
9096
9528
  // Determine if inputs should show error state
9097
9529
  const keyHasError = isDuplicateKey || (keyRequired && isKeyEmpty);
@@ -9306,10 +9738,7 @@ export interface ApiFeatureCardProps
9306
9738
  * />
9307
9739
  * \`\`\`
9308
9740
  */
9309
- export const ApiFeatureCard = React.forwardRef<
9310
- HTMLDivElement,
9311
- ApiFeatureCardProps
9312
- >(
9741
+ export const ApiFeatureCard = React.forwardRef(
9313
9742
  (
9314
9743
  {
9315
9744
  icon,
@@ -9322,8 +9751,8 @@ export const ApiFeatureCard = React.forwardRef<
9322
9751
  capabilitiesLabel = "Key Capabilities",
9323
9752
  className,
9324
9753
  ...props
9325
- },
9326
- ref
9754
+ }: ApiFeatureCardProps,
9755
+ ref: React.Ref<HTMLDivElement>
9327
9756
  ) => {
9328
9757
  return (
9329
9758
  <div
@@ -9495,10 +9924,7 @@ export interface EndpointDetailsProps
9495
9924
  * />
9496
9925
  * \`\`\`
9497
9926
  */
9498
- export const EndpointDetails = React.forwardRef<
9499
- HTMLDivElement,
9500
- EndpointDetailsProps
9501
- >(
9927
+ export const EndpointDetails = React.forwardRef(
9502
9928
  (
9503
9929
  {
9504
9930
  title = "Endpoint Details",
@@ -9519,8 +9945,8 @@ export const EndpointDetails = React.forwardRef<
9519
9945
  revokeDescription = "Revoking access will immediately disable all integrations using these keys.",
9520
9946
  className,
9521
9947
  ...props
9522
- },
9523
- ref
9948
+ }: EndpointDetailsProps,
9949
+ ref: React.Ref<HTMLDivElement>
9524
9950
  ) => {
9525
9951
  const isCalling = variant === "calling";
9526
9952
 
@@ -9710,10 +10136,7 @@ export interface AlertConfigurationProps {
9710
10136
  * AlertConfiguration component displays current alert values for minimum balance and top-up.
9711
10137
  * Used in payment auto-pay setup to show notification thresholds.
9712
10138
  */
9713
- export const AlertConfiguration = React.forwardRef<
9714
- HTMLDivElement,
9715
- AlertConfigurationProps
9716
- >(
10139
+ export const AlertConfiguration = React.forwardRef(
9717
10140
  (
9718
10141
  {
9719
10142
  minimumBalance,
@@ -9721,8 +10144,8 @@ export const AlertConfiguration = React.forwardRef<
9721
10144
  currencySymbol = "\u20B9",
9722
10145
  onEdit,
9723
10146
  className,
9724
- },
9725
- ref
10147
+ }: AlertConfigurationProps,
10148
+ ref: React.Ref<HTMLDivElement>
9726
10149
  ) => {
9727
10150
  const formatCurrency = (amount: number) => {
9728
10151
  const formatted = amount.toLocaleString("en-IN", {
@@ -9857,10 +10280,7 @@ export interface AlertValuesModalProps {
9857
10280
  * AlertValuesModal component for editing alert configuration values.
9858
10281
  * Displays a form with inputs for minimum balance and minimum top-up.
9859
10282
  */
9860
- export const AlertValuesModal = React.forwardRef<
9861
- HTMLDivElement,
9862
- AlertValuesModalProps
9863
- >(
10283
+ export const AlertValuesModal = React.forwardRef(
9864
10284
  (
9865
10285
  {
9866
10286
  open,
@@ -9872,8 +10292,8 @@ export const AlertValuesModal = React.forwardRef<
9872
10292
  topupOptions,
9873
10293
  onSave,
9874
10294
  loading = false,
9875
- },
9876
- ref
10295
+ }: AlertValuesModalProps,
10296
+ ref: React.Ref<HTMLDivElement>
9877
10297
  ) => {
9878
10298
  const [minimumBalance, setMinimumBalance] = React.useState(
9879
10299
  initialMinimumBalance.toString()
@@ -10022,7 +10442,7 @@ import type { AutoPaySetupProps } from "./types";
10022
10442
  * />
10023
10443
  * \`\`\`
10024
10444
  */
10025
- export const AutoPaySetup = React.forwardRef<HTMLDivElement, AutoPaySetupProps>(
10445
+ export const AutoPaySetup = React.forwardRef(
10026
10446
  (
10027
10447
  {
10028
10448
  title = "Auto-pay setup",
@@ -10041,8 +10461,8 @@ export const AutoPaySetup = React.forwardRef<HTMLDivElement, AutoPaySetupProps>(
10041
10461
  open,
10042
10462
  onOpenChange,
10043
10463
  className,
10044
- },
10045
- ref
10464
+ }: AutoPaySetupProps,
10465
+ ref: React.Ref<HTMLDivElement>
10046
10466
  ) => {
10047
10467
  const isControlled = open !== undefined;
10048
10468
 
@@ -10233,7 +10653,7 @@ import type { BankDetailsProps, BankDetailItem } from "./types";
10233
10653
  * />
10234
10654
  * \`\`\`
10235
10655
  */
10236
- export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
10656
+ export const BankDetails = React.forwardRef(
10237
10657
  (
10238
10658
  {
10239
10659
  title = "Bank details",
@@ -10245,8 +10665,8 @@ export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
10245
10665
  onOpenChange,
10246
10666
  onCopy,
10247
10667
  className,
10248
- },
10249
- ref
10668
+ }: BankDetailsProps,
10669
+ ref: React.Ref<HTMLDivElement>
10250
10670
  ) => {
10251
10671
  const isControlled = open !== undefined;
10252
10672
 
@@ -11062,8 +11482,8 @@ const BreakdownCardRow = ({ item }: { item: BreakdownCardItem }) => (
11062
11482
  * />
11063
11483
  * \`\`\`
11064
11484
  */
11065
- export const PaymentSummary = React.forwardRef<HTMLDivElement, PaymentSummaryProps>(
11066
- ({ items = [], summaryItems, className, title, headerInfo, subtotal, breakdownCard, creditLimit }, ref) => {
11485
+ export const PaymentSummary = React.forwardRef(
11486
+ ({ items = [], summaryItems, className, title, headerInfo, subtotal, breakdownCard, creditLimit }: PaymentSummaryProps, ref: React.Ref<HTMLDivElement>) => {
11067
11487
  const hasItemsBorder =
11068
11488
  items.length > 0 &&
11069
11489
  (!!subtotal || !!breakdownCard || (summaryItems && summaryItems.length > 0));
@@ -11260,10 +11680,7 @@ import type { PaymentOptionCardProps } from "./types";
11260
11680
  * />
11261
11681
  * \`\`\`
11262
11682
  */
11263
- export const PaymentOptionCard = React.forwardRef<
11264
- HTMLDivElement,
11265
- PaymentOptionCardProps
11266
- >(
11683
+ export const PaymentOptionCard = React.forwardRef(
11267
11684
  (
11268
11685
  {
11269
11686
  title = "Select payment method",
@@ -11278,8 +11695,8 @@ export const PaymentOptionCard = React.forwardRef<
11278
11695
  loading = false,
11279
11696
  disabled = false,
11280
11697
  className,
11281
- },
11282
- ref
11698
+ }: PaymentOptionCardProps,
11699
+ ref: React.Ref<HTMLDivElement>
11283
11700
  ) => {
11284
11701
  const [internalSelected, setInternalSelected] = React.useState<
11285
11702
  string | undefined
@@ -11412,10 +11829,7 @@ export interface PaymentOptionCardModalProps
11412
11829
  * />
11413
11830
  * \`\`\`
11414
11831
  */
11415
- export const PaymentOptionCardModal = React.forwardRef<
11416
- HTMLDivElement,
11417
- PaymentOptionCardModalProps
11418
- >(
11832
+ export const PaymentOptionCardModal = React.forwardRef(
11419
11833
  (
11420
11834
  {
11421
11835
  open,
@@ -11431,8 +11845,8 @@ export const PaymentOptionCardModal = React.forwardRef<
11431
11845
  loading,
11432
11846
  disabled,
11433
11847
  className,
11434
- },
11435
- ref
11848
+ }: PaymentOptionCardModalProps,
11849
+ ref: React.Ref<HTMLDivElement>
11436
11850
  ) => {
11437
11851
  const handleClose = () => {
11438
11852
  onOpenChange(false);
@@ -11570,7 +11984,7 @@ const DEFAULT_FEATURES: PlanFeature[] = [
11570
11984
  { name: "Channel(s)", free: "1 Pair(s)", rate: "\u20B9 300.00" },
11571
11985
  ];
11572
11986
 
11573
- const PlanDetailModal = React.forwardRef<HTMLDivElement, PlanDetailModalProps>(
11987
+ const PlanDetailModal = React.forwardRef(
11574
11988
  (
11575
11989
  {
11576
11990
  open,
@@ -11581,8 +11995,8 @@ const PlanDetailModal = React.forwardRef<HTMLDivElement, PlanDetailModalProps>(
11581
11995
  onClose,
11582
11996
  className,
11583
11997
  ...props
11584
- },
11585
- ref
11998
+ }: PlanDetailModalProps,
11999
+ ref: React.Ref<HTMLDivElement>
11586
12000
  ) => {
11587
12001
  const handleClose = () => {
11588
12002
  onClose?.();
@@ -11791,7 +12205,7 @@ const renderOptionIcon = (icon: BillingCycleOption["icon"]) => {
11791
12205
  return icon;
11792
12206
  };
11793
12207
 
11794
- const PlanUpgradeModal = React.forwardRef<HTMLDivElement, PlanUpgradeModalProps>(
12208
+ const PlanUpgradeModal = React.forwardRef(
11795
12209
  (
11796
12210
  {
11797
12211
  open,
@@ -11808,8 +12222,8 @@ const PlanUpgradeModal = React.forwardRef<HTMLDivElement, PlanUpgradeModalProps>
11808
12222
  onClose,
11809
12223
  className,
11810
12224
  ...props
11811
- },
11812
- ref
12225
+ }: PlanUpgradeModalProps,
12226
+ ref: React.Ref<HTMLDivElement>
11813
12227
  ) => {
11814
12228
  const initialOptionId = defaultSelectedOptionId ?? options[0]?.id;
11815
12229
  const [internalSelectedOptionId, setInternalSelectedOptionId] = React.useState<
@@ -12087,10 +12501,7 @@ const getStatusIcon = (tone: PlanUpgradeSummaryTone) => {
12087
12501
  return <AlertCircle className="size-6 text-semantic-warning-text" aria-hidden="true" />;
12088
12502
  };
12089
12503
 
12090
- const PlanUpgradeSummaryModal = React.forwardRef<
12091
- HTMLDivElement,
12092
- PlanUpgradeSummaryModalProps
12093
- >(
12504
+ const PlanUpgradeSummaryModal = React.forwardRef(
12094
12505
  (
12095
12506
  {
12096
12507
  open,
@@ -12112,8 +12523,8 @@ const PlanUpgradeSummaryModal = React.forwardRef<
12112
12523
  closeAriaLabel = "Close plan summary modal",
12113
12524
  className,
12114
12525
  ...props
12115
- },
12116
- ref
12526
+ }: PlanUpgradeSummaryModalProps,
12527
+ ref: React.Ref<HTMLDivElement>
12117
12528
  ) => {
12118
12529
  const resolvedStatus = status ?? defaultStatusByMode[mode];
12119
12530
  const resolvedTone = resolvedStatus.tone ?? defaultStatusByMode[mode].tone ?? "warning";
@@ -12350,7 +12761,7 @@ import type { LetUsDriveCardProps } from "./types";
12350
12761
  * />
12351
12762
  * \`\`\`
12352
12763
  */
12353
- const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12764
+ const LetUsDriveCard = React.forwardRef(
12354
12765
  (
12355
12766
  {
12356
12767
  title,
@@ -12370,8 +12781,8 @@ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12370
12781
  onCtaClick,
12371
12782
  className,
12372
12783
  ...props
12373
- },
12374
- ref
12784
+ }: LetUsDriveCardProps,
12785
+ ref: React.Ref<HTMLDivElement>
12375
12786
  ) => {
12376
12787
  const [internalExpanded, setInternalExpanded] = React.useState(false);
12377
12788
  const isControlled = controlledExpanded !== undefined;
@@ -12395,7 +12806,7 @@ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12395
12806
  <div
12396
12807
  ref={ref}
12397
12808
  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",
12809
+ "flex min-h-0 flex-col gap-6 rounded-[14px] border border-semantic-border-layout bg-card p-5 shadow-sm",
12399
12810
  className
12400
12811
  )}
12401
12812
  {...props}
@@ -12634,7 +13045,7 @@ import type { PowerUpCardProps } from "./types";
12634
13045
  * />
12635
13046
  * \`\`\`
12636
13047
  */
12637
- const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
13048
+ const PowerUpCard = React.forwardRef(
12638
13049
  (
12639
13050
  {
12640
13051
  icon,
@@ -12645,8 +13056,8 @@ const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
12645
13056
  onCtaClick,
12646
13057
  className,
12647
13058
  ...props
12648
- },
12649
- ref
13059
+ }: PowerUpCardProps,
13060
+ ref: React.Ref<HTMLDivElement>
12650
13061
  ) => {
12651
13062
  return (
12652
13063
  <div
@@ -12773,7 +13184,7 @@ import type { PricingCardProps } from "./types";
12773
13184
  * />
12774
13185
  * \`\`\`
12775
13186
  */
12776
- const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
13187
+ const PricingCard = React.forwardRef(
12777
13188
  (
12778
13189
  {
12779
13190
  planName,
@@ -12797,8 +13208,8 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12797
13208
  infoText,
12798
13209
  className,
12799
13210
  ...props
12800
- },
12801
- ref
13211
+ }: PricingCardProps,
13212
+ ref: React.Ref<HTMLDivElement>
12802
13213
  ) => {
12803
13214
  const buttonText =
12804
13215
  ctaText || (isCurrentPlan ? "Current plan" : "Select plan");
@@ -12820,9 +13231,6 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12820
13231
  {/* Header */}
12821
13232
  <div
12822
13233
  className="flex flex-col gap-4 rounded-t-xl rounded-b-lg p-4"
12823
- style={
12824
- headerBgColor ? { backgroundColor: headerBgColor } : undefined
12825
- }
12826
13234
  >
12827
13235
  {/* Plan name + badge */}
12828
13236
  <div className="flex items-center gap-4">
@@ -12880,11 +13288,11 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12880
13288
  </div>
12881
13289
  )}
12882
13290
  <Button
12883
- variant={isCurrentPlan ? "outline" : "default"}
13291
+ variant={isCurrentPlan ? "secondary" : "default"}
12884
13292
  className="w-full"
12885
13293
  onClick={onCtaClick}
12886
13294
  loading={ctaLoading}
12887
- disabled={ctaDisabled}
13295
+ disabled={ctaDisabled || isCurrentPlan}
12888
13296
  >
12889
13297
  {buttonText}
12890
13298
  </Button>
@@ -12931,29 +13339,34 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12931
13339
  </div>
12932
13340
  )}
12933
13341
 
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]" />
13342
+ {/* Bottom sections pushed to card bottom for grid alignment */}
13343
+ {(addon || (usageDetails && usageDetails.length > 0)) && (
13344
+ <div className="mt-auto flex flex-col gap-6">
13345
+ {/* Addon */}
13346
+ {addon && (
13347
+ <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
13348
+ {addon.icon && (
13349
+ <div className="size-5 shrink-0">{addon.icon}</div>
13350
+ )}
12952
13351
  <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
12953
- <strong>{detail.label}:</strong> {detail.value}
13352
+ {addon.text}
12954
13353
  </span>
12955
13354
  </div>
12956
- ))}
13355
+ )}
13356
+
13357
+ {/* Usage Details */}
13358
+ {usageDetails && usageDetails.length > 0 && (
13359
+ <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
13360
+ {usageDetails.map((detail, index) => (
13361
+ <div key={index} className="flex items-start gap-2">
13362
+ <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
13363
+ <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
13364
+ <strong>{detail.label}:</strong> {detail.value}
13365
+ </span>
13366
+ </div>
13367
+ ))}
13368
+ </div>
13369
+ )}
12957
13370
  </div>
12958
13371
  )}
12959
13372
  </div>
@@ -12974,8 +13387,8 @@ interface PlanIconProps extends React.SVGAttributes<SVGElement> {
12974
13387
  className?: string;
12975
13388
  }
12976
13389
 
12977
- const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
12978
- ({ className, ...props }, ref) => (
13390
+ const CompactCarIcon = React.forwardRef(
13391
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
12979
13392
  <svg
12980
13393
  ref={ref}
12981
13394
  className={className}
@@ -13014,8 +13427,8 @@ const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13014
13427
  );
13015
13428
  CompactCarIcon.displayName = "CompactCarIcon";
13016
13429
 
13017
- const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13018
- ({ className, ...props }, ref) => (
13430
+ const SedanCarIcon = React.forwardRef(
13431
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13019
13432
  <svg
13020
13433
  ref={ref}
13021
13434
  className={className}
@@ -13066,8 +13479,8 @@ const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13066
13479
  );
13067
13480
  SedanCarIcon.displayName = "SedanCarIcon";
13068
13481
 
13069
- const SuvCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13070
- ({ className, ...props }, ref) => (
13482
+ const SuvCarIcon = React.forwardRef(
13483
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13071
13484
  <svg
13072
13485
  ref={ref}
13073
13486
  className={className}
@@ -13280,7 +13693,7 @@ import type { PricingPageProps } from "./types";
13280
13693
  * />
13281
13694
  * \`\`\`
13282
13695
  */
13283
- const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13696
+ const PricingPage = React.forwardRef(
13284
13697
  (
13285
13698
  {
13286
13699
  title = "Select business plan",
@@ -13300,11 +13713,10 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13300
13713
  onFeatureComparisonClick,
13301
13714
  letUsDriveCards = [],
13302
13715
  letUsDriveTitle = "Let us drive \u2014 Full-service management",
13303
- letUsDriveExpandMode,
13304
13716
  className,
13305
- ...props
13306
- },
13307
- ref
13717
+ ...props
13718
+ }: PricingPageProps,
13719
+ ref: React.Ref<HTMLDivElement>
13308
13720
  ) => {
13309
13721
  // Internal state for uncontrolled mode
13310
13722
  const [internalTab, setInternalTab] = React.useState(
@@ -13313,9 +13725,6 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13313
13725
  const [internalBilling, setInternalBilling] = React.useState<
13314
13726
  "monthly" | "yearly"
13315
13727
  >("monthly");
13316
- const [expandedLetUsDriveIndices, setExpandedLetUsDriveIndices] =
13317
- React.useState<number[]>([]);
13318
-
13319
13728
  const currentTab = controlledTab ?? internalTab;
13320
13729
  const currentBilling = controlledBilling ?? internalBilling;
13321
13730
 
@@ -13329,30 +13738,6 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13329
13738
  onBillingPeriodChange?.(period);
13330
13739
  };
13331
13740
 
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
13741
  const hasPowerUps = powerUpCards.length > 0;
13357
13742
  const hasLetUsDrive = letUsDriveCards.length > 0;
13358
13743
 
@@ -13448,22 +13833,11 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13448
13833
  {letUsDriveTitle}
13449
13834
  </h2>
13450
13835
 
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
- })}
13836
+ {/* Service cards \u2014 items-start so expanding one card doesn't stretch others */}
13837
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-start">
13838
+ {letUsDriveCards.map((cardProps, index) => (
13839
+ <LetUsDriveCard key={index} {...cardProps} />
13840
+ ))}
13467
13841
  </div>
13468
13842
  </div>
13469
13843
  </div>
@@ -13552,13 +13926,6 @@ export interface PricingPageProps
13552
13926
  letUsDriveCards?: LetUsDriveCardProps[];
13553
13927
  /** Let-us-drive section heading (default: "Let us drive \u2014 Full-service management") */
13554
13928
  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
13929
  }
13563
13930
  `, prefix)
13564
13931
  },
@@ -13615,7 +13982,7 @@ import type { PricingToggleProps } from "./types";
13615
13982
  * />
13616
13983
  * \`\`\`
13617
13984
  */
13618
- const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13985
+ const PricingToggle = React.forwardRef(
13619
13986
  (
13620
13987
  {
13621
13988
  tabs,
@@ -13628,8 +13995,8 @@ const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13628
13995
  yearlyLabel = "Yearly (Save 20%)",
13629
13996
  className,
13630
13997
  ...props
13631
- },
13632
- ref
13998
+ }: PricingToggleProps,
13999
+ ref: React.Ref<HTMLDivElement>
13633
14000
  ) => {
13634
14001
  const isYearly = billingPeriod === "yearly";
13635
14002
 
@@ -13874,8 +14241,8 @@ interface BrandIconProps extends React.SVGAttributes<SVGElement> {
13874
14241
  * Used in TalkToUsModal and available for any component that needs
13875
14242
  * the MyOperator contact/chat branding.
13876
14243
  */
13877
- const MyOperatorChatIcon = React.forwardRef<SVGSVGElement, BrandIconProps>(
13878
- ({ className, ...props }, ref) => (
14244
+ const MyOperatorChatIcon = React.forwardRef(
14245
+ ({ className, ...props }: BrandIconProps, ref: React.Ref<SVGSVGElement>) => (
13879
14246
  <svg
13880
14247
  ref={ref}
13881
14248
  className={className}
@@ -14008,8 +14375,8 @@ function getTypeLabel(
14008
14375
  * All displayed data (icon, badge, name, count, last published) comes from the \`bot\` prop.
14009
14376
  * Set bot.type to "chatbot" or "voicebot"; no separate card components needed.
14010
14377
  */
14011
- export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14012
- ({ bot, typeLabels, onEdit, onDelete, className, ...props }, ref) => {
14378
+ export const BotCard = React.forwardRef(
14379
+ ({ bot, typeLabels, onEdit, onDelete, className, ...props }: BotCardProps, ref: React.Ref<HTMLDivElement>) => {
14013
14380
  const typeLabel = getTypeLabel(bot, typeLabels);
14014
14381
  const isChatbot = bot.type === "chatbot";
14015
14382
 
@@ -14039,7 +14406,6 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14039
14406
  className={cn(
14040
14407
  "relative bg-semantic-bg-primary border border-semantic-border-layout rounded-[5px] min-w-0 max-w-full overflow-hidden flex flex-col",
14041
14408
  "shadow-[0px_4px_15.1px_0px_rgba(0,0,0,0.06)] p-3 sm:p-4 md:p-5",
14042
- "min-h-[180px] sm:min-h-[207px] h-full shrink-0",
14043
14409
  onEdit && "cursor-pointer",
14044
14410
  className
14045
14411
  )}
@@ -14097,7 +14463,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14097
14463
  </div>
14098
14464
 
14099
14465
  {/* Bot name */}
14100
- <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary truncate mb-1 min-w-0">
14466
+ <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary line-clamp-1 mb-1 min-w-0">
14101
14467
  {bot.name}
14102
14468
  </h3>
14103
14469
 
@@ -14125,7 +14491,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14125
14491
  </span>
14126
14492
  )}
14127
14493
  {(bot.lastPublishedBy || bot.lastPublishedDate) ? (
14128
- <p className="m-0 text-xs sm:text-sm text-semantic-text-muted truncate">
14494
+ <p className="m-0 text-xs sm:text-sm text-semantic-text-muted line-clamp-1">
14129
14495
  {bot.lastPublishedBy
14130
14496
  ? \`\${bot.lastPublishedBy} | \${bot.lastPublishedDate ?? "\u2014"}\`
14131
14497
  : bot.lastPublishedDate}
@@ -14175,10 +14541,7 @@ const BOT_TYPE_OPTIONS: BotTypeOption[] = [
14175
14541
  },
14176
14542
  ];
14177
14543
 
14178
- export const CreateBotModal = React.forwardRef<
14179
- HTMLDivElement,
14180
- CreateBotModalProps
14181
- >(({ open, onOpenChange, onSubmit, isLoading, className }, ref) => {
14544
+ export const CreateBotModal = React.forwardRef(({ open, onOpenChange, onSubmit, isLoading, className }: CreateBotModalProps, ref: React.Ref<HTMLDivElement>) => {
14182
14545
  const [name, setName] = React.useState("");
14183
14546
  const [selectedType, setSelectedType] = React.useState<BotType>("chatbot");
14184
14547
 
@@ -14326,15 +14689,15 @@ import type { CreateBotFlowProps } from "./types";
14326
14689
  * Create bot flow: "Create new bot" card + Create Bot modal. No header (title/subtitle/search).
14327
14690
  * Use when you want the create-bot experience without the list header.
14328
14691
  */
14329
- export const CreateBotFlow = React.forwardRef<HTMLDivElement, CreateBotFlowProps>(
14692
+ export const CreateBotFlow = React.forwardRef(
14330
14693
  (
14331
14694
  {
14332
14695
  createCardLabel = "Create new bot",
14333
14696
  onSubmit,
14334
14697
  className,
14335
14698
  ...props
14336
- },
14337
- ref
14699
+ }: CreateBotFlowProps,
14700
+ ref: React.Ref<HTMLDivElement>
14338
14701
  ) => {
14339
14702
  const [modalOpen, setModalOpen] = React.useState(false);
14340
14703
 
@@ -14450,7 +14813,7 @@ import { BotListGrid } from "./bot-list-grid";
14450
14813
  import { CreateBotModal } from "./create-bot-modal";
14451
14814
  import type { BotListProps } from "./types";
14452
14815
 
14453
- export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14816
+ export const BotList = React.forwardRef(
14454
14817
  (
14455
14818
  {
14456
14819
  bots = [],
@@ -14466,8 +14829,8 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14466
14829
  createCardLabel = "Create new bot",
14467
14830
  className,
14468
14831
  ...props
14469
- },
14470
- ref
14832
+ }: BotListProps,
14833
+ ref: React.Ref<HTMLDivElement>
14471
14834
  ) => {
14472
14835
  const [searchQuery, setSearchQuery] = React.useState("");
14473
14836
  const [createModalOpen, setCreateModalOpen] = React.useState(false);
@@ -14577,10 +14940,10 @@ const botListHeaderVariants = cva("min-w-0", {
14577
14940
  },
14578
14941
  });
14579
14942
 
14580
- export const BotListHeader = React.forwardRef<HTMLDivElement, BotListHeaderProps>(
14943
+ export const BotListHeader = React.forwardRef(
14581
14944
  (
14582
- { title, subtitle, variant = "default", rightContent, className, ...props },
14583
- ref
14945
+ { title, subtitle, variant = "default", rightContent, className, ...props }: BotListHeaderProps,
14946
+ ref: React.Ref<HTMLDivElement>
14584
14947
  ) => {
14585
14948
  const rootClassName = cn(botListHeaderVariants({ variant }), className);
14586
14949
  const titleBlock = (
@@ -14627,7 +14990,7 @@ import { Search } from "lucide-react";
14627
14990
  import { cn } from "../../../lib/utils";
14628
14991
  import type { BotListSearchProps } from "./types";
14629
14992
 
14630
- export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps>(
14993
+ export const BotListSearch = React.forwardRef(
14631
14994
  (
14632
14995
  {
14633
14996
  value,
@@ -14636,8 +14999,8 @@ export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps
14636
14999
  defaultValue,
14637
15000
  className,
14638
15001
  ...props
14639
- },
14640
- ref
15002
+ }: BotListSearchProps,
15003
+ ref: React.Ref<HTMLDivElement>
14641
15004
  ) => {
14642
15005
  const [internalValue, setInternalValue] = React.useState(defaultValue ?? "");
14643
15006
  const isControlled = value !== undefined;
@@ -14684,18 +15047,15 @@ import { Plus } from "lucide-react";
14684
15047
  import { cn } from "../../../lib/utils";
14685
15048
  import type { BotListCreateCardProps } from "./types";
14686
15049
 
14687
- export const BotListCreateCard = React.forwardRef<
14688
- HTMLButtonElement,
14689
- BotListCreateCardProps
14690
- >(
15050
+ export const BotListCreateCard = React.forwardRef(
14691
15051
  (
14692
15052
  {
14693
15053
  label = "Create new bot",
14694
15054
  onClick,
14695
15055
  className,
14696
15056
  ...props
14697
- },
14698
- ref
15057
+ }: BotListCreateCardProps,
15058
+ ref: React.Ref<HTMLButtonElement>
14699
15059
  ) => (
14700
15060
  <button
14701
15061
  ref={ref}
@@ -14744,14 +15104,13 @@ BotListCreateCard.displayName = "BotListCreateCard";
14744
15104
  import { cn } from "../../../lib/utils";
14745
15105
  import type { BotListGridProps } from "./types";
14746
15106
 
14747
- export const BotListGrid = React.forwardRef<HTMLDivElement, BotListGridProps>(
14748
- ({ children, className, ...props }, ref) => (
15107
+ export const BotListGrid = React.forwardRef(
15108
+ ({ children, className, ...props }: BotListGridProps, ref: React.Ref<HTMLDivElement>) => (
14749
15109
  <div
14750
15110
  ref={ref}
14751
15111
  className={cn(
14752
- "grid w-full min-w-0 max-w-full content-start gap-3 sm:gap-5 md:gap-6",
15112
+ "grid w-full min-w-0 max-w-full overflow-hidden gap-3 sm:gap-5 md:gap-6",
14753
15113
  "grid-cols-[repeat(auto-fill,minmax(min(100%,280px),1fr))]",
14754
- "auto-rows-auto items-stretch",
14755
15114
  className
14756
15115
  )}
14757
15116
  {...props}
@@ -15047,7 +15406,7 @@ function getTimeRemaining(progress: number) {
15047
15406
  : \`\${secs} seconds remaining\`;
15048
15407
  }
15049
15408
 
15050
- const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15409
+ const FileUploadModal = React.forwardRef(
15051
15410
  (
15052
15411
  {
15053
15412
  open,
@@ -15070,8 +15429,8 @@ const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15070
15429
  loading = false,
15071
15430
  className,
15072
15431
  ...props
15073
- },
15074
- ref
15432
+ }: FileUploadModalProps,
15433
+ ref: React.Ref<HTMLDivElement>
15075
15434
  ) => {
15076
15435
  const [items, setItems] = React.useState<UploadItem[]>([]);
15077
15436
  const fileInputRef = React.useRef<HTMLInputElement>(null);
@@ -15441,8 +15800,8 @@ import { X, Play, File } from "lucide-react";
15441
15800
  import { cn } from "../../../lib/utils";
15442
15801
  import type { AttachmentPreviewProps } from "./types";
15443
15802
 
15444
- const AttachmentPreview = React.forwardRef<HTMLDivElement, AttachmentPreviewProps>(
15445
- ({ className, file, onRemove, ...props }, ref) => {
15803
+ const AttachmentPreview = React.forwardRef(
15804
+ ({ className, file, onRemove, ...props }: AttachmentPreviewProps, ref: React.Ref<HTMLDivElement>) => {
15446
15805
  const url = React.useMemo(() => URL.createObjectURL(file), [file]);
15447
15806
 
15448
15807
  const isImage = file.type.startsWith("image/");
@@ -15600,7 +15959,7 @@ const BAR_WIDTH = 2;
15600
15959
  const BAR_GAP = 1.5;
15601
15960
  const SVG_HEIGHT = 32;
15602
15961
 
15603
- const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15962
+ const AudioMedia = React.forwardRef(
15604
15963
  (
15605
15964
  {
15606
15965
  className,
@@ -15614,8 +15973,8 @@ const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15614
15973
  onPlayChange,
15615
15974
  onSpeedChange,
15616
15975
  ...props
15617
- },
15618
- ref
15976
+ }: AudioMediaProps,
15977
+ ref: React.Ref<HTMLDivElement>
15619
15978
  ) => {
15620
15979
  const [playing, setPlaying] = React.useState(false);
15621
15980
  const [speed, setSpeed] = React.useState(1);
@@ -15815,8 +16174,8 @@ import { Reply, ExternalLink, ChevronLeft, ChevronRight } from "lucide-react";
15815
16174
  import { cn } from "../../../lib/utils";
15816
16175
  import type { CarouselMediaProps } from "./types";
15817
16176
 
15818
- const CarouselMedia = React.forwardRef<HTMLDivElement, CarouselMediaProps>(
15819
- ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }, ref) => {
16177
+ const CarouselMedia = React.forwardRef(
16178
+ ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }: CarouselMediaProps, ref: React.Ref<HTMLDivElement>) => {
15820
16179
  const scrollRef = useRef<HTMLDivElement>(null);
15821
16180
  const [canScrollLeft, setCanScrollLeft] = useState(false);
15822
16181
  const [canScrollRight, setCanScrollRight] = useState(
@@ -16070,7 +16429,7 @@ function DeliveryFooter({
16070
16429
  * </ChatBubble>
16071
16430
  * \`\`\`
16072
16431
  */
16073
- const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16432
+ const ChatBubble = React.forwardRef(
16074
16433
  (
16075
16434
  {
16076
16435
  variant,
@@ -16085,8 +16444,8 @@ const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16085
16444
  children,
16086
16445
  className,
16087
16446
  ...props
16088
- },
16089
- ref
16447
+ }: ChatBubbleProps,
16448
+ ref: React.Ref<HTMLDivElement>
16090
16449
  ) => {
16091
16450
  const hasMedia = !!media;
16092
16451
 
@@ -16204,6 +16563,126 @@ export interface ChatBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
16204
16563
  name: "index.ts",
16205
16564
  content: prefixTailwindClasses(`export { ChatBubble } from "./chat-bubble";
16206
16565
  export type { ChatBubbleProps, ChatBubbleReply, DeliveryStatus } from "./types";
16566
+ `, prefix)
16567
+ }
16568
+ ]
16569
+ },
16570
+ "chat-timeline-divider": {
16571
+ name: "chat-timeline-divider",
16572
+ description: "A timeline divider for chat message lists \u2014 renders centered content between horizontal lines with date, unread, and system event variants",
16573
+ category: "custom",
16574
+ dependencies: [
16575
+ "clsx",
16576
+ "tailwind-merge"
16577
+ ],
16578
+ internalDependencies: [],
16579
+ isMultiFile: true,
16580
+ directory: "chat-timeline-divider",
16581
+ mainFile: "chat-timeline-divider.tsx",
16582
+ files: [
16583
+ {
16584
+ name: "chat-timeline-divider.tsx",
16585
+ content: prefixTailwindClasses(`import * as React from "react";
16586
+ import { cn } from "../../../lib/utils";
16587
+
16588
+ /* \u2500\u2500 Types \u2500\u2500 */
16589
+
16590
+ export type ChatTimelineDividerVariant = "default" | "unread" | "system";
16591
+
16592
+ export interface ChatTimelineDividerProps
16593
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
16594
+ /**
16595
+ * Visual style of the divider.
16596
+ * - \`default\`: plain centered text between lines (e.g. "Today", "Yesterday")
16597
+ * - \`unread\`: bold text in a white pill with border (e.g. "3 unread messages")
16598
+ * - \`system\`: muted text in a white pill with border (e.g. "Assigned to Alex Smith")
16599
+ */
16600
+ variant?: ChatTimelineDividerVariant;
16601
+ /** Content to display \u2014 text or ReactNode for rich content (e.g. linked names) */
16602
+ children: React.ReactNode;
16603
+ }
16604
+
16605
+ /* \u2500\u2500 Variant styles \u2500\u2500 */
16606
+
16607
+ const containerStyles: Record<ChatTimelineDividerVariant, string> = {
16608
+ default: "",
16609
+ unread:
16610
+ "bg-white px-2.5 py-0.5 rounded-full border border-semantic-border-layout shadow-sm",
16611
+ system:
16612
+ "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)]",
16613
+ };
16614
+
16615
+ const textStyles: Record<ChatTimelineDividerVariant, string> = {
16616
+ default: "text-[13px] text-semantic-text-muted",
16617
+ unread: "text-[12px] font-semibold text-semantic-text-primary",
16618
+ system: "text-[13px] text-semantic-text-muted",
16619
+ };
16620
+
16621
+ /* \u2500\u2500 Component \u2500\u2500 */
16622
+
16623
+ /**
16624
+ * ChatTimelineDivider renders a centered label between two horizontal lines
16625
+ * in a chat message timeline.
16626
+ *
16627
+ * Use it to separate messages by date, mark unread boundaries,
16628
+ * or display system/action events (assignments, resolutions, etc.).
16629
+ *
16630
+ * @example
16631
+ * \`\`\`tsx
16632
+ * // Date separator
16633
+ * <ChatTimelineDivider>Today</ChatTimelineDivider>
16634
+ *
16635
+ * // Unread count
16636
+ * <ChatTimelineDivider variant="unread">3 unread messages</ChatTimelineDivider>
16637
+ *
16638
+ * // System event with linked names
16639
+ * <ChatTimelineDivider variant="system">
16640
+ * Assigned to <span className="text-semantic-text-link font-medium">Alex Smith</span>
16641
+ * </ChatTimelineDivider>
16642
+ * \`\`\`
16643
+ */
16644
+ const ChatTimelineDivider = React.forwardRef<
16645
+ HTMLDivElement,
16646
+ ChatTimelineDividerProps
16647
+ >(
16648
+ (
16649
+ { variant = "default", children, className, ...props },
16650
+ ref
16651
+ ) => {
16652
+ const showLines = true;
16653
+
16654
+ return (
16655
+ <div
16656
+ ref={ref}
16657
+ role="separator"
16658
+ className={cn("flex items-center gap-4 my-2", className)}
16659
+ {...props}
16660
+ >
16661
+ {showLines && (
16662
+ <div className="flex-1 h-px bg-semantic-border-layout" />
16663
+ )}
16664
+ <div className={cn(containerStyles[variant])}>
16665
+ <span className={cn(textStyles[variant])}>{children}</span>
16666
+ </div>
16667
+ {showLines && (
16668
+ <div className="flex-1 h-px bg-semantic-border-layout" />
16669
+ )}
16670
+ </div>
16671
+ );
16672
+ }
16673
+ );
16674
+ ChatTimelineDivider.displayName = "ChatTimelineDivider";
16675
+
16676
+ export { ChatTimelineDivider };
16677
+ `, prefix)
16678
+ },
16679
+ {
16680
+ name: "index.ts",
16681
+ content: prefixTailwindClasses(`export {
16682
+ ChatTimelineDivider,
16683
+ type ChatTimelineDividerProps,
16684
+ type ChatTimelineDividerVariant,
16685
+ } from "./chat-timeline-divider";
16207
16686
  `, prefix)
16208
16687
  }
16209
16688
  ]
@@ -16259,7 +16738,7 @@ import type { ChatComposerProps } from "./types";
16259
16738
  * />
16260
16739
  * \`\`\`
16261
16740
  */
16262
- const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16741
+ const ChatComposer = React.forwardRef(
16263
16742
  (
16264
16743
  {
16265
16744
  className,
@@ -16283,8 +16762,8 @@ const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16283
16762
  expiredMessage = "This chat has expired. Send a template to continue.",
16284
16763
  onTemplateClick,
16285
16764
  ...props
16286
- },
16287
- ref
16765
+ }: ChatComposerProps,
16766
+ ref: React.Ref<HTMLDivElement>
16288
16767
  ) => {
16289
16768
  const textareaRef = React.useRef<HTMLTextAreaElement>(null);
16290
16769
 
@@ -16459,8 +16938,8 @@ export interface ChatComposerProps extends Omit<React.HTMLAttributes<HTMLDivElem
16459
16938
  leftActions?: React.ReactNode;
16460
16939
  /** Slot for right action buttons (rendered inside textarea container, bottom-right) */
16461
16940
  rightActions?: React.ReactNode;
16462
- /** Send button label. Defaults to "Send" */
16463
- sendLabel?: string;
16941
+ /** Send button label. Accepts text or JSX (e.g. icon + text). Defaults to "Send" */
16942
+ sendLabel?: React.ReactNode;
16464
16943
  /** Whether to show the send dropdown chevron. Defaults to false */
16465
16944
  showSendDropdown?: boolean;
16466
16945
  /** Whether the chat is expired (shows template prompt instead of composer) */
@@ -16501,7 +16980,7 @@ import { cn } from "../../../lib/utils";
16501
16980
  import { File, FileSpreadsheet, ArrowDownToLine } from "lucide-react";
16502
16981
  import type { DocMediaProps } from "./types";
16503
16982
 
16504
- const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16983
+ const DocMedia = React.forwardRef(
16505
16984
  (
16506
16985
  {
16507
16986
  className,
@@ -16514,8 +16993,8 @@ const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16514
16993
  caption,
16515
16994
  onDownload,
16516
16995
  ...props
16517
- },
16518
- ref
16996
+ }: DocMediaProps,
16997
+ ref: React.Ref<HTMLDivElement>
16519
16998
  ) => {
16520
16999
  if (variant === "preview") {
16521
17000
  return (
@@ -16554,12 +17033,35 @@ const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16554
17033
 
16555
17034
  if (variant === "download") {
16556
17035
  return (
16557
- <div ref={ref} className={cn("relative", className)} {...props}>
17036
+ <div
17037
+ ref={ref}
17038
+ className={cn("relative rounded-t overflow-hidden", className)}
17039
+ {...props}
17040
+ >
16558
17041
  <img
16559
17042
  src={thumbnailUrl}
16560
17043
  alt={caption || filename || "Document"}
16561
- className="w-full rounded-t object-cover max-h-[280px]"
17044
+ className="w-full object-cover"
17045
+ style={{ aspectRatio: "442/308" }}
16562
17046
  />
17047
+ <div className="absolute inset-0 bg-gradient-to-t from-[#1d222f] via-[#1d222f]/30 to-transparent" />
17048
+ <div className="absolute bottom-0 left-0 right-0 px-4 py-3">
17049
+ <p className="m-0 text-[14px] font-semibold text-white truncate">
17050
+ {filename || "Document"}
17051
+ </p>
17052
+ <div className="flex items-center gap-1.5 mt-1">
17053
+ <File className="size-3.5 text-white/80" />
17054
+ <span className="text-[12px] text-white/80">
17055
+ {[
17056
+ fileType,
17057
+ pageCount && \`\${pageCount} pages\`,
17058
+ fileSize,
17059
+ ]
17060
+ .filter(Boolean)
17061
+ .join(" \\u00B7 ")}
17062
+ </span>
17063
+ </div>
17064
+ </div>
16563
17065
  </div>
16564
17066
  );
16565
17067
  }
@@ -16702,7 +17204,7 @@ import type { VideoMediaProps } from "./types";
16702
17204
 
16703
17205
  const DEFAULT_SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
16704
17206
 
16705
- const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
17207
+ const VideoMedia = React.forwardRef(
16706
17208
  (
16707
17209
  {
16708
17210
  className,
@@ -16714,8 +17216,8 @@ const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
16714
17216
  onSpeedChange,
16715
17217
  onClick,
16716
17218
  ...props
16717
- },
16718
- ref
17219
+ }: VideoMediaProps,
17220
+ ref: React.Ref<HTMLDivElement>
16719
17221
  ) => {
16720
17222
  const [playing, setPlaying] = useState(false);
16721
17223
  const [muted, setMuted] = useState(false);
@@ -16948,7 +17450,10 @@ export type { VideoMediaProps } from "./types";
16948
17450
  "creatable-multi-select",
16949
17451
  "page-header",
16950
17452
  "tag",
16951
- "file-upload-modal"
17453
+ "file-upload-modal",
17454
+ "form-modal",
17455
+ "text-field",
17456
+ "textarea"
16952
17457
  ],
16953
17458
  isMultiFile: true,
16954
17459
  directory: "ivr-bot",
@@ -17000,7 +17505,7 @@ const DEFAULT_DATA: IvrBotConfigData = {
17000
17505
  };
17001
17506
 
17002
17507
  // \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>(
17508
+ export const IvrBotConfig = React.forwardRef(
17004
17509
  (
17005
17510
  {
17006
17511
  botTitle = "IVR bot",
@@ -17047,8 +17552,8 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
17047
17552
  callEndThresholdMin,
17048
17553
  callEndThresholdMax,
17049
17554
  className,
17050
- },
17051
- ref
17555
+ }: IvrBotConfigProps,
17556
+ ref: React.Ref<HTMLDivElement>
17052
17557
  ) => {
17053
17558
  const [data, setData] = React.useState<IvrBotConfigData>({
17054
17559
  ...DEFAULT_DATA,
@@ -17251,7 +17756,7 @@ IvrBotConfig.displayName = "IvrBotConfig";
17251
17756
  {
17252
17757
  name: "create-function-modal.tsx",
17253
17758
  content: prefixTailwindClasses(`import * as React from "react";
17254
- import { Trash2, ChevronDown, X, Plus } from "lucide-react";
17759
+ import { Trash2, ChevronDown, X, Plus, Pencil } from "lucide-react";
17255
17760
  import { cn } from "../../../lib/utils";
17256
17761
  import {
17257
17762
  Dialog,
@@ -17259,6 +17764,9 @@ import {
17259
17764
  DialogTitle,
17260
17765
  } from "../dialog";
17261
17766
  import { Button } from "../button";
17767
+ import { FormModal } from "../form-modal";
17768
+ import { TextField } from "../text-field";
17769
+ import { Textarea } from "../textarea";
17262
17770
  import type {
17263
17771
  CreateFunctionModalProps,
17264
17772
  CreateFunctionData,
@@ -17266,10 +17774,12 @@ import type {
17266
17774
  FunctionTabType,
17267
17775
  HttpMethod,
17268
17776
  KeyValuePair,
17777
+ VariableGroup,
17778
+ VariableItem,
17779
+ VariableFormData,
17269
17780
  } from "./types";
17270
17781
 
17271
17782
  const HTTP_METHODS: HttpMethod[] = ["GET", "POST", "PUT", "DELETE", "PATCH"];
17272
- const METHODS_WITH_BODY: HttpMethod[] = ["POST", "PUT", "PATCH"];
17273
17783
  const FUNCTION_NAME_MAX = 100;
17274
17784
  const BODY_MAX = 4000;
17275
17785
  const URL_MAX = 500;
@@ -17277,6 +17787,8 @@ const HEADER_KEY_MAX = 512;
17277
17787
  const HEADER_VALUE_MAX = 2048;
17278
17788
 
17279
17789
  const FUNCTION_NAME_REGEX = /^(?!_+$)(?=.*[a-zA-Z])[a-zA-Z][a-zA-Z0-9_]*$/;
17790
+ const VARIABLE_NAME_MAX = 30;
17791
+ const VARIABLE_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;
17280
17792
  const URL_REGEX = /^https?:\\/\\//;
17281
17793
  const HEADER_KEY_REGEX = /^[!#$%&'*+\\-.^_\`|~0-9a-zA-Z]+$/;
17282
17794
  // Query parameter validation (aligned with apiIntegrationSchema.queryParams)
@@ -17332,120 +17844,393 @@ function extractVarRefs(texts: string[]): string[] {
17332
17844
  return Array.from(new Set(all));
17333
17845
  }
17334
17846
 
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
- });
17847
+ // \u2500\u2500 Value segment parser \u2014 splits "text {{var}} text" into typed segments \u2500\u2500\u2500\u2500\u2500
17848
+
17849
+ type ValueSegment =
17850
+ | { type: "text"; content: string }
17851
+ | { type: "var"; name: string; raw: string };
17852
+
17853
+ function parseValueSegments(value: string): ValueSegment[] {
17854
+ const segments: ValueSegment[] = [];
17855
+ const regex = /\\{\\{([^}]+)\\}\\}/g;
17856
+ let lastIndex = 0;
17857
+ let match;
17858
+ while ((match = regex.exec(value)) !== null) {
17859
+ if (match.index > lastIndex) {
17860
+ segments.push({ type: "text", content: value.slice(lastIndex, match.index) });
17861
+ }
17862
+ segments.push({ type: "var", name: match[1], raw: match[0] });
17863
+ lastIndex = regex.lastIndex;
17864
+ }
17865
+ if (lastIndex < value.length) {
17866
+ segments.push({ type: "text", content: value.slice(lastIndex) });
17867
+ }
17868
+ return segments;
17869
+ }
17870
+
17871
+ /** Mirror-div technique \u2014 returns { top, left } relative to the element's top-left corner. */
17872
+ function getCaretPixelPos(
17873
+ el: HTMLTextAreaElement | HTMLInputElement,
17874
+ position: number
17875
+ ): { top: number; left: number } {
17876
+ const cs = window.getComputedStyle(el);
17877
+ const mirror = document.createElement("div");
17878
+
17879
+ (
17880
+ [
17881
+ "boxSizing", "width", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft",
17882
+ "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth",
17883
+ "fontFamily", "fontSize", "fontWeight", "fontStyle", "fontVariant",
17884
+ "letterSpacing", "lineHeight", "textTransform", "wordSpacing", "tabSize",
17885
+ ] as (keyof CSSStyleDeclaration)[]
17886
+ ).forEach((prop) => {
17887
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17888
+ (mirror.style as any)[prop] = cs[prop];
17889
+ });
17890
+
17891
+ mirror.style.whiteSpace = el.tagName === "TEXTAREA" ? "pre-wrap" : "pre";
17892
+ mirror.style.wordWrap = el.tagName === "TEXTAREA" ? "break-word" : "normal";
17893
+ mirror.style.position = "absolute";
17894
+ mirror.style.visibility = "hidden";
17895
+ mirror.style.overflow = "hidden";
17896
+ mirror.style.top = "0";
17897
+ mirror.style.left = "0";
17898
+ mirror.style.width = el.offsetWidth + "px";
17899
+
17900
+ document.body.appendChild(mirror);
17901
+ mirror.appendChild(document.createTextNode(el.value.substring(0, position)));
17902
+
17903
+ const marker = document.createElement("span");
17904
+ marker.textContent = "\\u200b";
17905
+ mirror.appendChild(marker);
17906
+
17907
+ const markerRect = marker.getBoundingClientRect();
17908
+ const mirrorRect = mirror.getBoundingClientRect();
17909
+ document.body.removeChild(mirror);
17910
+
17911
+ const scrollTop = el instanceof HTMLTextAreaElement ? el.scrollTop : 0;
17912
+ return {
17913
+ top: markerRect.top - mirrorRect.top - scrollTop,
17914
+ left: markerRect.left - mirrorRect.left,
17915
+ };
17916
+ }
17917
+
17918
+ // Uses same visual classes as DropdownMenuContent + DropdownMenuItem.
17919
+ // Position is cursor-anchored via getCaretPixelPos.
17920
+ // No search bar \u2014 typing after {{ already filters via filterQuery.
17921
+ function VarPopup({
17922
+ variables,
17923
+ variableGroups,
17924
+ filterQuery = "",
17925
+ onSelect,
17926
+ onAddVariable,
17927
+ onEditVariable,
17928
+ style,
17929
+ }: {
17930
+ variables: string[];
17931
+ variableGroups?: VariableGroup[];
17932
+ filterQuery?: string;
17933
+ onSelect: (v: string) => void;
17934
+ onAddVariable?: () => void;
17935
+ onEditVariable?: (variable: string) => void;
17936
+ style?: React.CSSProperties;
17937
+ }) {
17938
+ const hasGroups = variableGroups && variableGroups.length > 0;
17939
+
17940
+ if (!hasGroups && variables.length === 0) return null;
17941
+
17942
+ // Flat mode \u2014 variables are already pre-filtered by VariableInput
17943
+ if (!hasGroups) {
17944
+ return (
17945
+ <div
17946
+ role="listbox"
17947
+ style={style}
17948
+ 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"
17949
+ >
17950
+ {/* Add new variable */}
17951
+ {onAddVariable && (
17952
+ <button
17953
+ type="button"
17954
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
17955
+ 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"
17956
+ >
17957
+ <Plus className="size-3.5 shrink-0" />
17958
+ Add new variable
17959
+ </button>
17960
+ )}
17961
+
17962
+ {/* Variable list */}
17963
+ <div className="max-h-48 overflow-y-auto p-1">
17964
+ {variables.map((v) => (
17965
+ <button
17966
+ key={v}
17967
+ type="button"
17968
+ role="option"
17969
+ onMouseDown={(e) => { e.preventDefault(); onSelect(v); }}
17970
+ 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"
17971
+ >
17972
+ {v}
17973
+ </button>
17974
+ ))}
17975
+ {variables.length === 0 && (
17976
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
17977
+ )}
17978
+ </div>
17979
+ </div>
17980
+ );
17981
+ }
17982
+
17983
+ // Grouped mode \u2014 filter by the {{ trigger query
17984
+ const lowerQuery = filterQuery.toLowerCase();
17985
+ const filteredGroups = variableGroups.map((g) => ({
17986
+ ...g,
17987
+ items: g.items.filter((item) =>
17988
+ item.name.toLowerCase().includes(lowerQuery)
17989
+ ),
17990
+ })).filter((g) => g.items.length > 0);
17991
+
17992
+ return (
17993
+ <div
17994
+ role="listbox"
17995
+ style={style}
17996
+ 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"
17997
+ >
17998
+ {/* Add new variable */}
17999
+ {onAddVariable && (
18000
+ <>
18001
+ <button
18002
+ type="button"
18003
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
18004
+ 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"
18005
+ >
18006
+ <Plus className="size-3.5 shrink-0" />
18007
+ Add new variable
18008
+ </button>
18009
+ <div className="border-t border-semantic-border-layout" />
18010
+ </>
18011
+ )}
18012
+
18013
+ {/* Grouped variable list */}
18014
+ <div className="max-h-48 overflow-y-auto p-1">
18015
+ {filteredGroups.map((group) => (
18016
+ <div key={group.label}>
18017
+ <p className="m-0 px-2 pt-2 pb-1 text-sm font-medium text-semantic-text-muted">
18018
+ {group.label}
18019
+ </p>
18020
+ {group.items.map((item) => {
18021
+ const insertValue = item.value ?? \`{{\${item.name}}}\`;
18022
+ return (
18023
+ <div key={item.name} className="flex items-center rounded-sm transition-colors hover:bg-semantic-bg-ui">
18024
+ <button
18025
+ type="button"
18026
+ role="option"
18027
+ onMouseDown={(e) => { e.preventDefault(); onSelect(insertValue); }}
18028
+ className="relative flex flex-1 min-w-0 cursor-pointer select-none items-center px-2 py-1.5 text-sm outline-none"
18029
+ >
18030
+ {\`{{\${item.name}}}\`}
18031
+ </button>
18032
+ {item.editable && onEditVariable && (
18033
+ <button
18034
+ type="button"
18035
+ onMouseDown={(e) => { e.preventDefault(); onEditVariable(item.name); }}
18036
+ className="shrink-0 p-1.5 rounded text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
18037
+ aria-label={\`Edit \${item.name}\`}
18038
+ >
18039
+ <Pencil className="size-3.5" />
18040
+ </button>
18041
+ )}
18042
+ </div>
18043
+ );
18044
+ })}
18045
+ </div>
18046
+ ))}
18047
+ {filteredGroups.length === 0 && (
18048
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
18049
+ )}
18050
+ </div>
18051
+ </div>
18052
+ );
18053
+ }
18054
+
18055
+ // \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
18056
 
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";
18057
+ function VariableFormModal({
18058
+ open,
18059
+ onOpenChange,
18060
+ mode,
18061
+ initialData,
18062
+ onSave,
18063
+ }: {
18064
+ open: boolean;
18065
+ onOpenChange: (open: boolean) => void;
18066
+ mode: "create" | "edit";
18067
+ initialData?: VariableItem;
18068
+ onSave: (data: VariableFormData) => void;
18069
+ }) {
18070
+ const [name, setName] = React.useState("");
18071
+ const [description, setDescription] = React.useState("");
18072
+ const [required, setRequired] = React.useState(false);
18073
+ const [nameError, setNameError] = React.useState("");
17363
18074
 
17364
- document.body.appendChild(mirror);
17365
- mirror.appendChild(document.createTextNode(el.value.substring(0, position)));
18075
+ // Reset form when modal opens
18076
+ React.useEffect(() => {
18077
+ if (open) {
18078
+ setName(initialData?.name ?? "");
18079
+ setDescription(initialData?.description ?? "");
18080
+ setRequired(initialData?.required ?? false);
18081
+ setNameError("");
18082
+ }
18083
+ }, [open, initialData]);
17366
18084
 
17367
- const marker = document.createElement("span");
17368
- marker.textContent = "\\u200b";
17369
- mirror.appendChild(marker);
18085
+ const validateName = (v: string) => {
18086
+ if (!v.trim()) return "";
18087
+ if (!VARIABLE_NAME_REGEX.test(v)) {
18088
+ return "Variable name should start with alphabet; Cannot have special characters except underscore (_)";
18089
+ }
18090
+ return "";
18091
+ };
17370
18092
 
17371
- const markerRect = marker.getBoundingClientRect();
17372
- const mirrorRect = mirror.getBoundingClientRect();
17373
- document.body.removeChild(mirror);
18093
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
18094
+ const v = e.target.value;
18095
+ setName(v);
18096
+ setNameError(validateName(v));
18097
+ };
17374
18098
 
17375
- const scrollTop = el instanceof HTMLTextAreaElement ? el.scrollTop : 0;
17376
- return {
17377
- top: markerRect.top - mirrorRect.top - scrollTop,
17378
- left: markerRect.left - mirrorRect.left,
18099
+ const handleSave = () => {
18100
+ const error = validateName(name);
18101
+ if (error || !name.trim()) {
18102
+ setNameError(error || "Variable name is required");
18103
+ return;
18104
+ }
18105
+ onSave({ name: name.trim(), description: description.trim() || undefined, required });
17379
18106
  };
17380
- }
17381
18107
 
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
18108
  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"
18109
+ <FormModal
18110
+ open={open}
18111
+ onOpenChange={onOpenChange}
18112
+ title={mode === "create" ? "Create new variable" : "Edit variable"}
18113
+ saveButtonText={mode === "create" ? "Save" : "Save Changes"}
18114
+ disableSave={!name.trim() || !!nameError}
18115
+ onSave={handleSave}
18116
+ size="default"
17399
18117
  >
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>
18118
+ <div className="flex flex-col gap-4">
18119
+ <div className="flex flex-col gap-1.5">
18120
+ <label className="text-sm font-medium text-semantic-text-muted">
18121
+ Variable name{" "}
18122
+ <span className="text-semantic-error-primary">*</span>
18123
+ </label>
18124
+ <div className="relative">
18125
+ <input
18126
+ type="text"
18127
+ value={name}
18128
+ onChange={handleNameChange}
18129
+ placeholder="e.g., customer_name"
18130
+ maxLength={VARIABLE_NAME_MAX}
18131
+ className={cn(inputCls, "pr-16")}
18132
+ />
18133
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18134
+ {name.length}/{VARIABLE_NAME_MAX}
18135
+ </span>
18136
+ </div>
18137
+ <span className={cn("text-sm", nameError ? "text-semantic-error-primary" : "text-semantic-text-muted")}>
18138
+ {nameError || "Variable name should start with alphabet; Cannot have special characters except underscore (_)"}
18139
+ </span>
18140
+ </div>
18141
+ <TextField
18142
+ label="Description (optional)"
18143
+ placeholder="What this variable represents"
18144
+ value={description}
18145
+ onChange={(e) => setDescription(e.target.value)}
18146
+ />
18147
+ <div className="flex flex-col gap-1.5">
18148
+ <span className="text-sm font-medium text-semantic-text-muted">Required</span>
18149
+ <div className="flex items-center gap-6">
18150
+ <label className="flex items-center gap-2 cursor-pointer">
18151
+ <input
18152
+ type="radio"
18153
+ name="variable-required"
18154
+ checked={required}
18155
+ onChange={() => setRequired(true)}
18156
+ className="size-4 accent-semantic-primary"
18157
+ />
18158
+ <span className="text-base text-semantic-text-primary">Yes</span>
18159
+ </label>
18160
+ <label className="flex items-center gap-2 cursor-pointer">
18161
+ <input
18162
+ type="radio"
18163
+ name="variable-required"
18164
+ checked={!required}
18165
+ onChange={() => setRequired(false)}
18166
+ className="size-4 accent-semantic-primary"
18167
+ />
18168
+ <span className="text-base text-semantic-text-primary">No</span>
18169
+ </label>
18170
+ </div>
18171
+ </div>
18172
+ </div>
18173
+ </FormModal>
17416
18174
  );
17417
18175
  }
17418
18176
 
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
18177
+ // \u2500\u2500 VariableInput \u2014 input with {{ autocomplete + badge display \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17420
18178
 
17421
18179
  function VariableInput({
17422
18180
  value,
17423
18181
  onChange,
17424
18182
  sessionVariables,
18183
+ variableGroups,
18184
+ onAddVariable,
18185
+ onEditVariable,
17425
18186
  placeholder,
17426
18187
  maxLength,
17427
18188
  className,
17428
18189
  inputRef: externalInputRef,
18190
+ disabled,
17429
18191
  ...inputProps
17430
18192
  }: {
17431
18193
  value: string;
17432
18194
  onChange: (v: string) => void;
17433
18195
  sessionVariables: string[];
18196
+ variableGroups?: VariableGroup[];
18197
+ onAddVariable?: () => void;
18198
+ onEditVariable?: (variable: string) => void;
17434
18199
  placeholder?: string;
17435
18200
  maxLength?: number;
17436
18201
  className?: string;
17437
18202
  inputRef?: React.RefObject<HTMLInputElement>;
18203
+ disabled?: boolean;
17438
18204
  [k: string]: unknown;
17439
18205
  }) {
17440
18206
  const internalRef = React.useRef<HTMLInputElement>(null);
17441
18207
  const inputRef = externalInputRef ?? internalRef;
18208
+ const displayRef = React.useRef<HTMLDivElement>(null);
17442
18209
  const [trigger, setTrigger] = React.useState<TriggerState | null>(null);
17443
18210
  const [popupStyle, setPopupStyle] = React.useState<React.CSSProperties | undefined>();
18211
+ const [isEditing, setIsEditing] = React.useState(false);
18212
+ const [isExpanded, setIsExpanded] = React.useState(false);
18213
+ const [isOverflowing, setIsOverflowing] = React.useState(false);
17444
18214
 
17445
18215
  const filtered = trigger
17446
18216
  ? sessionVariables.filter((v) => v.toLowerCase().includes(trigger.query))
17447
18217
  : [];
17448
18218
 
18219
+ // Parse value into text + variable segments
18220
+ const segments = React.useMemo(() => parseValueSegments(value), [value]);
18221
+ const hasVariables = segments.some((s) => s.type === "var");
18222
+ const showDisplay = !isEditing && value.length > 0 && hasVariables;
18223
+
18224
+ // Check overflow in display mode
18225
+ React.useEffect(() => {
18226
+ if (showDisplay && displayRef.current && !isExpanded) {
18227
+ const el = displayRef.current;
18228
+ setIsOverflowing(el.scrollWidth > el.clientWidth);
18229
+ } else {
18230
+ setIsOverflowing(false);
18231
+ }
18232
+ }, [showDisplay, value, isExpanded]);
18233
+
17449
18234
  const updatePopupPos = (el: HTMLInputElement, cursor: number) => {
17450
18235
  const caret = getCaretPixelPos(el, cursor);
17451
18236
  const lineHeight = parseFloat(window.getComputedStyle(el).lineHeight) || 20;
@@ -17474,13 +18259,15 @@ function VariableInput({
17474
18259
 
17475
18260
  return (
17476
18261
  <div className="relative w-full">
18262
+ {/* Input \u2014 always in DOM, hidden when display mode is active */}
17477
18263
  <input
17478
18264
  ref={inputRef}
17479
18265
  type="text"
17480
18266
  value={value}
17481
18267
  placeholder={placeholder}
17482
18268
  maxLength={maxLength}
17483
- className={className}
18269
+ disabled={disabled}
18270
+ className={cn(className, showDisplay && "opacity-0 pointer-events-none")}
17484
18271
  onChange={(e) => {
17485
18272
  onChange(e.target.value);
17486
18273
  const cursor = e.target.selectionStart ?? e.target.value.length;
@@ -17492,10 +18279,88 @@ function VariableInput({
17492
18279
  onKeyDown={(e) => {
17493
18280
  if (e.key === "Escape") clearTrigger();
17494
18281
  }}
17495
- onBlur={() => clearTrigger()}
18282
+ onFocus={() => setIsEditing(true)}
18283
+ onBlur={() => {
18284
+ clearTrigger();
18285
+ setIsEditing(false);
18286
+ setIsExpanded(false);
18287
+ }}
17496
18288
  {...inputProps}
17497
18289
  />
17498
- <VarPopup variables={filtered} onSelect={handleSelect} style={popupStyle} />
18290
+
18291
+ {/* Display mode \u2014 variable badges + text + overflow */}
18292
+ {showDisplay && (
18293
+ <div
18294
+ className={cn(
18295
+ "absolute cursor-text",
18296
+ !isExpanded && "inset-0 flex items-center",
18297
+ isExpanded && "inset-x-0 top-0 z-10",
18298
+ disabled && "opacity-50 cursor-not-allowed"
18299
+ )}
18300
+ onClick={() => {
18301
+ if (!disabled) inputRef.current?.focus();
18302
+ }}
18303
+ >
18304
+ <div
18305
+ ref={displayRef}
18306
+ className={cn(
18307
+ "flex items-center gap-1 px-2",
18308
+ !isExpanded && "flex-1 min-w-0 overflow-hidden",
18309
+ isExpanded && "flex-wrap bg-semantic-bg-primary border border-semantic-border-input rounded py-1.5 shadow-sm"
18310
+ )}
18311
+ >
18312
+ {segments.map((seg, i) =>
18313
+ seg.type === "text" ? (
18314
+ <span key={i} className="text-sm text-semantic-text-primary whitespace-pre shrink-0">{seg.content}</span>
18315
+ ) : (
18316
+ <span
18317
+ key={i}
18318
+ 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"
18319
+ >
18320
+ {seg.name}
18321
+ {onEditVariable && (
18322
+ <button
18323
+ type="button"
18324
+ onMouseDown={(e) => {
18325
+ e.preventDefault();
18326
+ e.stopPropagation();
18327
+ onEditVariable(seg.name);
18328
+ }}
18329
+ className="p-0.5 text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
18330
+ >
18331
+ <Pencil className="size-3" />
18332
+ </button>
18333
+ )}
18334
+ </span>
18335
+ )
18336
+ )}
18337
+ </div>
18338
+ {isOverflowing && !isExpanded && (
18339
+ <button
18340
+ type="button"
18341
+ onMouseDown={(e) => {
18342
+ e.preventDefault();
18343
+ e.stopPropagation();
18344
+ setIsExpanded(true);
18345
+ }}
18346
+ className="shrink-0 px-1 text-sm font-medium text-semantic-text-muted hover:text-semantic-text-primary"
18347
+ >
18348
+ ...
18349
+ </button>
18350
+ )}
18351
+ </div>
18352
+ )}
18353
+
18354
+ {/* VarPopup */}
18355
+ <VarPopup
18356
+ variables={filtered}
18357
+ variableGroups={trigger ? variableGroups : undefined}
18358
+ filterQuery={trigger?.query ?? ""}
18359
+ onSelect={handleSelect}
18360
+ onAddVariable={onAddVariable}
18361
+ onEditVariable={onEditVariable}
18362
+ style={popupStyle}
18363
+ />
17499
18364
  </div>
17500
18365
  );
17501
18366
  }
@@ -17505,7 +18370,7 @@ const inputCls = cn(
17505
18370
  "w-full h-[42px] px-4 text-base rounded border",
17506
18371
  "border-semantic-border-input bg-semantic-bg-primary",
17507
18372
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17508
- "outline-none hover:border-semantic-border-input-focus",
18373
+ "outline-none",
17509
18374
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17510
18375
  "disabled:opacity-50 disabled:cursor-not-allowed"
17511
18376
  );
@@ -17514,7 +18379,7 @@ const textareaCls = cn(
17514
18379
  "w-full px-4 py-2.5 text-base rounded border resize-none",
17515
18380
  "border-semantic-border-input bg-semantic-bg-primary",
17516
18381
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17517
- "outline-none hover:border-semantic-border-input-focus",
18382
+ "outline-none",
17518
18383
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17519
18384
  "disabled:opacity-50 disabled:cursor-not-allowed"
17520
18385
  );
@@ -17532,6 +18397,9 @@ function KeyValueTable({
17532
18397
  keyRegex,
17533
18398
  keyRegexError,
17534
18399
  sessionVariables = [],
18400
+ variableGroups,
18401
+ onAddVariable,
18402
+ onEditVariable,
17535
18403
  disabled = false,
17536
18404
  }: {
17537
18405
  rows: KeyValuePair[];
@@ -17543,6 +18411,9 @@ function KeyValueTable({
17543
18411
  keyRegex?: RegExp;
17544
18412
  keyRegexError?: string;
17545
18413
  sessionVariables?: string[];
18414
+ variableGroups?: VariableGroup[];
18415
+ onAddVariable?: () => void;
18416
+ onEditVariable?: (variable: string) => void;
17546
18417
  disabled?: boolean;
17547
18418
  }) {
17548
18419
  const update = (id: string, patch: Partial<KeyValuePair>) => {
@@ -17574,14 +18445,14 @@ function KeyValueTable({
17574
18445
 
17575
18446
  return (
17576
18447
  <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">
18448
+ <span className="text-sm text-semantic-text-muted">{label}</span>
18449
+ <div className="border border-semantic-border-layout rounded">
17579
18450
  {/* 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">
18451
+ <div className="hidden sm:flex border-b border-semantic-border-layout rounded-t">
18452
+ <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
18453
  Key
17583
18454
  </div>
17584
- <div className="flex-[2] min-w-0 px-3 py-2 text-xs font-semibold text-semantic-text-muted">
18455
+ <div className="flex-[2] min-w-0 px-3 py-2 text-sm font-semibold text-semantic-text-muted">
17585
18456
  Value
17586
18457
  </div>
17587
18458
  <div className="w-10 shrink-0" aria-hidden="true" />
@@ -17597,7 +18468,7 @@ function KeyValueTable({
17597
18468
  >
17598
18469
  {/* Key column \u2014 border-r on column (not input) so it aligns with header */}
17599
18470
  <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">
18471
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17601
18472
  Key
17602
18473
  </span>
17603
18474
  <input
@@ -17608,45 +18479,36 @@ function KeyValueTable({
17608
18479
  maxLength={keyMaxLength}
17609
18480
  disabled={disabled}
17610
18481
  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",
18482
+ "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
18483
  "disabled:opacity-50 disabled:cursor-not-allowed",
17613
- errors.key && "border-semantic-error-primary"
18484
+ errors.key && "text-semantic-error-primary"
17614
18485
  )}
17615
18486
  aria-invalid={Boolean(errors.key)}
17616
- aria-describedby={errors.key ? \`err-key-\${row.id}\` : undefined}
17617
18487
  />
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
18488
  </div>
17624
18489
 
17625
18490
  {/* Value column \u2014 uses VariableInput for {{ autocomplete */}
17626
18491
  <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">
18492
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17628
18493
  Value
17629
18494
  </span>
17630
18495
  <VariableInput
17631
18496
  value={row.value}
17632
18497
  onChange={(v) => update(row.id, { value: v })}
17633
18498
  sessionVariables={sessionVariables}
18499
+ variableGroups={variableGroups}
18500
+ onAddVariable={onAddVariable}
18501
+ onEditVariable={onEditVariable}
17634
18502
  placeholder="Type {{ to add variables"
17635
18503
  maxLength={valueMaxLength}
17636
18504
  disabled={disabled}
17637
18505
  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",
18506
+ "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
18507
  "disabled:opacity-50 disabled:cursor-not-allowed",
17640
- errors.value && "border-semantic-error-primary"
18508
+ errors.value && "text-semantic-error-primary"
17641
18509
  )}
17642
18510
  aria-invalid={Boolean(errors.value)}
17643
- aria-describedby={errors.value ? \`err-value-\${row.id}\` : undefined}
17644
18511
  />
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
18512
  </div>
17651
18513
 
17652
18514
  {/* Action column \u2014 delete aligned with row (same as KeyValueRow / knowledge-base-card) */}
@@ -17673,7 +18535,7 @@ function KeyValueTable({
17673
18535
  onClick={add}
17674
18536
  disabled={disabled}
17675
18537
  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",
18538
+ "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
18539
  disabled && "opacity-50 cursor-not-allowed"
17678
18540
  )}
17679
18541
  >
@@ -17681,15 +18543,35 @@ function KeyValueTable({
17681
18543
  <span>Add row</span>
17682
18544
  </button>
17683
18545
  </div>
18546
+
18547
+ {/* Collected row errors \u2014 shown below the table */}
18548
+ {(() => {
18549
+ const allErrors = rows
18550
+ .map((row) => {
18551
+ const errs = getErrors(row);
18552
+ const msgs: string[] = [];
18553
+ if (errs.key) msgs.push(errs.key);
18554
+ if (errs.value) msgs.push(errs.value);
18555
+ return msgs;
18556
+ })
18557
+ .flat();
18558
+ if (allErrors.length === 0) return null;
18559
+ // Deduplicate
18560
+ const unique = Array.from(new Set(allErrors));
18561
+ return (
18562
+ <div className="flex flex-col gap-0.5">
18563
+ {unique.map((msg) => (
18564
+ <p key={msg} className="m-0 text-sm text-semantic-error-primary">{msg}</p>
18565
+ ))}
18566
+ </div>
18567
+ );
18568
+ })()}
17684
18569
  </div>
17685
18570
  );
17686
18571
  }
17687
18572
 
17688
18573
  // \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
- >(
18574
+ export const CreateFunctionModal = React.forwardRef(
17693
18575
  (
17694
18576
  {
17695
18577
  open,
@@ -17703,10 +18585,13 @@ export const CreateFunctionModal = React.forwardRef<
17703
18585
  initialStep = 1,
17704
18586
  initialTab = "header",
17705
18587
  sessionVariables = DEFAULT_SESSION_VARIABLES,
18588
+ variableGroups,
18589
+ onAddVariable,
18590
+ onEditVariable,
17706
18591
  disabled = false,
17707
18592
  className,
17708
- },
17709
- ref
18593
+ }: CreateFunctionModalProps,
18594
+ ref: React.Ref<HTMLDivElement>
17710
18595
  ) => {
17711
18596
  const [step, setStep] = React.useState<1 | 2>(initialStep);
17712
18597
 
@@ -17727,6 +18612,35 @@ export const CreateFunctionModal = React.forwardRef<
17727
18612
  const [urlError, setUrlError] = React.useState("");
17728
18613
  const [bodyError, setBodyError] = React.useState("");
17729
18614
 
18615
+ // Variable modal state
18616
+ const [varModalOpen, setVarModalOpen] = React.useState(false);
18617
+ const [varModalMode, setVarModalMode] = React.useState<"create" | "edit">("create");
18618
+ const [varModalInitialData, setVarModalInitialData] = React.useState<VariableItem | undefined>();
18619
+
18620
+ const handleAddVariableClick = () => {
18621
+ setVarModalMode("create");
18622
+ setVarModalInitialData(undefined);
18623
+ setVarModalOpen(true);
18624
+ };
18625
+
18626
+ const handleEditVariableClick = (variableName: string) => {
18627
+ const variable = variableGroups
18628
+ ?.flatMap((g) => g.items)
18629
+ .find((item) => item.name === variableName);
18630
+ setVarModalMode("edit");
18631
+ setVarModalInitialData(variable ?? { name: variableName, editable: true });
18632
+ setVarModalOpen(true);
18633
+ };
18634
+
18635
+ const handleVariableSave = (data: VariableFormData) => {
18636
+ if (varModalMode === "create") {
18637
+ onAddVariable?.(data);
18638
+ } else {
18639
+ onEditVariable?.(varModalInitialData?.name ?? "", data);
18640
+ }
18641
+ setVarModalOpen(false);
18642
+ };
18643
+
17730
18644
  // Variable trigger state for URL and body
17731
18645
  const urlInputRef = React.useRef<HTMLInputElement>(null);
17732
18646
  const bodyTextareaRef = React.useRef<HTMLTextAreaElement>(null);
@@ -17821,14 +18735,7 @@ export const CreateFunctionModal = React.forwardRef<
17821
18735
  onOpenChange(false);
17822
18736
  }, [reset, onOpenChange]);
17823
18737
 
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]);
18738
+ // Body tab is always visible regardless of HTTP method
17832
18739
 
17833
18740
  const validateName = (value: string) => {
17834
18741
  if (value.trim() && !FUNCTION_NAME_REGEX.test(value.trim())) {
@@ -17963,11 +18870,10 @@ export const CreateFunctionModal = React.forwardRef<
17963
18870
  body: "Body",
17964
18871
  };
17965
18872
 
17966
- const visibleTabs: FunctionTabType[] = supportsBody
17967
- ? ["header", "queryParams", "body"]
17968
- : ["header", "queryParams"];
18873
+ const visibleTabs: FunctionTabType[] = ["header", "queryParams", "body"];
17969
18874
 
17970
18875
  return (
18876
+ <>
17971
18877
  <Dialog open={open} onOpenChange={onOpenChange}>
17972
18878
  <DialogContent
17973
18879
  ref={ref}
@@ -17975,7 +18881,7 @@ export const CreateFunctionModal = React.forwardRef<
17975
18881
  hideCloseButton
17976
18882
  className={cn(
17977
18883
  "flex flex-col gap-0 p-0 w-[calc(100vw-2rem)] sm:w-full",
17978
- "max-h-[calc(100svh-2rem)] overflow-hidden",
18884
+ "max-h-[calc(100vh-2rem)] overflow-hidden",
17979
18885
  className
17980
18886
  )}
17981
18887
  >
@@ -17995,7 +18901,7 @@ export const CreateFunctionModal = React.forwardRef<
17995
18901
  </div>
17996
18902
 
17997
18903
  {/* \u2500\u2500 Scrollable body \u2500\u2500 */}
17998
- <div className="flex-1 overflow-y-auto min-h-0 px-4 py-5 sm:px-6">
18904
+ <div className="flex-1 overflow-y-auto min-h-0 overscroll-contain px-4 py-5 sm:px-6">
17999
18905
  {/* \u2500 Step 1 \u2500 */}
18000
18906
  {step === 1 && (
18001
18907
  <div className="flex flex-col gap-5">
@@ -18022,44 +18928,33 @@ export const CreateFunctionModal = React.forwardRef<
18022
18928
  placeholder="Enter name of the function"
18023
18929
  className={cn(inputCls, "pr-16")}
18024
18930
  />
18025
- <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs italic text-semantic-text-muted pointer-events-none">
18931
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18026
18932
  {name.length}/{FUNCTION_NAME_MAX}
18027
18933
  </span>
18028
18934
  </div>
18029
18935
  {nameError && (
18030
- <p className="m-0 text-xs text-semantic-error-primary">{nameError}</p>
18936
+ <p className="m-0 text-sm text-semantic-error-primary">{nameError}</p>
18031
18937
  )}
18032
18938
  </div>
18033
18939
 
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>
18940
+ <Textarea
18941
+ id="fn-prompt"
18942
+ label="Prompt"
18943
+ required
18944
+ value={prompt}
18945
+ maxLength={promptMaxLength}
18946
+ showCount
18947
+ disabled={disabled}
18948
+ onChange={(e) => setPrompt(e.target.value)}
18949
+ placeholder="Enter the description of the function"
18950
+ rows={5}
18951
+ labelClassName="font-semibold text-semantic-text-primary"
18952
+ error={
18953
+ prompt.length > 0 && prompt.trim().length < promptMinLength
18954
+ ? \`Minimum \${promptMinLength} characters required\`
18955
+ : undefined
18956
+ }
18957
+ />
18063
18958
  </div>
18064
18959
  )}
18065
18960
 
@@ -18068,13 +18963,12 @@ export const CreateFunctionModal = React.forwardRef<
18068
18963
  <div className="flex flex-col gap-5">
18069
18964
  {/* API URL \u2014 always a single combined row */}
18070
18965
  <div className="flex flex-col gap-1.5">
18071
- <span className="text-xs text-semantic-text-muted tracking-[0.048px]">
18966
+ <span className="text-sm text-semantic-text-muted tracking-[0.048px]">
18072
18967
  API URL
18073
18968
  </span>
18074
18969
  <div
18075
18970
  className={cn(
18076
18971
  "flex h-[42px] rounded border border-semantic-border-input overflow-visible bg-semantic-bg-primary",
18077
- "hover:border-semantic-border-input-focus",
18078
18972
  "focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
18079
18973
  "transition-shadow"
18080
18974
  )}
@@ -18135,11 +19029,19 @@ export const CreateFunctionModal = React.forwardRef<
18135
19029
  disabled && "opacity-50 cursor-not-allowed"
18136
19030
  )}
18137
19031
  />
18138
- <VarPopup variables={filteredUrlVars} onSelect={handleUrlVarSelect} style={urlPopupStyle} />
19032
+ <VarPopup
19033
+ variables={filteredUrlVars}
19034
+ variableGroups={urlTrigger ? variableGroups : undefined}
19035
+ filterQuery={urlTrigger?.query ?? ""}
19036
+ onSelect={handleUrlVarSelect}
19037
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
19038
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
19039
+ style={urlPopupStyle}
19040
+ />
18139
19041
  </div>
18140
19042
  </div>
18141
19043
  {urlError && (
18142
- <p className="m-0 text-xs text-semantic-error-primary">{urlError}</p>
19044
+ <p className="m-0 text-sm text-semantic-error-primary">{urlError}</p>
18143
19045
  )}
18144
19046
  </div>
18145
19047
 
@@ -18179,6 +19081,9 @@ export const CreateFunctionModal = React.forwardRef<
18179
19081
  keyRegex={HEADER_KEY_REGEX}
18180
19082
  keyRegexError="Invalid header key. Use only alphanumeric and !#$%&'*+-.^_\`|~ characters."
18181
19083
  sessionVariables={sessionVariables}
19084
+ variableGroups={variableGroups}
19085
+ onAddVariable={handleAddVariableClick}
19086
+ onEditVariable={handleEditVariableClick}
18182
19087
  disabled={disabled}
18183
19088
  />
18184
19089
  )}
@@ -18198,12 +19103,15 @@ export const CreateFunctionModal = React.forwardRef<
18198
19103
  };
18199
19104
  }}
18200
19105
  sessionVariables={sessionVariables}
19106
+ variableGroups={variableGroups}
19107
+ onAddVariable={handleAddVariableClick}
19108
+ onEditVariable={handleEditVariableClick}
18201
19109
  disabled={disabled}
18202
19110
  />
18203
19111
  )}
18204
19112
  {activeTab === "body" && (
18205
19113
  <div className="flex flex-col gap-1.5">
18206
- <span className="text-xs text-semantic-text-muted">
19114
+ <span className="text-sm text-semantic-text-muted">
18207
19115
  Body
18208
19116
  </span>
18209
19117
  <div className={cn("relative")}>
@@ -18233,13 +19141,21 @@ export const CreateFunctionModal = React.forwardRef<
18233
19141
  rows={6}
18234
19142
  className={cn(textareaCls, "pb-7")}
18235
19143
  />
18236
- <span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted pointer-events-none">
19144
+ <span className="absolute bottom-2 right-3 text-sm text-semantic-text-muted pointer-events-none">
18237
19145
  {body.length}/{BODY_MAX}
18238
19146
  </span>
18239
- <VarPopup variables={filteredBodyVars} onSelect={handleBodyVarSelect} style={bodyPopupStyle} />
19147
+ <VarPopup
19148
+ variables={filteredBodyVars}
19149
+ variableGroups={bodyTrigger ? variableGroups : undefined}
19150
+ filterQuery={bodyTrigger?.query ?? ""}
19151
+ onSelect={handleBodyVarSelect}
19152
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
19153
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
19154
+ style={bodyPopupStyle}
19155
+ />
18240
19156
  </div>
18241
19157
  {bodyError && (
18242
- <p className="m-0 text-xs text-semantic-error-primary">{bodyError}</p>
19158
+ <p className="m-0 text-sm text-semantic-error-primary">{bodyError}</p>
18243
19159
  )}
18244
19160
  </div>
18245
19161
  )}
@@ -18248,7 +19164,7 @@ export const CreateFunctionModal = React.forwardRef<
18248
19164
  {/* Test Your API */}
18249
19165
  <div className="flex flex-col gap-4">
18250
19166
  <div className="flex flex-col gap-1.5">
18251
- <span className="text-xs font-semibold text-semantic-text-muted tracking-[0.048px]">
19167
+ <span className="text-sm font-semibold text-semantic-text-muted tracking-[0.048px]">
18252
19168
  Test Your API
18253
19169
  </span>
18254
19170
  <div className="border-t border-semantic-border-layout" />
@@ -18257,12 +19173,12 @@ export const CreateFunctionModal = React.forwardRef<
18257
19173
  {/* Variable test values \u2014 shown when URL/body/params contain {{variables}} */}
18258
19174
  {testableVars.length > 0 && (
18259
19175
  <div className="flex flex-col gap-2">
18260
- <span className="text-xs text-semantic-text-muted">
19176
+ <span className="text-sm text-semantic-text-muted">
18261
19177
  Variable values for testing
18262
19178
  </span>
18263
19179
  {testableVars.map((variable) => (
18264
19180
  <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]">
19181
+ <span className="text-sm text-semantic-text-muted font-mono shrink-0 min-w-[120px]">
18266
19182
  {variable}
18267
19183
  </span>
18268
19184
  <input
@@ -18292,7 +19208,7 @@ export const CreateFunctionModal = React.forwardRef<
18292
19208
  </button>
18293
19209
 
18294
19210
  <div className="flex flex-col gap-1.5">
18295
- <span className="text-xs text-semantic-text-muted">
19211
+ <span className="text-sm text-semantic-text-muted">
18296
19212
  Response from API
18297
19213
  </span>
18298
19214
  <textarea
@@ -18350,6 +19266,15 @@ export const CreateFunctionModal = React.forwardRef<
18350
19266
  </div>
18351
19267
  </DialogContent>
18352
19268
  </Dialog>
19269
+
19270
+ <VariableFormModal
19271
+ open={varModalOpen}
19272
+ onOpenChange={setVarModalOpen}
19273
+ mode={varModalMode}
19274
+ initialData={varModalInitialData}
19275
+ onSave={handleVariableSave}
19276
+ />
19277
+ </>
18353
19278
  );
18354
19279
  }
18355
19280
  );
@@ -18561,7 +19486,7 @@ const DEFAULT_LANGUAGE_OPTIONS: LanguageOption[] = [
18561
19486
 
18562
19487
  // \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
19488
 
18564
- const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
19489
+ const BotIdentityCard = React.forwardRef(
18565
19490
  (
18566
19491
  {
18567
19492
  data,
@@ -18575,8 +19500,8 @@ const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
18575
19500
  playingVoice,
18576
19501
  disabled,
18577
19502
  className,
18578
- },
18579
- ref
19503
+ }: BotIdentityCardProps,
19504
+ ref: React.Ref<HTMLDivElement>
18580
19505
  ) => {
18581
19506
  return (
18582
19507
  <div
@@ -18878,7 +19803,6 @@ function VarPopup({
18878
19803
  key={v}
18879
19804
  type="button"
18880
19805
  role="option"
18881
- aria-selected={false}
18882
19806
  onMouseDown={(e) => {
18883
19807
  e.preventDefault(); // keep textarea focused so blur doesn't close popup first
18884
19808
  onSelect(v);
@@ -18922,7 +19846,7 @@ function SectionCard({
18922
19846
 
18923
19847
  // \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
19848
 
18925
- const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
19849
+ const BotBehaviorCard = React.forwardRef(
18926
19850
  (
18927
19851
  {
18928
19852
  data,
@@ -18932,8 +19856,8 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
18932
19856
  maxLength = 5000,
18933
19857
  disabled,
18934
19858
  className,
18935
- },
18936
- ref
19859
+ }: BotBehaviorCardProps,
19860
+ ref: React.Ref<HTMLDivElement>
18937
19861
  ) => {
18938
19862
  const prompt = data.systemPrompt ?? "";
18939
19863
  const MAX = maxLength;
@@ -19117,7 +20041,7 @@ import {
19117
20041
  TooltipTrigger,
19118
20042
  } from "../tooltip";
19119
20043
  import { BOT_KNOWLEDGE_STATUS } from "./types";
19120
- import type { KnowledgeBaseFile, KnowledgeFileStatus } from "./types";
20044
+ import type { KnowledgeBaseFile } from "./types";
19121
20045
 
19122
20046
  // \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19123
20047
 
@@ -19151,7 +20075,7 @@ export interface KnowledgeBaseCardProps {
19151
20075
  // \u2500\u2500\u2500 Status config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
19152
20076
 
19153
20077
  type BadgeVariant = "default" | "active" | "destructive";
19154
- const STATUS_CONFIG: Record<KnowledgeFileStatus, { label: string; variant: BadgeVariant }> = {
20078
+ const STATUS_CONFIG: Record<BOT_KNOWLEDGE_STATUS, { label: string; variant: BadgeVariant }> = {
19155
20079
  [BOT_KNOWLEDGE_STATUS.PENDING]: { label: "Pending", variant: "default" },
19156
20080
  [BOT_KNOWLEDGE_STATUS.READY]: { label: "Ready", variant: "active" },
19157
20081
  [BOT_KNOWLEDGE_STATUS.PROCESSING]: { label: "Processing", variant: "active" },
@@ -19160,7 +20084,7 @@ const STATUS_CONFIG: Record<KnowledgeFileStatus, { label: string; variant: Badge
19160
20084
 
19161
20085
  // \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
20086
 
19163
- const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProps>(
20087
+ const KnowledgeBaseCard = React.forwardRef(
19164
20088
  (
19165
20089
  {
19166
20090
  files,
@@ -19172,8 +20096,8 @@ const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProp
19172
20096
  downloadDisabled,
19173
20097
  deleteDisabled,
19174
20098
  className,
19175
- },
19176
- ref
20099
+ }: KnowledgeBaseCardProps,
20100
+ ref: React.Ref<HTMLDivElement>
19177
20101
  ) => {
19178
20102
  return (
19179
20103
  <div
@@ -19325,8 +20249,8 @@ export interface FunctionsCardProps {
19325
20249
 
19326
20250
  // \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
20251
 
19328
- const FunctionsCard = React.forwardRef<HTMLDivElement, FunctionsCardProps>(
19329
- ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }, ref) => {
20252
+ const FunctionsCard = React.forwardRef(
20253
+ ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }: FunctionsCardProps, ref: React.Ref<HTMLDivElement>) => {
19330
20254
  return (
19331
20255
  <div
19332
20256
  ref={ref}
@@ -19512,8 +20436,8 @@ function Field({
19512
20436
 
19513
20437
  // \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
20438
 
19515
- const FrustrationHandoverCard = React.forwardRef<HTMLDivElement, FrustrationHandoverCardProps>(
19516
- ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }, ref) => {
20439
+ const FrustrationHandoverCard = React.forwardRef(
20440
+ ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }: FrustrationHandoverCardProps, ref: React.Ref<HTMLDivElement>) => {
19517
20441
  return (
19518
20442
  <div
19519
20443
  ref={ref}
@@ -19686,7 +20610,7 @@ function NumberSpinner({
19686
20610
 
19687
20611
  // \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
20612
 
19689
- const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCardProps>(
20613
+ const AdvancedSettingsCard = React.forwardRef(
19690
20614
  (
19691
20615
  {
19692
20616
  data,
@@ -19697,8 +20621,8 @@ const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCa
19697
20621
  callEndThresholdMax = 10,
19698
20622
  disabled,
19699
20623
  className,
19700
- },
19701
- ref
20624
+ }: AdvancedSettingsCardProps,
20625
+ ref: React.Ref<HTMLDivElement>
19702
20626
  ) => {
19703
20627
  return (
19704
20628
  <div
@@ -19864,10 +20788,7 @@ function PromptField({
19864
20788
 
19865
20789
  // \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
20790
 
19867
- const FallbackPromptsCard = React.forwardRef<
19868
- HTMLDivElement,
19869
- FallbackPromptsCardProps
19870
- >(
20791
+ const FallbackPromptsCard = React.forwardRef(
19871
20792
  (
19872
20793
  {
19873
20794
  data,
@@ -19878,8 +20799,8 @@ const FallbackPromptsCard = React.forwardRef<
19878
20799
  disabled,
19879
20800
  defaultOpen = false,
19880
20801
  className,
19881
- },
19882
- ref
20802
+ }: FallbackPromptsCardProps,
20803
+ ref: React.Ref<HTMLDivElement>
19883
20804
  ) => {
19884
20805
  return (
19885
20806
  <div
@@ -19950,7 +20871,9 @@ export const BOT_KNOWLEDGE_STATUS = {
19950
20871
  FAILED: "failed",
19951
20872
  } as const;
19952
20873
 
19953
- export type KnowledgeFileStatus = typeof BOT_KNOWLEDGE_STATUS[keyof typeof BOT_KNOWLEDGE_STATUS];
20874
+ export type BOT_KNOWLEDGE_STATUS = typeof BOT_KNOWLEDGE_STATUS[keyof typeof BOT_KNOWLEDGE_STATUS];
20875
+
20876
+ export type KnowledgeFileStatus = BOT_KNOWLEDGE_STATUS;
19954
20877
 
19955
20878
  export interface KeyValuePair {
19956
20879
  id: string;
@@ -19958,6 +20881,35 @@ export interface KeyValuePair {
19958
20881
  value: string;
19959
20882
  }
19960
20883
 
20884
+ /** A single variable shown in the {{ autocomplete popup */
20885
+ export interface VariableItem {
20886
+ /** Display name (e.g., "Order_id") */
20887
+ name: string;
20888
+ /** Value inserted into the input. Defaults to \`{{name}}\` if omitted */
20889
+ value?: string;
20890
+ /** When true, an edit icon is shown next to this variable */
20891
+ editable?: boolean;
20892
+ /** Description of what this variable represents */
20893
+ description?: string;
20894
+ /** Whether this variable is required */
20895
+ required?: boolean;
20896
+ }
20897
+
20898
+ /** Data shape for creating or editing a variable */
20899
+ export interface VariableFormData {
20900
+ name: string;
20901
+ description?: string;
20902
+ required?: boolean;
20903
+ }
20904
+
20905
+ /** A labelled group of variables in the autocomplete popup */
20906
+ export interface VariableGroup {
20907
+ /** Group header text (e.g., "Function variables", "Session variables") */
20908
+ label: string;
20909
+ /** Variables in this group */
20910
+ items: VariableItem[];
20911
+ }
20912
+
19961
20913
  export interface FunctionItem {
19962
20914
  id: string;
19963
20915
  name: string;
@@ -20008,6 +20960,12 @@ export interface CreateFunctionModalProps {
20008
20960
  initialTab?: FunctionTabType;
20009
20961
  /** Session variables available for {{ autocomplete in URL, body, header values, and query param values */
20010
20962
  sessionVariables?: string[];
20963
+ /** Grouped variables shown in the {{ autocomplete popup (overrides flat list display when provided) */
20964
+ variableGroups?: VariableGroup[];
20965
+ /** Called when user saves a new variable from the autocomplete popup */
20966
+ onAddVariable?: (data: VariableFormData) => void;
20967
+ /** Called when user edits a variable from the autocomplete popup */
20968
+ onEditVariable?: (originalName: string, data: VariableFormData) => void;
20011
20969
  /** When true, all form fields are disabled (view mode) but Next is enabled so user can browse steps */
20012
20970
  disabled?: boolean;
20013
20971
  className?: string;
@@ -20168,6 +21126,9 @@ export type {
20168
21126
  HttpMethod,
20169
21127
  FunctionTabType,
20170
21128
  SelectOption,
21129
+ VariableItem,
21130
+ VariableGroup,
21131
+ VariableFormData,
20171
21132
  } from "./types";
20172
21133
  `, prefix)
20173
21134
  }
@@ -20237,7 +21198,7 @@ function formatCurrency(amount: number, symbol: string = "\u20B9"): string {
20237
21198
  * />
20238
21199
  * \`\`\`
20239
21200
  */
20240
- export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
21201
+ export const WalletTopup = React.forwardRef(
20241
21202
  (
20242
21203
  {
20243
21204
  title = "Instant wallet top-up",
@@ -20284,8 +21245,8 @@ export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
20284
21245
  open,
20285
21246
  onOpenChange,
20286
21247
  className,
20287
- },
20288
- ref
21248
+ }: WalletTopupProps,
21249
+ ref: React.Ref<HTMLDivElement>
20289
21250
  ) => {
20290
21251
  const isOpenControlled = open !== undefined;
20291
21252
 
@@ -22287,22 +23248,99 @@ async function sync(options) {
22287
23248
  }
22288
23249
  let selectedToAdd = toAdd;
22289
23250
  let selectedToUpdate = toUpdate;
23251
+ const CUSTOM_GROUPS = {
23252
+ "attachment-preview": "Chat",
23253
+ "audio-media": "Chat",
23254
+ "carousel-media": "Chat",
23255
+ "chat-bubble": "Chat",
23256
+ "chat-composer": "Chat",
23257
+ "contact-list-item": "Chat",
23258
+ "date-divider": "Chat",
23259
+ "doc-media": "Chat",
23260
+ "image-media": "Chat",
23261
+ "reply-quote": "Chat",
23262
+ "system-message": "Chat",
23263
+ "unread-separator": "Chat",
23264
+ "video-media": "Chat",
23265
+ "event-selector": "Webhook",
23266
+ "key-value-input": "Webhook",
23267
+ "api-feature-card": "Webhook",
23268
+ "endpoint-details": "Webhook",
23269
+ "alert-configuration": "Webhook",
23270
+ "auto-pay-setup": "Plan & Payment",
23271
+ "bank-details": "Plan & Payment",
23272
+ "date-range-modal": "Plan & Payment",
23273
+ "payment-option-card": "Plan & Payment",
23274
+ "plan-upgrade-modal": "Plan & Payment",
23275
+ "plan-upgrade-summary-modal": "Plan & Payment",
23276
+ "payment-summary": "Plan & Payment",
23277
+ "let-us-drive-card": "Plan & Payment",
23278
+ "power-up-card": "Plan & Payment",
23279
+ "pricing-card": "Plan & Payment",
23280
+ "pricing-page": "Plan & Payment",
23281
+ "pricing-toggle": "Plan & Payment",
23282
+ "talk-to-us-modal": "Plan & Payment",
23283
+ "wallet-topup": "Plan & Payment",
23284
+ "file-upload-modal": "Plan & Payment",
23285
+ "plan-detail-modal": "Plan & Payment",
23286
+ "bots": "AI Bot",
23287
+ "ivr-bot": "AI Bot"
23288
+ };
22290
23289
  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);
23290
+ const uiToAdd = toAdd.filter((c) => !CUSTOM_GROUPS[c]);
23291
+ const customToAdd = toAdd.filter((c) => !!CUSTOM_GROUPS[c]);
23292
+ const picked = [];
23293
+ if (uiToAdd.length > 0) {
23294
+ console.log(chalk5.cyan.bold(" \u2500\u2500 Components \u2500\u2500\n"));
23295
+ const { selected } = await prompts3({
23296
+ type: "multiselect",
23297
+ name: "selected",
23298
+ message: "Select new components to add",
23299
+ choices: uiToAdd.map((c) => ({
23300
+ title: c,
23301
+ value: c,
23302
+ selected: false
23303
+ }))
23304
+ });
23305
+ if (!selected) {
23306
+ console.log(chalk5.yellow("\n Sync cancelled.\n"));
23307
+ process.exit(0);
23308
+ }
23309
+ picked.push(...selected);
23310
+ }
23311
+ if (customToAdd.length > 0) {
23312
+ const grouped = /* @__PURE__ */ new Map();
23313
+ for (const c of customToAdd) {
23314
+ const group = CUSTOM_GROUPS[c] || "Other";
23315
+ if (!grouped.has(group)) grouped.set(group, []);
23316
+ grouped.get(group).push(c);
23317
+ }
23318
+ const sortedGroups = [...grouped.keys()].sort();
23319
+ console.log(chalk5.cyan.bold("\n \u2500\u2500 Custom \u2500\u2500\n"));
23320
+ const { selected } = await prompts3({
23321
+ type: "multiselect",
23322
+ name: "selected",
23323
+ message: "Select custom component folders to add",
23324
+ choices: sortedGroups.map((group) => {
23325
+ const components = grouped.get(group);
23326
+ const count = components.length;
23327
+ return {
23328
+ title: group,
23329
+ value: group,
23330
+ selected: false,
23331
+ description: `${count} component${count === 1 ? "" : "s"}`
23332
+ };
23333
+ })
23334
+ });
23335
+ if (!selected) {
23336
+ console.log(chalk5.yellow("\n Sync cancelled.\n"));
23337
+ process.exit(0);
23338
+ }
23339
+ for (const group of selected) {
23340
+ picked.push(...grouped.get(group));
23341
+ }
22304
23342
  }
22305
- selectedToAdd = selected;
23343
+ selectedToAdd = picked;
22306
23344
  }
22307
23345
  if (!options.yes && toUpdate.length > 0) {
22308
23346
  const { selected } = await prompts3({