myoperator-ui 0.0.216-beta.2 → 0.0.216-beta.20

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 +1594 -637
  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] =
@@ -3812,7 +4372,7 @@ export interface CreatableSelectProps
3812
4372
  maxLength?: number
3813
4373
  }
3814
4374
 
3815
- const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
4375
+ const CreatableSelect = React.forwardRef(
3816
4376
  (
3817
4377
  {
3818
4378
  className,
@@ -3825,8 +4385,8 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
3825
4385
  disabled = false,
3826
4386
  maxLength,
3827
4387
  ...props
3828
- },
3829
- ref
4388
+ }: CreatableSelectProps,
4389
+ ref: React.Ref<HTMLDivElement>
3830
4390
  ) => {
3831
4391
  const [open, setOpen] = React.useState(false)
3832
4392
  const [search, setSearch] = React.useState("")
@@ -4157,10 +4717,7 @@ export interface CreatableMultiSelectProps
4157
4717
  maxLengthPerItem?: number
4158
4718
  }
4159
4719
 
4160
- const CreatableMultiSelect = React.forwardRef<
4161
- HTMLDivElement,
4162
- CreatableMultiSelectProps
4163
- >(
4720
+ const CreatableMultiSelect = React.forwardRef(
4164
4721
  (
4165
4722
  {
4166
4723
  className,
@@ -4175,8 +4732,8 @@ const CreatableMultiSelect = React.forwardRef<
4175
4732
  maxItems,
4176
4733
  maxLengthPerItem,
4177
4734
  ...props
4178
- },
4179
- ref
4735
+ }: CreatableMultiSelectProps,
4736
+ ref: React.Ref<HTMLDivElement>
4180
4737
  ) => {
4181
4738
  const [isOpen, setIsOpen] = React.useState(false)
4182
4739
  const [inputValue, setInputValue] = React.useState("")
@@ -4471,8 +5028,8 @@ export interface TableProps
4471
5028
  wrapContent?: boolean;
4472
5029
  }
4473
5030
 
4474
- const Table = React.forwardRef<HTMLTableElement, TableProps>(
4475
- ({ className, size, withoutBorder, wrapContent, ...props }, ref) => (
5031
+ const Table = React.forwardRef(
5032
+ ({ className, size, withoutBorder, wrapContent, ...props }: TableProps, ref: React.Ref<HTMLTableElement>) => (
4476
5033
  <div
4477
5034
  className={cn(
4478
5035
  "relative w-full overflow-auto",
@@ -4493,10 +5050,7 @@ const Table = React.forwardRef<HTMLTableElement, TableProps>(
4493
5050
  );
4494
5051
  Table.displayName = "Table";
4495
5052
 
4496
- const TableHeader = React.forwardRef<
4497
- HTMLTableSectionElement,
4498
- React.HTMLAttributes<HTMLTableSectionElement>
4499
- >(({ className, ...props }, ref) => (
5053
+ const TableHeader = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>, ref: React.Ref<HTMLTableSectionElement>) => (
4500
5054
  <thead
4501
5055
  ref={ref}
4502
5056
  className={cn("bg-[var(--color-neutral-100)] [&_tr]:border-b", className)}
@@ -4515,8 +5069,8 @@ export interface TableBodyProps
4515
5069
  loadingColumns?: number;
4516
5070
  }
4517
5071
 
4518
- const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
4519
- ({ 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>) => (
4520
5074
  <tbody
4521
5075
  ref={ref}
4522
5076
  className={cn("[&_tr:last-child]:border-0", className)}
@@ -4532,10 +5086,7 @@ const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
4532
5086
  );
4533
5087
  TableBody.displayName = "TableBody";
4534
5088
 
4535
- const TableFooter = React.forwardRef<
4536
- HTMLTableSectionElement,
4537
- React.HTMLAttributes<HTMLTableSectionElement>
4538
- >(({ className, ...props }, ref) => (
5089
+ const TableFooter = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>, ref: React.Ref<HTMLTableSectionElement>) => (
4539
5090
  <tfoot
4540
5091
  ref={ref}
4541
5092
  className={cn(
@@ -4552,8 +5103,8 @@ export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement>
4552
5103
  highlighted?: boolean;
4553
5104
  }
4554
5105
 
4555
- const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
4556
- ({ className, highlighted, ...props }, ref) => (
5106
+ const TableRow = React.forwardRef(
5107
+ ({ className, highlighted, ...props }: TableRowProps, ref: React.Ref<HTMLTableRowElement>) => (
4557
5108
  <tr
4558
5109
  ref={ref}
4559
5110
  className={cn(
@@ -4578,10 +5129,10 @@ export interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElem
4578
5129
  infoTooltip?: string;
4579
5130
  }
4580
5131
 
4581
- const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
5132
+ const TableHead = React.forwardRef(
4582
5133
  (
4583
- { className, sticky, sortDirection, infoTooltip, children, ...props },
4584
- ref
5134
+ { className, sticky, sortDirection, infoTooltip, children, ...props }: TableHeadProps,
5135
+ ref: React.Ref<HTMLTableCellElement>
4585
5136
  ) => (
4586
5137
  <th
4587
5138
  ref={ref}
@@ -4619,8 +5170,8 @@ export interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElem
4619
5170
  sticky?: boolean;
4620
5171
  }
4621
5172
 
4622
- const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
4623
- ({ className, sticky, ...props }, ref) => (
5173
+ const TableCell = React.forwardRef(
5174
+ ({ className, sticky, ...props }: TableCellProps, ref: React.Ref<HTMLTableCellElement>) => (
4624
5175
  <td
4625
5176
  ref={ref}
4626
5177
  className={cn(
@@ -4634,10 +5185,7 @@ const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
4634
5185
  );
4635
5186
  TableCell.displayName = "TableCell";
4636
5187
 
4637
- const TableCaption = React.forwardRef<
4638
- HTMLTableCaptionElement,
4639
- React.HTMLAttributes<HTMLTableCaptionElement>
4640
- >(({ className, ...props }, ref) => (
5188
+ const TableCaption = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLTableCaptionElement>, ref: React.Ref<HTMLTableCaptionElement>) => (
4641
5189
  <caption
4642
5190
  ref={ref}
4643
5191
  className={cn("mt-4 text-sm text-semantic-text-muted", className)}
@@ -4726,8 +5274,8 @@ export interface TableToggleProps extends Omit<SwitchProps, "size"> {
4726
5274
  size?: "sm" | "default";
4727
5275
  }
4728
5276
 
4729
- const TableToggle = React.forwardRef<HTMLButtonElement, TableToggleProps>(
4730
- ({ size = "sm", ...props }, ref) => (
5277
+ const TableToggle = React.forwardRef(
5278
+ ({ size = "sm", ...props }: TableToggleProps, ref: React.Ref<HTMLButtonElement>) => (
4731
5279
  <Switch ref={ref} size={size} {...props} />
4732
5280
  )
4733
5281
  );
@@ -4792,10 +5340,7 @@ export interface TabsListProps
4792
5340
  fullWidth?: boolean
4793
5341
  }
4794
5342
 
4795
- const TabsList = React.forwardRef<
4796
- React.ComponentRef<typeof TabsPrimitive.List>,
4797
- TabsListProps
4798
- >(({ className, fullWidth, ...props }, ref) => (
5343
+ const TabsList = React.forwardRef(({ className, fullWidth, ...props }: TabsListProps, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.List>>) => (
4799
5344
  <TabsPrimitive.List
4800
5345
  ref={ref}
4801
5346
  className={cn(
@@ -4808,10 +5353,7 @@ const TabsList = React.forwardRef<
4808
5353
  ))
4809
5354
  TabsList.displayName = TabsPrimitive.List.displayName
4810
5355
 
4811
- const TabsTrigger = React.forwardRef<
4812
- React.ComponentRef<typeof TabsPrimitive.Trigger>,
4813
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
4814
- >(({ className, ...props }, ref) => (
5356
+ const TabsTrigger = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.Trigger>>) => (
4815
5357
  <TabsPrimitive.Trigger
4816
5358
  ref={ref}
4817
5359
  className={cn(
@@ -4826,10 +5368,7 @@ const TabsTrigger = React.forwardRef<
4826
5368
  ))
4827
5369
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
4828
5370
 
4829
- const TabsContent = React.forwardRef<
4830
- React.ComponentRef<typeof TabsPrimitive.Content>,
4831
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
4832
- >(({ className, ...props }, ref) => (
5371
+ const TabsContent = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>, ref: React.Ref<React.ComponentRef<typeof TabsPrimitive.Content>>) => (
4833
5372
  <TabsPrimitive.Content
4834
5373
  ref={ref}
4835
5374
  className={cn(
@@ -4876,10 +5415,7 @@ const DialogPortal = DialogPrimitive.Portal;
4876
5415
 
4877
5416
  const DialogClose = DialogPrimitive.Close;
4878
5417
 
4879
- const DialogOverlay = React.forwardRef<
4880
- React.ElementRef<typeof DialogPrimitive.Overlay>,
4881
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
4882
- >(({ className, ...props }, ref) => (
5418
+ const DialogOverlay = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>) => (
4883
5419
  <DialogPrimitive.Overlay
4884
5420
  ref={ref}
4885
5421
  className={cn(
@@ -4937,10 +5473,7 @@ const hasDialogDescription = (children: React.ReactNode): boolean => {
4937
5473
  return found;
4938
5474
  };
4939
5475
 
4940
- const DialogContent = React.forwardRef<
4941
- React.ElementRef<typeof DialogPrimitive.Content>,
4942
- DialogContentProps
4943
- >(({ 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>>) => {
4944
5477
  const hasDescription = hasDialogDescription(children);
4945
5478
 
4946
5479
  return (
@@ -4998,10 +5531,7 @@ const DialogFooter = ({
4998
5531
  );
4999
5532
  DialogFooter.displayName = "DialogFooter";
5000
5533
 
5001
- const DialogTitle = React.forwardRef<
5002
- React.ElementRef<typeof DialogPrimitive.Title>,
5003
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
5004
- >(({ className, ...props }, ref) => (
5534
+ const DialogTitle = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Title>>) => (
5005
5535
  <DialogPrimitive.Title
5006
5536
  ref={ref}
5007
5537
  className={cn(
@@ -5013,10 +5543,7 @@ const DialogTitle = React.forwardRef<
5013
5543
  ));
5014
5544
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5015
5545
 
5016
- const DialogDescription = React.forwardRef<
5017
- React.ElementRef<typeof DialogPrimitive.Description>,
5018
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
5019
- >(({ className, ...props }, ref) => (
5546
+ const DialogDescription = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>, ref: React.Ref<React.ElementRef<typeof DialogPrimitive.Description>>) => (
5020
5547
  <DialogPrimitive.Description
5021
5548
  ref={ref}
5022
5549
  className={cn("text-sm text-muted-foreground", className)}
@@ -5064,10 +5591,7 @@ import { cn } from "../../lib/utils";
5064
5591
 
5065
5592
  const DropdownMenu = DropdownMenuPrimitive.Root;
5066
5593
 
5067
- const DropdownMenuTrigger = React.forwardRef<
5068
- React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
5069
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
5070
- >(({ className, ...props }, ref) => (
5594
+ const DropdownMenuTrigger = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Trigger>>) => (
5071
5595
  <DropdownMenuPrimitive.Trigger
5072
5596
  ref={ref}
5073
5597
  className={cn("focus-visible:outline-none focus-visible:ring-0", className)}
@@ -5084,12 +5608,9 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
5084
5608
 
5085
5609
  const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
5086
5610
 
5087
- const DropdownMenuSubTrigger = React.forwardRef<
5088
- React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
5089
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
5611
+ const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
5090
5612
  inset?: boolean;
5091
- }
5092
- >(({ className, inset, children, ...props }, ref) => (
5613
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>>) => (
5093
5614
  <DropdownMenuPrimitive.SubTrigger
5094
5615
  ref={ref}
5095
5616
  className={cn(
@@ -5106,10 +5627,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
5106
5627
  DropdownMenuSubTrigger.displayName =
5107
5628
  DropdownMenuPrimitive.SubTrigger.displayName;
5108
5629
 
5109
- const DropdownMenuSubContent = React.forwardRef<
5110
- React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
5111
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
5112
- >(({ className, ...props }, ref) => (
5630
+ const DropdownMenuSubContent = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.SubContent>>) => (
5113
5631
  <DropdownMenuPrimitive.SubContent
5114
5632
  ref={ref}
5115
5633
  className={cn(
@@ -5122,10 +5640,7 @@ const DropdownMenuSubContent = React.forwardRef<
5122
5640
  DropdownMenuSubContent.displayName =
5123
5641
  DropdownMenuPrimitive.SubContent.displayName;
5124
5642
 
5125
- const DropdownMenuContent = React.forwardRef<
5126
- React.ElementRef<typeof DropdownMenuPrimitive.Content>,
5127
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
5128
- >(({ 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>>) => (
5129
5644
  <DropdownMenuPrimitive.Portal>
5130
5645
  <DropdownMenuPrimitive.Content
5131
5646
  ref={ref}
@@ -5141,16 +5656,13 @@ const DropdownMenuContent = React.forwardRef<
5141
5656
  ));
5142
5657
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
5143
5658
 
5144
- const DropdownMenuItem = React.forwardRef<
5145
- React.ElementRef<typeof DropdownMenuPrimitive.Item>,
5146
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
5659
+ const DropdownMenuItem = React.forwardRef(({ className, inset, children, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
5147
5660
  inset?: boolean;
5148
5661
  /** Secondary text displayed below children */
5149
5662
  description?: string;
5150
5663
  /** Content displayed at the right edge of the item */
5151
5664
  suffix?: React.ReactNode;
5152
- }
5153
- >(({ className, inset, children, description, suffix, ...props }, ref) => (
5665
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Item>>) => (
5154
5666
  <DropdownMenuPrimitive.Item
5155
5667
  ref={ref}
5156
5668
  className={cn(
@@ -5175,15 +5687,12 @@ const DropdownMenuItem = React.forwardRef<
5175
5687
  ));
5176
5688
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
5177
5689
 
5178
- const DropdownMenuCheckboxItem = React.forwardRef<
5179
- React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
5180
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
5690
+ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
5181
5691
  /** Secondary text displayed below children */
5182
5692
  description?: string;
5183
5693
  /** Content displayed at the right edge of the item */
5184
5694
  suffix?: React.ReactNode;
5185
- }
5186
- >(({ className, children, checked, description, suffix, ...props }, ref) => (
5695
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>>) => (
5187
5696
  <DropdownMenuPrimitive.CheckboxItem
5188
5697
  ref={ref}
5189
5698
  className={cn(
@@ -5214,15 +5723,12 @@ const DropdownMenuCheckboxItem = React.forwardRef<
5214
5723
  DropdownMenuCheckboxItem.displayName =
5215
5724
  DropdownMenuPrimitive.CheckboxItem.displayName;
5216
5725
 
5217
- const DropdownMenuRadioItem = React.forwardRef<
5218
- React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
5219
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
5726
+ const DropdownMenuRadioItem = React.forwardRef(({ className, children, description, suffix, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
5220
5727
  /** Secondary text displayed below children */
5221
5728
  description?: string;
5222
5729
  /** Content displayed at the right edge of the item */
5223
5730
  suffix?: React.ReactNode;
5224
- }
5225
- >(({ className, children, description, suffix, ...props }, ref) => (
5731
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>>) => (
5226
5732
  <DropdownMenuPrimitive.RadioItem
5227
5733
  ref={ref}
5228
5734
  className={cn(
@@ -5251,12 +5757,9 @@ const DropdownMenuRadioItem = React.forwardRef<
5251
5757
  ));
5252
5758
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
5253
5759
 
5254
- const DropdownMenuLabel = React.forwardRef<
5255
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
5256
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
5760
+ const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
5257
5761
  inset?: boolean;
5258
- }
5259
- >(({ className, inset, ...props }, ref) => (
5762
+ }, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Label>>) => (
5260
5763
  <DropdownMenuPrimitive.Label
5261
5764
  ref={ref}
5262
5765
  className={cn(
@@ -5269,10 +5772,7 @@ const DropdownMenuLabel = React.forwardRef<
5269
5772
  ));
5270
5773
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
5271
5774
 
5272
- const DropdownMenuSeparator = React.forwardRef<
5273
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
5274
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
5275
- >(({ className, ...props }, ref) => (
5775
+ const DropdownMenuSeparator = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>, ref: React.Ref<React.ElementRef<typeof DropdownMenuPrimitive.Separator>>) => (
5276
5776
  <DropdownMenuPrimitive.Separator
5277
5777
  ref={ref}
5278
5778
  className={cn("-mx-1 my-1 h-px bg-semantic-border-layout", className)}
@@ -5339,10 +5839,7 @@ const Tooltip = TooltipPrimitive.Root;
5339
5839
 
5340
5840
  const TooltipTrigger = TooltipPrimitive.Trigger;
5341
5841
 
5342
- const TooltipContent = React.forwardRef<
5343
- React.ElementRef<typeof TooltipPrimitive.Content>,
5344
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
5345
- >(({ 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>>) => (
5346
5843
  <TooltipPrimitive.Portal>
5347
5844
  <TooltipPrimitive.Content
5348
5845
  ref={ref}
@@ -5357,10 +5854,7 @@ const TooltipContent = React.forwardRef<
5357
5854
  ));
5358
5855
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
5359
5856
 
5360
- const TooltipArrow = React.forwardRef<
5361
- React.ElementRef<typeof TooltipPrimitive.Arrow>,
5362
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
5363
- >(({ className, ...props }, ref) => (
5857
+ const TooltipArrow = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>, ref: React.Ref<React.ElementRef<typeof TooltipPrimitive.Arrow>>) => (
5364
5858
  <TooltipPrimitive.Arrow
5365
5859
  ref={ref}
5366
5860
  className={cn("fill-semantic-primary", className)}
@@ -5464,10 +5958,7 @@ export interface DeleteConfirmationModalProps {
5464
5958
  * />
5465
5959
  * \`\`\`
5466
5960
  */
5467
- const DeleteConfirmationModal = React.forwardRef<
5468
- HTMLDivElement,
5469
- DeleteConfirmationModalProps
5470
- >(
5961
+ const DeleteConfirmationModal = React.forwardRef(
5471
5962
  (
5472
5963
  {
5473
5964
  open,
@@ -5483,8 +5974,8 @@ const DeleteConfirmationModal = React.forwardRef<
5483
5974
  cancelButtonText = "Cancel",
5484
5975
  trigger,
5485
5976
  className,
5486
- },
5487
- ref
5977
+ }: DeleteConfirmationModalProps,
5978
+ ref: React.Ref<HTMLDivElement>
5488
5979
  ) => {
5489
5980
  const [inputValue, setInputValue] = React.useState("");
5490
5981
  const isConfirmEnabled = inputValue === confirmText;
@@ -5652,10 +6143,7 @@ export interface ConfirmationModalProps {
5652
6143
  * />
5653
6144
  * \`\`\`
5654
6145
  */
5655
- const ConfirmationModal = React.forwardRef<
5656
- HTMLDivElement,
5657
- ConfirmationModalProps
5658
- >(
6146
+ const ConfirmationModal = React.forwardRef(
5659
6147
  (
5660
6148
  {
5661
6149
  open,
@@ -5670,8 +6158,8 @@ const ConfirmationModal = React.forwardRef<
5670
6158
  cancelButtonText = "Cancel",
5671
6159
  trigger,
5672
6160
  className,
5673
- },
5674
- ref
6161
+ }: ConfirmationModalProps,
6162
+ ref: React.Ref<HTMLDivElement>
5675
6163
  ) => {
5676
6164
  const handleConfirm = () => {
5677
6165
  onConfirm?.();
@@ -5803,7 +6291,7 @@ export interface FormModalProps {
5803
6291
  * </FormModal>
5804
6292
  * \`\`\`
5805
6293
  */
5806
- const FormModal = React.forwardRef<HTMLDivElement, FormModalProps>(
6294
+ const FormModal = React.forwardRef(
5807
6295
  (
5808
6296
  {
5809
6297
  open,
@@ -5819,8 +6307,8 @@ const FormModal = React.forwardRef<HTMLDivElement, FormModalProps>(
5819
6307
  disableSave = false,
5820
6308
  className,
5821
6309
  size = "sm",
5822
- },
5823
- ref
6310
+ }: FormModalProps,
6311
+ ref: React.Ref<HTMLDivElement>
5824
6312
  ) => {
5825
6313
  const handleSave = () => {
5826
6314
  onSave?.();
@@ -5935,8 +6423,8 @@ export interface TagProps
5935
6423
  label?: string;
5936
6424
  }
5937
6425
 
5938
- const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
5939
- ({ className, variant, size, label, children, ...props }, ref) => {
6426
+ const Tag = React.forwardRef(
6427
+ ({ className, variant, size, label, children, ...props }: TagProps, ref: React.Ref<HTMLSpanElement>) => {
5940
6428
  return (
5941
6429
  <span
5942
6430
  className={cn(tagVariants({ variant, size, className }))}
@@ -6132,7 +6620,7 @@ export interface AlertProps
6132
6620
  defaultOpen?: boolean;
6133
6621
  }
6134
6622
 
6135
- const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
6623
+ const Alert = React.forwardRef(
6136
6624
  (
6137
6625
  {
6138
6626
  className,
@@ -6147,8 +6635,8 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
6147
6635
  defaultOpen = true,
6148
6636
  children,
6149
6637
  ...props
6150
- },
6151
- ref
6638
+ }: AlertProps,
6639
+ ref: React.Ref<HTMLDivElement>
6152
6640
  ) => {
6153
6641
  const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
6154
6642
  const isControlled = controlledOpen !== undefined;
@@ -6220,10 +6708,7 @@ Alert.displayName = "Alert";
6220
6708
  /**
6221
6709
  * Alert title component for the heading text.
6222
6710
  */
6223
- const AlertTitle = React.forwardRef<
6224
- HTMLHeadingElement,
6225
- React.HTMLAttributes<HTMLHeadingElement>
6226
- >(({ className, ...props }, ref) => (
6711
+ const AlertTitle = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>, ref: React.Ref<HTMLHeadingElement>) => (
6227
6712
  <h5
6228
6713
  ref={ref}
6229
6714
  className={cn("font-semibold leading-tight tracking-tight", className)}
@@ -6235,10 +6720,7 @@ AlertTitle.displayName = "AlertTitle";
6235
6720
  /**
6236
6721
  * Alert description component for the body text.
6237
6722
  */
6238
- const AlertDescription = React.forwardRef<
6239
- HTMLParagraphElement,
6240
- React.HTMLAttributes<HTMLParagraphElement>
6241
- >(({ className, ...props }, ref) => (
6723
+ const AlertDescription = React.forwardRef(({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>, ref: React.Ref<HTMLParagraphElement>) => (
6242
6724
  <p ref={ref} className={cn("m-0 mt-1 text-sm", className)} {...props} />
6243
6725
  ));
6244
6726
  AlertDescription.displayName = "AlertDescription";
@@ -6272,10 +6754,7 @@ import { cn } from "../../lib/utils";
6272
6754
 
6273
6755
  const ToastProvider = ToastPrimitives.Provider;
6274
6756
 
6275
- const ToastViewport = React.forwardRef<
6276
- React.ElementRef<typeof ToastPrimitives.Viewport>,
6277
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
6278
- >(({ className, ...props }, ref) => (
6757
+ const ToastViewport = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Viewport>>) => (
6279
6758
  <ToastPrimitives.Viewport
6280
6759
  ref={ref}
6281
6760
  className={cn(
@@ -6309,11 +6788,8 @@ const toastVariants = cva(
6309
6788
  }
6310
6789
  );
6311
6790
 
6312
- const Toast = React.forwardRef<
6313
- React.ElementRef<typeof ToastPrimitives.Root>,
6314
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
6315
- VariantProps<typeof toastVariants>
6316
- >(({ 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>>) => {
6317
6793
  return (
6318
6794
  <ToastPrimitives.Root
6319
6795
  ref={ref}
@@ -6324,10 +6800,7 @@ const Toast = React.forwardRef<
6324
6800
  });
6325
6801
  Toast.displayName = ToastPrimitives.Root.displayName;
6326
6802
 
6327
- const ToastAction = React.forwardRef<
6328
- React.ElementRef<typeof ToastPrimitives.Action>,
6329
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
6330
- >(({ className, ...props }, ref) => (
6803
+ const ToastAction = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Action>>) => (
6331
6804
  <ToastPrimitives.Action
6332
6805
  ref={ref}
6333
6806
  className={cn(
@@ -6343,10 +6816,7 @@ const ToastAction = React.forwardRef<
6343
6816
  ));
6344
6817
  ToastAction.displayName = ToastPrimitives.Action.displayName;
6345
6818
 
6346
- const ToastClose = React.forwardRef<
6347
- React.ElementRef<typeof ToastPrimitives.Close>,
6348
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
6349
- >(({ className, ...props }, ref) => (
6819
+ const ToastClose = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Close>>) => (
6350
6820
  <ToastPrimitives.Close
6351
6821
  ref={ref}
6352
6822
  className={cn(
@@ -6361,10 +6831,7 @@ const ToastClose = React.forwardRef<
6361
6831
  ));
6362
6832
  ToastClose.displayName = ToastPrimitives.Close.displayName;
6363
6833
 
6364
- const ToastTitle = React.forwardRef<
6365
- React.ElementRef<typeof ToastPrimitives.Title>,
6366
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
6367
- >(({ className, ...props }, ref) => (
6834
+ const ToastTitle = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Title>>) => (
6368
6835
  <ToastPrimitives.Title
6369
6836
  ref={ref}
6370
6837
  className={cn("text-sm font-semibold tracking-[0.014px]", className)}
@@ -6373,10 +6840,7 @@ const ToastTitle = React.forwardRef<
6373
6840
  ));
6374
6841
  ToastTitle.displayName = ToastPrimitives.Title.displayName;
6375
6842
 
6376
- const ToastDescription = React.forwardRef<
6377
- React.ElementRef<typeof ToastPrimitives.Description>,
6378
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
6379
- >(({ className, ...props }, ref) => (
6843
+ const ToastDescription = React.forwardRef(({ className, ...props }: React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>, ref: React.Ref<React.ElementRef<typeof ToastPrimitives.Description>>) => (
6380
6844
  <ToastPrimitives.Description
6381
6845
  ref={ref}
6382
6846
  className={cn("text-xs tracking-[0.048px]", className)}
@@ -6825,7 +7289,7 @@ export interface SpinnerProps
6825
7289
  "aria-label"?: string;
6826
7290
  }
6827
7291
 
6828
- const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
7292
+ const Spinner = React.forwardRef(
6829
7293
  (
6830
7294
  {
6831
7295
  className,
@@ -6833,8 +7297,8 @@ const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
6833
7297
  variant,
6834
7298
  "aria-label": ariaLabel = "Loading",
6835
7299
  ...props
6836
- },
6837
- ref
7300
+ }: SpinnerProps,
7301
+ ref: React.Ref<HTMLDivElement>
6838
7302
  ) => {
6839
7303
  const strokeWidth = strokeWidths[size || "default"] ?? 3;
6840
7304
  const radius = 10;
@@ -6954,8 +7418,8 @@ export interface SkeletonProps
6954
7418
  height?: number | string;
6955
7419
  }
6956
7420
 
6957
- const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
6958
- ({ 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>) => {
6959
7423
  const dimensionStyle: React.CSSProperties = {
6960
7424
  ...style,
6961
7425
  ...(width !== undefined
@@ -7198,7 +7662,7 @@ export interface AccordionProps
7198
7662
  onValueChange?: (value: string[]) => void;
7199
7663
  }
7200
7664
 
7201
- const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
7665
+ const Accordion = React.forwardRef(
7202
7666
  (
7203
7667
  {
7204
7668
  className,
@@ -7209,8 +7673,8 @@ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
7209
7673
  onValueChange,
7210
7674
  children,
7211
7675
  ...props
7212
- },
7213
- ref
7676
+ }: AccordionProps,
7677
+ ref: React.Ref<HTMLDivElement>
7214
7678
  ) => {
7215
7679
  const [internalValue, setInternalValue] =
7216
7680
  React.useState<string[]>(defaultValue);
@@ -7266,8 +7730,8 @@ export interface AccordionItemProps
7266
7730
  disabled?: boolean;
7267
7731
  }
7268
7732
 
7269
- const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
7270
- ({ className, value, disabled, children, ...props }, ref) => {
7733
+ const AccordionItem = React.forwardRef(
7734
+ ({ className, value, disabled, children, ...props }: AccordionItemProps, ref: React.Ref<HTMLDivElement>) => {
7271
7735
  const { value: openValues, variant } = useAccordionContext();
7272
7736
  const isOpen = openValues.includes(value);
7273
7737
 
@@ -7307,10 +7771,7 @@ export interface AccordionTriggerProps
7307
7771
  showChevron?: boolean;
7308
7772
  }
7309
7773
 
7310
- const AccordionTrigger = React.forwardRef<
7311
- HTMLButtonElement,
7312
- AccordionTriggerProps
7313
- >(({ className, showChevron = true, children, ...props }, ref) => {
7774
+ const AccordionTrigger = React.forwardRef(({ className, showChevron = true, children, ...props }: AccordionTriggerProps, ref: React.Ref<HTMLButtonElement>) => {
7314
7775
  const {
7315
7776
  type,
7316
7777
  value: openValues,
@@ -7369,10 +7830,7 @@ export interface AccordionContentProps
7369
7830
  React.HTMLAttributes<HTMLDivElement>,
7370
7831
  VariantProps<typeof accordionContentVariants> {}
7371
7832
 
7372
- const AccordionContent = React.forwardRef<
7373
- HTMLDivElement,
7374
- AccordionContentProps
7375
- >(({ className, children, ...props }, ref) => {
7833
+ const AccordionContent = React.forwardRef(({ className, children, ...props }: AccordionContentProps, ref: React.Ref<HTMLDivElement>) => {
7376
7834
  const { variant } = useAccordionContext();
7377
7835
  const { isOpen } = useAccordionItemContext();
7378
7836
  const contentRef = React.useRef<HTMLDivElement>(null);
@@ -7504,7 +7962,7 @@ export interface PageHeaderProps
7504
7962
  mobileOverflowLimit?: number;
7505
7963
  }
7506
7964
 
7507
- const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
7965
+ const PageHeader = React.forwardRef(
7508
7966
  (
7509
7967
  {
7510
7968
  className,
@@ -7520,8 +7978,8 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
7520
7978
  layout = "responsive",
7521
7979
  mobileOverflowLimit = 2,
7522
7980
  ...props
7523
- },
7524
- ref
7981
+ }: PageHeaderProps,
7982
+ ref: React.Ref<HTMLDivElement>
7525
7983
  ) => {
7526
7984
  // State for overflow expansion (moved to top level)
7527
7985
  const [isOverflowExpanded, setIsOverflowExpanded] = React.useState(false);
@@ -7809,7 +8267,7 @@ export interface PanelProps
7809
8267
  * </Panel>
7810
8268
  * \`\`\`
7811
8269
  */
7812
- const Panel = React.forwardRef<HTMLElement, PanelProps>(
8270
+ const Panel = React.forwardRef(
7813
8271
  (
7814
8272
  {
7815
8273
  open = true,
@@ -7823,8 +8281,8 @@ const Panel = React.forwardRef<HTMLElement, PanelProps>(
7823
8281
  "aria-label": ariaLabel,
7824
8282
  onKeyDown,
7825
8283
  ...props
7826
- },
7827
- ref
8284
+ }: PanelProps,
8285
+ ref: React.Ref<HTMLElement>
7828
8286
  ) => {
7829
8287
  const resolvedSize = size ?? "default";
7830
8288
  const widthClass = panelWidths[resolvedSize];
@@ -8268,10 +8726,7 @@ import type { EventSelectorProps, EventCategory, EventGroup } from "./types";
8268
8726
  * />
8269
8727
  * \`\`\`
8270
8728
  */
8271
- export const EventSelector = React.forwardRef<
8272
- HTMLDivElement,
8273
- EventSelectorProps
8274
- >(
8729
+ export const EventSelector = React.forwardRef(
8275
8730
  (
8276
8731
  {
8277
8732
  events,
@@ -8286,8 +8741,8 @@ export const EventSelector = React.forwardRef<
8286
8741
  renderEmptyGroup,
8287
8742
  className,
8288
8743
  ...props
8289
- },
8290
- ref
8744
+ }: EventSelectorProps,
8745
+ ref: React.Ref<HTMLDivElement>
8291
8746
  ) => {
8292
8747
  // Controlled vs uncontrolled state
8293
8748
  const [internalSelected, setInternalSelected] = React.useState<string[]>(
@@ -8448,10 +8903,7 @@ import type { EventGroupComponentProps } from "./types";
8448
8903
  /**
8449
8904
  * Event group with accordion section and group-level checkbox
8450
8905
  */
8451
- export const EventGroupComponent = React.forwardRef<
8452
- HTMLDivElement,
8453
- EventGroupComponentProps & React.HTMLAttributes<HTMLDivElement>
8454
- >(
8906
+ export const EventGroupComponent = React.forwardRef(
8455
8907
  (
8456
8908
  {
8457
8909
  group,
@@ -8463,8 +8915,8 @@ export const EventGroupComponent = React.forwardRef<
8463
8915
  defaultExpanded = false,
8464
8916
  className,
8465
8917
  ...props
8466
- },
8467
- ref
8918
+ }: EventGroupComponentProps & React.HTMLAttributes<HTMLDivElement>,
8919
+ ref: React.Ref<HTMLDivElement>
8468
8920
  ) => {
8469
8921
  // Calculate selection state for this group
8470
8922
  const groupEventIds = events.map((e) => e.id);
@@ -8627,10 +9079,7 @@ import type { EventItemComponentProps } from "./types";
8627
9079
  /**
8628
9080
  * Individual event item with checkbox
8629
9081
  */
8630
- export const EventItemComponent = React.forwardRef<
8631
- HTMLDivElement,
8632
- EventItemComponentProps & React.HTMLAttributes<HTMLDivElement>
8633
- >(({ 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>) => {
8634
9083
  return (
8635
9084
  <div
8636
9085
  ref={ref}
@@ -8841,10 +9290,7 @@ const generateId = () =>
8841
9290
  * />
8842
9291
  * \`\`\`
8843
9292
  */
8844
- export const KeyValueInput = React.forwardRef<
8845
- HTMLDivElement,
8846
- KeyValueInputProps
8847
- >(
9293
+ export const KeyValueInput = React.forwardRef(
8848
9294
  (
8849
9295
  {
8850
9296
  title,
@@ -8862,8 +9308,8 @@ export const KeyValueInput = React.forwardRef<
8862
9308
  defaultValue = [],
8863
9309
  className,
8864
9310
  ...props
8865
- },
8866
- ref
9311
+ }: KeyValueInputProps,
9312
+ ref: React.Ref<HTMLDivElement>
8867
9313
  ) => {
8868
9314
  // Controlled vs uncontrolled state
8869
9315
  const [internalPairs, setInternalPairs] =
@@ -9060,10 +9506,7 @@ import type { KeyValueRowProps } from "./types";
9060
9506
  /**
9061
9507
  * Individual key-value pair row with inputs and delete button
9062
9508
  */
9063
- export const KeyValueRow = React.forwardRef<
9064
- HTMLDivElement,
9065
- KeyValueRowProps & React.HTMLAttributes<HTMLDivElement>
9066
- >(
9509
+ export const KeyValueRow = React.forwardRef(
9067
9510
  (
9068
9511
  {
9069
9512
  pair,
@@ -9079,8 +9522,8 @@ export const KeyValueRow = React.forwardRef<
9079
9522
  onDelete,
9080
9523
  className,
9081
9524
  ...props
9082
- },
9083
- ref
9525
+ }: KeyValueRowProps & React.HTMLAttributes<HTMLDivElement>,
9526
+ ref: React.Ref<HTMLDivElement>
9084
9527
  ) => {
9085
9528
  // Determine if inputs should show error state
9086
9529
  const keyHasError = isDuplicateKey || (keyRequired && isKeyEmpty);
@@ -9295,10 +9738,7 @@ export interface ApiFeatureCardProps
9295
9738
  * />
9296
9739
  * \`\`\`
9297
9740
  */
9298
- export const ApiFeatureCard = React.forwardRef<
9299
- HTMLDivElement,
9300
- ApiFeatureCardProps
9301
- >(
9741
+ export const ApiFeatureCard = React.forwardRef(
9302
9742
  (
9303
9743
  {
9304
9744
  icon,
@@ -9311,8 +9751,8 @@ export const ApiFeatureCard = React.forwardRef<
9311
9751
  capabilitiesLabel = "Key Capabilities",
9312
9752
  className,
9313
9753
  ...props
9314
- },
9315
- ref
9754
+ }: ApiFeatureCardProps,
9755
+ ref: React.Ref<HTMLDivElement>
9316
9756
  ) => {
9317
9757
  return (
9318
9758
  <div
@@ -9484,10 +9924,7 @@ export interface EndpointDetailsProps
9484
9924
  * />
9485
9925
  * \`\`\`
9486
9926
  */
9487
- export const EndpointDetails = React.forwardRef<
9488
- HTMLDivElement,
9489
- EndpointDetailsProps
9490
- >(
9927
+ export const EndpointDetails = React.forwardRef(
9491
9928
  (
9492
9929
  {
9493
9930
  title = "Endpoint Details",
@@ -9508,8 +9945,8 @@ export const EndpointDetails = React.forwardRef<
9508
9945
  revokeDescription = "Revoking access will immediately disable all integrations using these keys.",
9509
9946
  className,
9510
9947
  ...props
9511
- },
9512
- ref
9948
+ }: EndpointDetailsProps,
9949
+ ref: React.Ref<HTMLDivElement>
9513
9950
  ) => {
9514
9951
  const isCalling = variant === "calling";
9515
9952
 
@@ -9699,10 +10136,7 @@ export interface AlertConfigurationProps {
9699
10136
  * AlertConfiguration component displays current alert values for minimum balance and top-up.
9700
10137
  * Used in payment auto-pay setup to show notification thresholds.
9701
10138
  */
9702
- export const AlertConfiguration = React.forwardRef<
9703
- HTMLDivElement,
9704
- AlertConfigurationProps
9705
- >(
10139
+ export const AlertConfiguration = React.forwardRef(
9706
10140
  (
9707
10141
  {
9708
10142
  minimumBalance,
@@ -9710,8 +10144,8 @@ export const AlertConfiguration = React.forwardRef<
9710
10144
  currencySymbol = "\u20B9",
9711
10145
  onEdit,
9712
10146
  className,
9713
- },
9714
- ref
10147
+ }: AlertConfigurationProps,
10148
+ ref: React.Ref<HTMLDivElement>
9715
10149
  ) => {
9716
10150
  const formatCurrency = (amount: number) => {
9717
10151
  const formatted = amount.toLocaleString("en-IN", {
@@ -9846,10 +10280,7 @@ export interface AlertValuesModalProps {
9846
10280
  * AlertValuesModal component for editing alert configuration values.
9847
10281
  * Displays a form with inputs for minimum balance and minimum top-up.
9848
10282
  */
9849
- export const AlertValuesModal = React.forwardRef<
9850
- HTMLDivElement,
9851
- AlertValuesModalProps
9852
- >(
10283
+ export const AlertValuesModal = React.forwardRef(
9853
10284
  (
9854
10285
  {
9855
10286
  open,
@@ -9861,8 +10292,8 @@ export const AlertValuesModal = React.forwardRef<
9861
10292
  topupOptions,
9862
10293
  onSave,
9863
10294
  loading = false,
9864
- },
9865
- ref
10295
+ }: AlertValuesModalProps,
10296
+ ref: React.Ref<HTMLDivElement>
9866
10297
  ) => {
9867
10298
  const [minimumBalance, setMinimumBalance] = React.useState(
9868
10299
  initialMinimumBalance.toString()
@@ -10011,7 +10442,7 @@ import type { AutoPaySetupProps } from "./types";
10011
10442
  * />
10012
10443
  * \`\`\`
10013
10444
  */
10014
- export const AutoPaySetup = React.forwardRef<HTMLDivElement, AutoPaySetupProps>(
10445
+ export const AutoPaySetup = React.forwardRef(
10015
10446
  (
10016
10447
  {
10017
10448
  title = "Auto-pay setup",
@@ -10030,8 +10461,8 @@ export const AutoPaySetup = React.forwardRef<HTMLDivElement, AutoPaySetupProps>(
10030
10461
  open,
10031
10462
  onOpenChange,
10032
10463
  className,
10033
- },
10034
- ref
10464
+ }: AutoPaySetupProps,
10465
+ ref: React.Ref<HTMLDivElement>
10035
10466
  ) => {
10036
10467
  const isControlled = open !== undefined;
10037
10468
 
@@ -10222,7 +10653,7 @@ import type { BankDetailsProps, BankDetailItem } from "./types";
10222
10653
  * />
10223
10654
  * \`\`\`
10224
10655
  */
10225
- export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
10656
+ export const BankDetails = React.forwardRef(
10226
10657
  (
10227
10658
  {
10228
10659
  title = "Bank details",
@@ -10234,8 +10665,8 @@ export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
10234
10665
  onOpenChange,
10235
10666
  onCopy,
10236
10667
  className,
10237
- },
10238
- ref
10668
+ }: BankDetailsProps,
10669
+ ref: React.Ref<HTMLDivElement>
10239
10670
  ) => {
10240
10671
  const isControlled = open !== undefined;
10241
10672
 
@@ -11051,8 +11482,8 @@ const BreakdownCardRow = ({ item }: { item: BreakdownCardItem }) => (
11051
11482
  * />
11052
11483
  * \`\`\`
11053
11484
  */
11054
- export const PaymentSummary = React.forwardRef<HTMLDivElement, PaymentSummaryProps>(
11055
- ({ 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>) => {
11056
11487
  const hasItemsBorder =
11057
11488
  items.length > 0 &&
11058
11489
  (!!subtotal || !!breakdownCard || (summaryItems && summaryItems.length > 0));
@@ -11249,10 +11680,7 @@ import type { PaymentOptionCardProps } from "./types";
11249
11680
  * />
11250
11681
  * \`\`\`
11251
11682
  */
11252
- export const PaymentOptionCard = React.forwardRef<
11253
- HTMLDivElement,
11254
- PaymentOptionCardProps
11255
- >(
11683
+ export const PaymentOptionCard = React.forwardRef(
11256
11684
  (
11257
11685
  {
11258
11686
  title = "Select payment method",
@@ -11267,8 +11695,8 @@ export const PaymentOptionCard = React.forwardRef<
11267
11695
  loading = false,
11268
11696
  disabled = false,
11269
11697
  className,
11270
- },
11271
- ref
11698
+ }: PaymentOptionCardProps,
11699
+ ref: React.Ref<HTMLDivElement>
11272
11700
  ) => {
11273
11701
  const [internalSelected, setInternalSelected] = React.useState<
11274
11702
  string | undefined
@@ -11401,10 +11829,7 @@ export interface PaymentOptionCardModalProps
11401
11829
  * />
11402
11830
  * \`\`\`
11403
11831
  */
11404
- export const PaymentOptionCardModal = React.forwardRef<
11405
- HTMLDivElement,
11406
- PaymentOptionCardModalProps
11407
- >(
11832
+ export const PaymentOptionCardModal = React.forwardRef(
11408
11833
  (
11409
11834
  {
11410
11835
  open,
@@ -11420,8 +11845,8 @@ export const PaymentOptionCardModal = React.forwardRef<
11420
11845
  loading,
11421
11846
  disabled,
11422
11847
  className,
11423
- },
11424
- ref
11848
+ }: PaymentOptionCardModalProps,
11849
+ ref: React.Ref<HTMLDivElement>
11425
11850
  ) => {
11426
11851
  const handleClose = () => {
11427
11852
  onOpenChange(false);
@@ -11559,7 +11984,7 @@ const DEFAULT_FEATURES: PlanFeature[] = [
11559
11984
  { name: "Channel(s)", free: "1 Pair(s)", rate: "\u20B9 300.00" },
11560
11985
  ];
11561
11986
 
11562
- const PlanDetailModal = React.forwardRef<HTMLDivElement, PlanDetailModalProps>(
11987
+ const PlanDetailModal = React.forwardRef(
11563
11988
  (
11564
11989
  {
11565
11990
  open,
@@ -11570,8 +11995,8 @@ const PlanDetailModal = React.forwardRef<HTMLDivElement, PlanDetailModalProps>(
11570
11995
  onClose,
11571
11996
  className,
11572
11997
  ...props
11573
- },
11574
- ref
11998
+ }: PlanDetailModalProps,
11999
+ ref: React.Ref<HTMLDivElement>
11575
12000
  ) => {
11576
12001
  const handleClose = () => {
11577
12002
  onClose?.();
@@ -11780,7 +12205,7 @@ const renderOptionIcon = (icon: BillingCycleOption["icon"]) => {
11780
12205
  return icon;
11781
12206
  };
11782
12207
 
11783
- const PlanUpgradeModal = React.forwardRef<HTMLDivElement, PlanUpgradeModalProps>(
12208
+ const PlanUpgradeModal = React.forwardRef(
11784
12209
  (
11785
12210
  {
11786
12211
  open,
@@ -11797,8 +12222,8 @@ const PlanUpgradeModal = React.forwardRef<HTMLDivElement, PlanUpgradeModalProps>
11797
12222
  onClose,
11798
12223
  className,
11799
12224
  ...props
11800
- },
11801
- ref
12225
+ }: PlanUpgradeModalProps,
12226
+ ref: React.Ref<HTMLDivElement>
11802
12227
  ) => {
11803
12228
  const initialOptionId = defaultSelectedOptionId ?? options[0]?.id;
11804
12229
  const [internalSelectedOptionId, setInternalSelectedOptionId] = React.useState<
@@ -12076,10 +12501,7 @@ const getStatusIcon = (tone: PlanUpgradeSummaryTone) => {
12076
12501
  return <AlertCircle className="size-6 text-semantic-warning-text" aria-hidden="true" />;
12077
12502
  };
12078
12503
 
12079
- const PlanUpgradeSummaryModal = React.forwardRef<
12080
- HTMLDivElement,
12081
- PlanUpgradeSummaryModalProps
12082
- >(
12504
+ const PlanUpgradeSummaryModal = React.forwardRef(
12083
12505
  (
12084
12506
  {
12085
12507
  open,
@@ -12101,8 +12523,8 @@ const PlanUpgradeSummaryModal = React.forwardRef<
12101
12523
  closeAriaLabel = "Close plan summary modal",
12102
12524
  className,
12103
12525
  ...props
12104
- },
12105
- ref
12526
+ }: PlanUpgradeSummaryModalProps,
12527
+ ref: React.Ref<HTMLDivElement>
12106
12528
  ) => {
12107
12529
  const resolvedStatus = status ?? defaultStatusByMode[mode];
12108
12530
  const resolvedTone = resolvedStatus.tone ?? defaultStatusByMode[mode].tone ?? "warning";
@@ -12339,7 +12761,7 @@ import type { LetUsDriveCardProps } from "./types";
12339
12761
  * />
12340
12762
  * \`\`\`
12341
12763
  */
12342
- const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12764
+ const LetUsDriveCard = React.forwardRef(
12343
12765
  (
12344
12766
  {
12345
12767
  title,
@@ -12359,8 +12781,8 @@ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12359
12781
  onCtaClick,
12360
12782
  className,
12361
12783
  ...props
12362
- },
12363
- ref
12784
+ }: LetUsDriveCardProps,
12785
+ ref: React.Ref<HTMLDivElement>
12364
12786
  ) => {
12365
12787
  const [internalExpanded, setInternalExpanded] = React.useState(false);
12366
12788
  const isControlled = controlledExpanded !== undefined;
@@ -12623,7 +13045,7 @@ import type { PowerUpCardProps } from "./types";
12623
13045
  * />
12624
13046
  * \`\`\`
12625
13047
  */
12626
- const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
13048
+ const PowerUpCard = React.forwardRef(
12627
13049
  (
12628
13050
  {
12629
13051
  icon,
@@ -12634,8 +13056,8 @@ const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
12634
13056
  onCtaClick,
12635
13057
  className,
12636
13058
  ...props
12637
- },
12638
- ref
13059
+ }: PowerUpCardProps,
13060
+ ref: React.Ref<HTMLDivElement>
12639
13061
  ) => {
12640
13062
  return (
12641
13063
  <div
@@ -12762,7 +13184,7 @@ import type { PricingCardProps } from "./types";
12762
13184
  * />
12763
13185
  * \`\`\`
12764
13186
  */
12765
- const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
13187
+ const PricingCard = React.forwardRef(
12766
13188
  (
12767
13189
  {
12768
13190
  planName,
@@ -12786,8 +13208,8 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12786
13208
  infoText,
12787
13209
  className,
12788
13210
  ...props
12789
- },
12790
- ref
13211
+ }: PricingCardProps,
13212
+ ref: React.Ref<HTMLDivElement>
12791
13213
  ) => {
12792
13214
  const buttonText =
12793
13215
  ctaText || (isCurrentPlan ? "Current plan" : "Select plan");
@@ -12920,29 +13342,34 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12920
13342
  </div>
12921
13343
  )}
12922
13344
 
12923
- {/* Addon */}
12924
- {addon && (
12925
- <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
12926
- {addon.icon && (
12927
- <div className="size-5 shrink-0">{addon.icon}</div>
12928
- )}
12929
- <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
12930
- {addon.text}
12931
- </span>
12932
- </div>
12933
- )}
12934
-
12935
- {/* Usage Details */}
12936
- {usageDetails && usageDetails.length > 0 && (
12937
- <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
12938
- {usageDetails.map((detail, index) => (
12939
- <div key={index} className="flex items-start gap-2">
12940
- <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
13345
+ {/* Bottom sections pushed to card bottom for grid alignment */}
13346
+ {(addon || (usageDetails && usageDetails.length > 0)) && (
13347
+ <div className="mt-auto flex flex-col gap-6">
13348
+ {/* Addon */}
13349
+ {addon && (
13350
+ <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
13351
+ {addon.icon && (
13352
+ <div className="size-5 shrink-0">{addon.icon}</div>
13353
+ )}
12941
13354
  <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
12942
- <strong>{detail.label}:</strong> {detail.value}
13355
+ {addon.text}
12943
13356
  </span>
12944
13357
  </div>
12945
- ))}
13358
+ )}
13359
+
13360
+ {/* Usage Details */}
13361
+ {usageDetails && usageDetails.length > 0 && (
13362
+ <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
13363
+ {usageDetails.map((detail, index) => (
13364
+ <div key={index} className="flex items-start gap-2">
13365
+ <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
13366
+ <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
13367
+ <strong>{detail.label}:</strong> {detail.value}
13368
+ </span>
13369
+ </div>
13370
+ ))}
13371
+ </div>
13372
+ )}
12946
13373
  </div>
12947
13374
  )}
12948
13375
  </div>
@@ -12963,8 +13390,8 @@ interface PlanIconProps extends React.SVGAttributes<SVGElement> {
12963
13390
  className?: string;
12964
13391
  }
12965
13392
 
12966
- const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
12967
- ({ className, ...props }, ref) => (
13393
+ const CompactCarIcon = React.forwardRef(
13394
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
12968
13395
  <svg
12969
13396
  ref={ref}
12970
13397
  className={className}
@@ -13003,8 +13430,8 @@ const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13003
13430
  );
13004
13431
  CompactCarIcon.displayName = "CompactCarIcon";
13005
13432
 
13006
- const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13007
- ({ className, ...props }, ref) => (
13433
+ const SedanCarIcon = React.forwardRef(
13434
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13008
13435
  <svg
13009
13436
  ref={ref}
13010
13437
  className={className}
@@ -13055,8 +13482,8 @@ const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13055
13482
  );
13056
13483
  SedanCarIcon.displayName = "SedanCarIcon";
13057
13484
 
13058
- const SuvCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13059
- ({ className, ...props }, ref) => (
13485
+ const SuvCarIcon = React.forwardRef(
13486
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13060
13487
  <svg
13061
13488
  ref={ref}
13062
13489
  className={className}
@@ -13269,7 +13696,7 @@ import type { PricingPageProps } from "./types";
13269
13696
  * />
13270
13697
  * \`\`\`
13271
13698
  */
13272
- const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13699
+ const PricingPage = React.forwardRef(
13273
13700
  (
13274
13701
  {
13275
13702
  title = "Select business plan",
@@ -13292,8 +13719,8 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13292
13719
  letUsDriveExpandMode,
13293
13720
  className,
13294
13721
  ...props
13295
- },
13296
- ref
13722
+ }: PricingPageProps,
13723
+ ref: React.Ref<HTMLDivElement>
13297
13724
  ) => {
13298
13725
  // Internal state for uncontrolled mode
13299
13726
  const [internalTab, setInternalTab] = React.useState(
@@ -13604,7 +14031,7 @@ import type { PricingToggleProps } from "./types";
13604
14031
  * />
13605
14032
  * \`\`\`
13606
14033
  */
13607
- const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
14034
+ const PricingToggle = React.forwardRef(
13608
14035
  (
13609
14036
  {
13610
14037
  tabs,
@@ -13617,8 +14044,8 @@ const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13617
14044
  yearlyLabel = "Yearly (Save 20%)",
13618
14045
  className,
13619
14046
  ...props
13620
- },
13621
- ref
14047
+ }: PricingToggleProps,
14048
+ ref: React.Ref<HTMLDivElement>
13622
14049
  ) => {
13623
14050
  const isYearly = billingPeriod === "yearly";
13624
14051
 
@@ -13863,8 +14290,8 @@ interface BrandIconProps extends React.SVGAttributes<SVGElement> {
13863
14290
  * Used in TalkToUsModal and available for any component that needs
13864
14291
  * the MyOperator contact/chat branding.
13865
14292
  */
13866
- const MyOperatorChatIcon = React.forwardRef<SVGSVGElement, BrandIconProps>(
13867
- ({ className, ...props }, ref) => (
14293
+ const MyOperatorChatIcon = React.forwardRef(
14294
+ ({ className, ...props }: BrandIconProps, ref: React.Ref<SVGSVGElement>) => (
13868
14295
  <svg
13869
14296
  ref={ref}
13870
14297
  className={className}
@@ -13997,8 +14424,8 @@ function getTypeLabel(
13997
14424
  * All displayed data (icon, badge, name, count, last published) comes from the \`bot\` prop.
13998
14425
  * Set bot.type to "chatbot" or "voicebot"; no separate card components needed.
13999
14426
  */
14000
- export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14001
- ({ bot, typeLabels, onEdit, onDelete, className, ...props }, ref) => {
14427
+ export const BotCard = React.forwardRef(
14428
+ ({ bot, typeLabels, onEdit, onDelete, className, ...props }: BotCardProps, ref: React.Ref<HTMLDivElement>) => {
14002
14429
  const typeLabel = getTypeLabel(bot, typeLabels);
14003
14430
  const isChatbot = bot.type === "chatbot";
14004
14431
 
@@ -14085,7 +14512,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14085
14512
  </div>
14086
14513
 
14087
14514
  {/* Bot name */}
14088
- <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary truncate mb-1 min-w-0">
14515
+ <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary line-clamp-1 mb-1 min-w-0">
14089
14516
  {bot.name}
14090
14517
  </h3>
14091
14518
 
@@ -14113,7 +14540,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14113
14540
  </span>
14114
14541
  )}
14115
14542
  {(bot.lastPublishedBy || bot.lastPublishedDate) ? (
14116
- <p className="m-0 text-xs sm:text-sm text-semantic-text-muted truncate">
14543
+ <p className="m-0 text-xs sm:text-sm text-semantic-text-muted line-clamp-1">
14117
14544
  {bot.lastPublishedBy
14118
14545
  ? \`\${bot.lastPublishedBy} | \${bot.lastPublishedDate ?? "\u2014"}\`
14119
14546
  : bot.lastPublishedDate}
@@ -14163,10 +14590,7 @@ const BOT_TYPE_OPTIONS: BotTypeOption[] = [
14163
14590
  },
14164
14591
  ];
14165
14592
 
14166
- export const CreateBotModal = React.forwardRef<
14167
- HTMLDivElement,
14168
- CreateBotModalProps
14169
- >(({ open, onOpenChange, onSubmit, isLoading, className }, ref) => {
14593
+ export const CreateBotModal = React.forwardRef(({ open, onOpenChange, onSubmit, isLoading, className }: CreateBotModalProps, ref: React.Ref<HTMLDivElement>) => {
14170
14594
  const [name, setName] = React.useState("");
14171
14595
  const [selectedType, setSelectedType] = React.useState<BotType>("chatbot");
14172
14596
 
@@ -14314,15 +14738,15 @@ import type { CreateBotFlowProps } from "./types";
14314
14738
  * Create bot flow: "Create new bot" card + Create Bot modal. No header (title/subtitle/search).
14315
14739
  * Use when you want the create-bot experience without the list header.
14316
14740
  */
14317
- export const CreateBotFlow = React.forwardRef<HTMLDivElement, CreateBotFlowProps>(
14741
+ export const CreateBotFlow = React.forwardRef(
14318
14742
  (
14319
14743
  {
14320
14744
  createCardLabel = "Create new bot",
14321
14745
  onSubmit,
14322
14746
  className,
14323
14747
  ...props
14324
- },
14325
- ref
14748
+ }: CreateBotFlowProps,
14749
+ ref: React.Ref<HTMLDivElement>
14326
14750
  ) => {
14327
14751
  const [modalOpen, setModalOpen] = React.useState(false);
14328
14752
 
@@ -14438,7 +14862,7 @@ import { BotListGrid } from "./bot-list-grid";
14438
14862
  import { CreateBotModal } from "./create-bot-modal";
14439
14863
  import type { BotListProps } from "./types";
14440
14864
 
14441
- export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14865
+ export const BotList = React.forwardRef(
14442
14866
  (
14443
14867
  {
14444
14868
  bots = [],
@@ -14454,8 +14878,8 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14454
14878
  createCardLabel = "Create new bot",
14455
14879
  className,
14456
14880
  ...props
14457
- },
14458
- ref
14881
+ }: BotListProps,
14882
+ ref: React.Ref<HTMLDivElement>
14459
14883
  ) => {
14460
14884
  const [searchQuery, setSearchQuery] = React.useState("");
14461
14885
  const [createModalOpen, setCreateModalOpen] = React.useState(false);
@@ -14565,10 +14989,10 @@ const botListHeaderVariants = cva("min-w-0", {
14565
14989
  },
14566
14990
  });
14567
14991
 
14568
- export const BotListHeader = React.forwardRef<HTMLDivElement, BotListHeaderProps>(
14992
+ export const BotListHeader = React.forwardRef(
14569
14993
  (
14570
- { title, subtitle, variant = "default", rightContent, className, ...props },
14571
- ref
14994
+ { title, subtitle, variant = "default", rightContent, className, ...props }: BotListHeaderProps,
14995
+ ref: React.Ref<HTMLDivElement>
14572
14996
  ) => {
14573
14997
  const rootClassName = cn(botListHeaderVariants({ variant }), className);
14574
14998
  const titleBlock = (
@@ -14615,7 +15039,7 @@ import { Search } from "lucide-react";
14615
15039
  import { cn } from "../../../lib/utils";
14616
15040
  import type { BotListSearchProps } from "./types";
14617
15041
 
14618
- export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps>(
15042
+ export const BotListSearch = React.forwardRef(
14619
15043
  (
14620
15044
  {
14621
15045
  value,
@@ -14624,8 +15048,8 @@ export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps
14624
15048
  defaultValue,
14625
15049
  className,
14626
15050
  ...props
14627
- },
14628
- ref
15051
+ }: BotListSearchProps,
15052
+ ref: React.Ref<HTMLDivElement>
14629
15053
  ) => {
14630
15054
  const [internalValue, setInternalValue] = React.useState(defaultValue ?? "");
14631
15055
  const isControlled = value !== undefined;
@@ -14672,18 +15096,15 @@ import { Plus } from "lucide-react";
14672
15096
  import { cn } from "../../../lib/utils";
14673
15097
  import type { BotListCreateCardProps } from "./types";
14674
15098
 
14675
- export const BotListCreateCard = React.forwardRef<
14676
- HTMLButtonElement,
14677
- BotListCreateCardProps
14678
- >(
15099
+ export const BotListCreateCard = React.forwardRef(
14679
15100
  (
14680
15101
  {
14681
15102
  label = "Create new bot",
14682
15103
  onClick,
14683
15104
  className,
14684
15105
  ...props
14685
- },
14686
- ref
15106
+ }: BotListCreateCardProps,
15107
+ ref: React.Ref<HTMLButtonElement>
14687
15108
  ) => (
14688
15109
  <button
14689
15110
  ref={ref}
@@ -14732,8 +15153,8 @@ BotListCreateCard.displayName = "BotListCreateCard";
14732
15153
  import { cn } from "../../../lib/utils";
14733
15154
  import type { BotListGridProps } from "./types";
14734
15155
 
14735
- export const BotListGrid = React.forwardRef<HTMLDivElement, BotListGridProps>(
14736
- ({ children, className, ...props }, ref) => (
15156
+ export const BotListGrid = React.forwardRef(
15157
+ ({ children, className, ...props }: BotListGridProps, ref: React.Ref<HTMLDivElement>) => (
14737
15158
  <div
14738
15159
  ref={ref}
14739
15160
  className={cn(
@@ -15034,7 +15455,7 @@ function getTimeRemaining(progress: number) {
15034
15455
  : \`\${secs} seconds remaining\`;
15035
15456
  }
15036
15457
 
15037
- const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15458
+ const FileUploadModal = React.forwardRef(
15038
15459
  (
15039
15460
  {
15040
15461
  open,
@@ -15057,8 +15478,8 @@ const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15057
15478
  loading = false,
15058
15479
  className,
15059
15480
  ...props
15060
- },
15061
- ref
15481
+ }: FileUploadModalProps,
15482
+ ref: React.Ref<HTMLDivElement>
15062
15483
  ) => {
15063
15484
  const [items, setItems] = React.useState<UploadItem[]>([]);
15064
15485
  const fileInputRef = React.useRef<HTMLInputElement>(null);
@@ -15428,8 +15849,8 @@ import { X, Play, File } from "lucide-react";
15428
15849
  import { cn } from "../../../lib/utils";
15429
15850
  import type { AttachmentPreviewProps } from "./types";
15430
15851
 
15431
- const AttachmentPreview = React.forwardRef<HTMLDivElement, AttachmentPreviewProps>(
15432
- ({ className, file, onRemove, ...props }, ref) => {
15852
+ const AttachmentPreview = React.forwardRef(
15853
+ ({ className, file, onRemove, ...props }: AttachmentPreviewProps, ref: React.Ref<HTMLDivElement>) => {
15433
15854
  const url = React.useMemo(() => URL.createObjectURL(file), [file]);
15434
15855
 
15435
15856
  const isImage = file.type.startsWith("image/");
@@ -15587,7 +16008,7 @@ const BAR_WIDTH = 2;
15587
16008
  const BAR_GAP = 1.5;
15588
16009
  const SVG_HEIGHT = 32;
15589
16010
 
15590
- const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
16011
+ const AudioMedia = React.forwardRef(
15591
16012
  (
15592
16013
  {
15593
16014
  className,
@@ -15601,8 +16022,8 @@ const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15601
16022
  onPlayChange,
15602
16023
  onSpeedChange,
15603
16024
  ...props
15604
- },
15605
- ref
16025
+ }: AudioMediaProps,
16026
+ ref: React.Ref<HTMLDivElement>
15606
16027
  ) => {
15607
16028
  const [playing, setPlaying] = React.useState(false);
15608
16029
  const [speed, setSpeed] = React.useState(1);
@@ -15802,8 +16223,8 @@ import { Reply, ExternalLink, ChevronLeft, ChevronRight } from "lucide-react";
15802
16223
  import { cn } from "../../../lib/utils";
15803
16224
  import type { CarouselMediaProps } from "./types";
15804
16225
 
15805
- const CarouselMedia = React.forwardRef<HTMLDivElement, CarouselMediaProps>(
15806
- ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }, ref) => {
16226
+ const CarouselMedia = React.forwardRef(
16227
+ ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }: CarouselMediaProps, ref: React.Ref<HTMLDivElement>) => {
15807
16228
  const scrollRef = useRef<HTMLDivElement>(null);
15808
16229
  const [canScrollLeft, setCanScrollLeft] = useState(false);
15809
16230
  const [canScrollRight, setCanScrollRight] = useState(
@@ -16057,7 +16478,7 @@ function DeliveryFooter({
16057
16478
  * </ChatBubble>
16058
16479
  * \`\`\`
16059
16480
  */
16060
- const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16481
+ const ChatBubble = React.forwardRef(
16061
16482
  (
16062
16483
  {
16063
16484
  variant,
@@ -16072,8 +16493,8 @@ const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16072
16493
  children,
16073
16494
  className,
16074
16495
  ...props
16075
- },
16076
- ref
16496
+ }: ChatBubbleProps,
16497
+ ref: React.Ref<HTMLDivElement>
16077
16498
  ) => {
16078
16499
  const hasMedia = !!media;
16079
16500
 
@@ -16246,7 +16667,7 @@ import type { ChatComposerProps } from "./types";
16246
16667
  * />
16247
16668
  * \`\`\`
16248
16669
  */
16249
- const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16670
+ const ChatComposer = React.forwardRef(
16250
16671
  (
16251
16672
  {
16252
16673
  className,
@@ -16270,8 +16691,8 @@ const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16270
16691
  expiredMessage = "This chat has expired. Send a template to continue.",
16271
16692
  onTemplateClick,
16272
16693
  ...props
16273
- },
16274
- ref
16694
+ }: ChatComposerProps,
16695
+ ref: React.Ref<HTMLDivElement>
16275
16696
  ) => {
16276
16697
  const textareaRef = React.useRef<HTMLTextAreaElement>(null);
16277
16698
 
@@ -16488,7 +16909,7 @@ import { cn } from "../../../lib/utils";
16488
16909
  import { File, FileSpreadsheet, ArrowDownToLine } from "lucide-react";
16489
16910
  import type { DocMediaProps } from "./types";
16490
16911
 
16491
- const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16912
+ const DocMedia = React.forwardRef(
16492
16913
  (
16493
16914
  {
16494
16915
  className,
@@ -16501,8 +16922,8 @@ const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16501
16922
  caption,
16502
16923
  onDownload,
16503
16924
  ...props
16504
- },
16505
- ref
16925
+ }: DocMediaProps,
16926
+ ref: React.Ref<HTMLDivElement>
16506
16927
  ) => {
16507
16928
  if (variant === "preview") {
16508
16929
  return (
@@ -16689,7 +17110,7 @@ import type { VideoMediaProps } from "./types";
16689
17110
 
16690
17111
  const DEFAULT_SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
16691
17112
 
16692
- const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
17113
+ const VideoMedia = React.forwardRef(
16693
17114
  (
16694
17115
  {
16695
17116
  className,
@@ -16701,8 +17122,8 @@ const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
16701
17122
  onSpeedChange,
16702
17123
  onClick,
16703
17124
  ...props
16704
- },
16705
- ref
17125
+ }: VideoMediaProps,
17126
+ ref: React.Ref<HTMLDivElement>
16706
17127
  ) => {
16707
17128
  const [playing, setPlaying] = useState(false);
16708
17129
  const [muted, setMuted] = useState(false);
@@ -16935,7 +17356,10 @@ export type { VideoMediaProps } from "./types";
16935
17356
  "creatable-multi-select",
16936
17357
  "page-header",
16937
17358
  "tag",
16938
- "file-upload-modal"
17359
+ "file-upload-modal",
17360
+ "form-modal",
17361
+ "text-field",
17362
+ "textarea"
16939
17363
  ],
16940
17364
  isMultiFile: true,
16941
17365
  directory: "ivr-bot",
@@ -16987,7 +17411,7 @@ const DEFAULT_DATA: IvrBotConfigData = {
16987
17411
  };
16988
17412
 
16989
17413
  // \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
16990
- export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
17414
+ export const IvrBotConfig = React.forwardRef(
16991
17415
  (
16992
17416
  {
16993
17417
  botTitle = "IVR bot",
@@ -17034,8 +17458,8 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
17034
17458
  callEndThresholdMin,
17035
17459
  callEndThresholdMax,
17036
17460
  className,
17037
- },
17038
- ref
17461
+ }: IvrBotConfigProps,
17462
+ ref: React.Ref<HTMLDivElement>
17039
17463
  ) => {
17040
17464
  const [data, setData] = React.useState<IvrBotConfigData>({
17041
17465
  ...DEFAULT_DATA,
@@ -17238,7 +17662,7 @@ IvrBotConfig.displayName = "IvrBotConfig";
17238
17662
  {
17239
17663
  name: "create-function-modal.tsx",
17240
17664
  content: prefixTailwindClasses(`import * as React from "react";
17241
- import { Trash2, ChevronDown, X, Plus } from "lucide-react";
17665
+ import { Trash2, ChevronDown, X, Plus, Pencil } from "lucide-react";
17242
17666
  import { cn } from "../../../lib/utils";
17243
17667
  import {
17244
17668
  Dialog,
@@ -17246,6 +17670,9 @@ import {
17246
17670
  DialogTitle,
17247
17671
  } from "../dialog";
17248
17672
  import { Button } from "../button";
17673
+ import { FormModal } from "../form-modal";
17674
+ import { TextField } from "../text-field";
17675
+ import { Textarea } from "../textarea";
17249
17676
  import type {
17250
17677
  CreateFunctionModalProps,
17251
17678
  CreateFunctionData,
@@ -17253,10 +17680,12 @@ import type {
17253
17680
  FunctionTabType,
17254
17681
  HttpMethod,
17255
17682
  KeyValuePair,
17683
+ VariableGroup,
17684
+ VariableItem,
17685
+ VariableFormData,
17256
17686
  } from "./types";
17257
17687
 
17258
17688
  const HTTP_METHODS: HttpMethod[] = ["GET", "POST", "PUT", "DELETE", "PATCH"];
17259
- const METHODS_WITH_BODY: HttpMethod[] = ["POST", "PUT", "PATCH"];
17260
17689
  const FUNCTION_NAME_MAX = 100;
17261
17690
  const BODY_MAX = 4000;
17262
17691
  const URL_MAX = 500;
@@ -17264,6 +17693,8 @@ const HEADER_KEY_MAX = 512;
17264
17693
  const HEADER_VALUE_MAX = 2048;
17265
17694
 
17266
17695
  const FUNCTION_NAME_REGEX = /^(?!_+$)(?=.*[a-zA-Z])[a-zA-Z][a-zA-Z0-9_]*$/;
17696
+ const VARIABLE_NAME_MAX = 30;
17697
+ const VARIABLE_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;
17267
17698
  const URL_REGEX = /^https?:\\/\\//;
17268
17699
  const HEADER_KEY_REGEX = /^[!#$%&'*+\\-.^_\`|~0-9a-zA-Z]+$/;
17269
17700
  // Query parameter validation (aligned with apiIntegrationSchema.queryParams)
@@ -17319,6 +17750,30 @@ function extractVarRefs(texts: string[]): string[] {
17319
17750
  return Array.from(new Set(all));
17320
17751
  }
17321
17752
 
17753
+ // \u2500\u2500 Value segment parser \u2014 splits "text {{var}} text" into typed segments \u2500\u2500\u2500\u2500\u2500
17754
+
17755
+ type ValueSegment =
17756
+ | { type: "text"; content: string }
17757
+ | { type: "var"; name: string; raw: string };
17758
+
17759
+ function parseValueSegments(value: string): ValueSegment[] {
17760
+ const segments: ValueSegment[] = [];
17761
+ const regex = /\\{\\{([^}]+)\\}\\}/g;
17762
+ let lastIndex = 0;
17763
+ let match;
17764
+ while ((match = regex.exec(value)) !== null) {
17765
+ if (match.index > lastIndex) {
17766
+ segments.push({ type: "text", content: value.slice(lastIndex, match.index) });
17767
+ }
17768
+ segments.push({ type: "var", name: match[1], raw: match[0] });
17769
+ lastIndex = regex.lastIndex;
17770
+ }
17771
+ if (lastIndex < value.length) {
17772
+ segments.push({ type: "text", content: value.slice(lastIndex) });
17773
+ }
17774
+ return segments;
17775
+ }
17776
+
17322
17777
  /** Mirror-div technique \u2014 returns { top, left } relative to the element's top-left corner. */
17323
17778
  function getCaretPixelPos(
17324
17779
  el: HTMLTextAreaElement | HTMLInputElement,
@@ -17368,70 +17823,320 @@ function getCaretPixelPos(
17368
17823
 
17369
17824
  // Uses same visual classes as DropdownMenuContent + DropdownMenuItem.
17370
17825
  // Position is cursor-anchored via getCaretPixelPos.
17826
+ // No search bar \u2014 typing after {{ already filters via filterQuery.
17371
17827
  function VarPopup({
17372
17828
  variables,
17829
+ variableGroups,
17830
+ filterQuery = "",
17373
17831
  onSelect,
17832
+ onAddVariable,
17833
+ onEditVariable,
17374
17834
  style,
17375
17835
  }: {
17376
17836
  variables: string[];
17837
+ variableGroups?: VariableGroup[];
17838
+ filterQuery?: string;
17377
17839
  onSelect: (v: string) => void;
17840
+ onAddVariable?: () => void;
17841
+ onEditVariable?: (variable: string) => void;
17378
17842
  style?: React.CSSProperties;
17379
17843
  }) {
17380
- if (variables.length === 0) return null;
17844
+ const hasGroups = variableGroups && variableGroups.length > 0;
17845
+
17846
+ if (!hasGroups && variables.length === 0) return null;
17847
+
17848
+ // Flat mode \u2014 variables are already pre-filtered by VariableInput
17849
+ if (!hasGroups) {
17850
+ return (
17851
+ <div
17852
+ role="listbox"
17853
+ style={style}
17854
+ 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"
17855
+ >
17856
+ {/* Add new variable */}
17857
+ {onAddVariable && (
17858
+ <button
17859
+ type="button"
17860
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
17861
+ 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"
17862
+ >
17863
+ <Plus className="size-3.5 shrink-0" />
17864
+ Add new variable
17865
+ </button>
17866
+ )}
17867
+
17868
+ {/* Variable list */}
17869
+ <div className="max-h-48 overflow-y-auto p-1">
17870
+ {variables.map((v) => (
17871
+ <button
17872
+ key={v}
17873
+ type="button"
17874
+ role="option"
17875
+ onMouseDown={(e) => { e.preventDefault(); onSelect(v); }}
17876
+ 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"
17877
+ >
17878
+ {v}
17879
+ </button>
17880
+ ))}
17881
+ {variables.length === 0 && (
17882
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
17883
+ )}
17884
+ </div>
17885
+ </div>
17886
+ );
17887
+ }
17888
+
17889
+ // Grouped mode \u2014 filter by the {{ trigger query
17890
+ const lowerQuery = filterQuery.toLowerCase();
17891
+ const filteredGroups = variableGroups.map((g) => ({
17892
+ ...g,
17893
+ items: g.items.filter((item) =>
17894
+ item.name.toLowerCase().includes(lowerQuery)
17895
+ ),
17896
+ })).filter((g) => g.items.length > 0);
17897
+
17381
17898
  return (
17382
17899
  <div
17383
17900
  role="listbox"
17384
17901
  style={style}
17385
- 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"
17902
+ 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"
17386
17903
  >
17387
- {variables.map((v) => (
17388
- <button
17389
- key={v}
17390
- type="button"
17391
- role="option"
17392
- onMouseDown={(e) => {
17393
- e.preventDefault(); // keep input focused so blur doesn't close popup first
17394
- onSelect(v);
17395
- }}
17396
- 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"
17397
- >
17398
- {v}
17399
- </button>
17400
- ))}
17904
+ {/* Add new variable */}
17905
+ {onAddVariable && (
17906
+ <>
17907
+ <button
17908
+ type="button"
17909
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
17910
+ 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"
17911
+ >
17912
+ <Plus className="size-3.5 shrink-0" />
17913
+ Add new variable
17914
+ </button>
17915
+ <div className="border-t border-semantic-border-layout" />
17916
+ </>
17917
+ )}
17918
+
17919
+ {/* Grouped variable list */}
17920
+ <div className="max-h-48 overflow-y-auto p-1">
17921
+ {filteredGroups.map((group) => (
17922
+ <div key={group.label}>
17923
+ <p className="m-0 px-2 pt-2 pb-1 text-sm font-medium text-semantic-text-muted">
17924
+ {group.label}
17925
+ </p>
17926
+ {group.items.map((item) => {
17927
+ const insertValue = item.value ?? \`{{\${item.name}}}\`;
17928
+ return (
17929
+ <div key={item.name} className="flex items-center rounded-sm transition-colors hover:bg-semantic-bg-ui">
17930
+ <button
17931
+ type="button"
17932
+ role="option"
17933
+ onMouseDown={(e) => { e.preventDefault(); onSelect(insertValue); }}
17934
+ className="relative flex flex-1 min-w-0 cursor-pointer select-none items-center px-2 py-1.5 text-sm outline-none"
17935
+ >
17936
+ {\`{{\${item.name}}}\`}
17937
+ </button>
17938
+ {item.editable && onEditVariable && (
17939
+ <button
17940
+ type="button"
17941
+ onMouseDown={(e) => { e.preventDefault(); onEditVariable(item.name); }}
17942
+ className="shrink-0 p-1.5 rounded text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
17943
+ aria-label={\`Edit \${item.name}\`}
17944
+ >
17945
+ <Pencil className="size-3.5" />
17946
+ </button>
17947
+ )}
17948
+ </div>
17949
+ );
17950
+ })}
17951
+ </div>
17952
+ ))}
17953
+ {filteredGroups.length === 0 && (
17954
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
17955
+ )}
17956
+ </div>
17401
17957
  </div>
17402
17958
  );
17403
17959
  }
17404
17960
 
17405
- // \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
17961
+ // \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
17962
+
17963
+ function VariableFormModal({
17964
+ open,
17965
+ onOpenChange,
17966
+ mode,
17967
+ initialData,
17968
+ onSave,
17969
+ }: {
17970
+ open: boolean;
17971
+ onOpenChange: (open: boolean) => void;
17972
+ mode: "create" | "edit";
17973
+ initialData?: VariableItem;
17974
+ onSave: (data: VariableFormData) => void;
17975
+ }) {
17976
+ const [name, setName] = React.useState("");
17977
+ const [description, setDescription] = React.useState("");
17978
+ const [required, setRequired] = React.useState(false);
17979
+ const [nameError, setNameError] = React.useState("");
17980
+
17981
+ // Reset form when modal opens
17982
+ React.useEffect(() => {
17983
+ if (open) {
17984
+ setName(initialData?.name ?? "");
17985
+ setDescription(initialData?.description ?? "");
17986
+ setRequired(initialData?.required ?? false);
17987
+ setNameError("");
17988
+ }
17989
+ }, [open, initialData]);
17990
+
17991
+ const validateName = (v: string) => {
17992
+ if (!v.trim()) return "";
17993
+ if (!VARIABLE_NAME_REGEX.test(v)) {
17994
+ return "Variable name should start with alphabet; Cannot have special characters except underscore (_)";
17995
+ }
17996
+ return "";
17997
+ };
17998
+
17999
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
18000
+ const v = e.target.value;
18001
+ setName(v);
18002
+ setNameError(validateName(v));
18003
+ };
18004
+
18005
+ const handleSave = () => {
18006
+ const error = validateName(name);
18007
+ if (error || !name.trim()) {
18008
+ setNameError(error || "Variable name is required");
18009
+ return;
18010
+ }
18011
+ onSave({ name: name.trim(), description: description.trim() || undefined, required });
18012
+ };
18013
+
18014
+ return (
18015
+ <FormModal
18016
+ open={open}
18017
+ onOpenChange={onOpenChange}
18018
+ title={mode === "create" ? "Create new variable" : "Edit variable"}
18019
+ saveButtonText={mode === "create" ? "Save" : "Save Changes"}
18020
+ disableSave={!name.trim() || !!nameError}
18021
+ onSave={handleSave}
18022
+ size="default"
18023
+ >
18024
+ <div className="flex flex-col gap-4">
18025
+ <div className="flex flex-col gap-1.5">
18026
+ <label className="text-sm font-medium text-semantic-text-muted">
18027
+ Variable name{" "}
18028
+ <span className="text-semantic-error-primary">*</span>
18029
+ </label>
18030
+ <div className="relative">
18031
+ <input
18032
+ type="text"
18033
+ value={name}
18034
+ onChange={handleNameChange}
18035
+ placeholder="e.g., customer_name"
18036
+ maxLength={VARIABLE_NAME_MAX}
18037
+ className={cn(inputCls, "pr-16")}
18038
+ />
18039
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18040
+ {name.length}/{VARIABLE_NAME_MAX}
18041
+ </span>
18042
+ </div>
18043
+ <span className={cn("text-sm", nameError ? "text-semantic-error-primary" : "text-semantic-text-muted")}>
18044
+ {nameError || "Variable name should start with alphabet; Cannot have special characters except underscore (_)"}
18045
+ </span>
18046
+ </div>
18047
+ <TextField
18048
+ label="Description (optional)"
18049
+ placeholder="What this variable represents"
18050
+ value={description}
18051
+ onChange={(e) => setDescription(e.target.value)}
18052
+ />
18053
+ <div className="flex flex-col gap-1.5">
18054
+ <span className="text-sm font-medium text-semantic-text-muted">Required</span>
18055
+ <div className="flex items-center gap-6">
18056
+ <label className="flex items-center gap-2 cursor-pointer">
18057
+ <input
18058
+ type="radio"
18059
+ name="variable-required"
18060
+ checked={required}
18061
+ onChange={() => setRequired(true)}
18062
+ className="size-4 accent-semantic-primary"
18063
+ />
18064
+ <span className="text-base text-semantic-text-primary">Yes</span>
18065
+ </label>
18066
+ <label className="flex items-center gap-2 cursor-pointer">
18067
+ <input
18068
+ type="radio"
18069
+ name="variable-required"
18070
+ checked={!required}
18071
+ onChange={() => setRequired(false)}
18072
+ className="size-4 accent-semantic-primary"
18073
+ />
18074
+ <span className="text-base text-semantic-text-primary">No</span>
18075
+ </label>
18076
+ </div>
18077
+ </div>
18078
+ </div>
18079
+ </FormModal>
18080
+ );
18081
+ }
18082
+
18083
+ // \u2500\u2500 VariableInput \u2014 input with {{ autocomplete + badge display \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17406
18084
 
17407
18085
  function VariableInput({
17408
18086
  value,
17409
18087
  onChange,
17410
18088
  sessionVariables,
18089
+ variableGroups,
18090
+ onAddVariable,
18091
+ onEditVariable,
17411
18092
  placeholder,
17412
18093
  maxLength,
17413
18094
  className,
17414
18095
  inputRef: externalInputRef,
18096
+ disabled,
17415
18097
  ...inputProps
17416
18098
  }: {
17417
18099
  value: string;
17418
18100
  onChange: (v: string) => void;
17419
18101
  sessionVariables: string[];
18102
+ variableGroups?: VariableGroup[];
18103
+ onAddVariable?: () => void;
18104
+ onEditVariable?: (variable: string) => void;
17420
18105
  placeholder?: string;
17421
18106
  maxLength?: number;
17422
18107
  className?: string;
17423
18108
  inputRef?: React.RefObject<HTMLInputElement>;
18109
+ disabled?: boolean;
17424
18110
  [k: string]: unknown;
17425
18111
  }) {
17426
18112
  const internalRef = React.useRef<HTMLInputElement>(null);
17427
18113
  const inputRef = externalInputRef ?? internalRef;
18114
+ const displayRef = React.useRef<HTMLDivElement>(null);
17428
18115
  const [trigger, setTrigger] = React.useState<TriggerState | null>(null);
17429
18116
  const [popupStyle, setPopupStyle] = React.useState<React.CSSProperties | undefined>();
18117
+ const [isEditing, setIsEditing] = React.useState(false);
18118
+ const [isExpanded, setIsExpanded] = React.useState(false);
18119
+ const [isOverflowing, setIsOverflowing] = React.useState(false);
17430
18120
 
17431
18121
  const filtered = trigger
17432
18122
  ? sessionVariables.filter((v) => v.toLowerCase().includes(trigger.query))
17433
18123
  : [];
17434
18124
 
18125
+ // Parse value into text + variable segments
18126
+ const segments = React.useMemo(() => parseValueSegments(value), [value]);
18127
+ const hasVariables = segments.some((s) => s.type === "var");
18128
+ const showDisplay = !isEditing && value.length > 0 && hasVariables;
18129
+
18130
+ // Check overflow in display mode
18131
+ React.useEffect(() => {
18132
+ if (showDisplay && displayRef.current && !isExpanded) {
18133
+ const el = displayRef.current;
18134
+ setIsOverflowing(el.scrollWidth > el.clientWidth);
18135
+ } else {
18136
+ setIsOverflowing(false);
18137
+ }
18138
+ }, [showDisplay, value, isExpanded]);
18139
+
17435
18140
  const updatePopupPos = (el: HTMLInputElement, cursor: number) => {
17436
18141
  const caret = getCaretPixelPos(el, cursor);
17437
18142
  const lineHeight = parseFloat(window.getComputedStyle(el).lineHeight) || 20;
@@ -17460,13 +18165,15 @@ function VariableInput({
17460
18165
 
17461
18166
  return (
17462
18167
  <div className="relative w-full">
18168
+ {/* Input \u2014 always in DOM, hidden when display mode is active */}
17463
18169
  <input
17464
18170
  ref={inputRef}
17465
18171
  type="text"
17466
18172
  value={value}
17467
18173
  placeholder={placeholder}
17468
18174
  maxLength={maxLength}
17469
- className={className}
18175
+ disabled={disabled}
18176
+ className={cn(className, showDisplay && "opacity-0 pointer-events-none")}
17470
18177
  onChange={(e) => {
17471
18178
  onChange(e.target.value);
17472
18179
  const cursor = e.target.selectionStart ?? e.target.value.length;
@@ -17478,10 +18185,88 @@ function VariableInput({
17478
18185
  onKeyDown={(e) => {
17479
18186
  if (e.key === "Escape") clearTrigger();
17480
18187
  }}
17481
- onBlur={() => clearTrigger()}
18188
+ onFocus={() => setIsEditing(true)}
18189
+ onBlur={() => {
18190
+ clearTrigger();
18191
+ setIsEditing(false);
18192
+ setIsExpanded(false);
18193
+ }}
17482
18194
  {...inputProps}
17483
18195
  />
17484
- <VarPopup variables={filtered} onSelect={handleSelect} style={popupStyle} />
18196
+
18197
+ {/* Display mode \u2014 variable badges + text + overflow */}
18198
+ {showDisplay && (
18199
+ <div
18200
+ className={cn(
18201
+ "absolute cursor-text",
18202
+ !isExpanded && "inset-0 flex items-center",
18203
+ isExpanded && "inset-x-0 top-0 z-10",
18204
+ disabled && "opacity-50 cursor-not-allowed"
18205
+ )}
18206
+ onClick={() => {
18207
+ if (!disabled) inputRef.current?.focus();
18208
+ }}
18209
+ >
18210
+ <div
18211
+ ref={displayRef}
18212
+ className={cn(
18213
+ "flex items-center gap-1 px-2",
18214
+ !isExpanded && "flex-1 min-w-0 overflow-hidden",
18215
+ isExpanded && "flex-wrap bg-semantic-bg-primary border border-semantic-border-input rounded py-1.5 shadow-sm"
18216
+ )}
18217
+ >
18218
+ {segments.map((seg, i) =>
18219
+ seg.type === "text" ? (
18220
+ <span key={i} className="text-sm text-semantic-text-primary whitespace-pre shrink-0">{seg.content}</span>
18221
+ ) : (
18222
+ <span
18223
+ key={i}
18224
+ 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"
18225
+ >
18226
+ {seg.name}
18227
+ {onEditVariable && (
18228
+ <button
18229
+ type="button"
18230
+ onMouseDown={(e) => {
18231
+ e.preventDefault();
18232
+ e.stopPropagation();
18233
+ onEditVariable(seg.name);
18234
+ }}
18235
+ className="p-0.5 text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
18236
+ >
18237
+ <Pencil className="size-3" />
18238
+ </button>
18239
+ )}
18240
+ </span>
18241
+ )
18242
+ )}
18243
+ </div>
18244
+ {isOverflowing && !isExpanded && (
18245
+ <button
18246
+ type="button"
18247
+ onMouseDown={(e) => {
18248
+ e.preventDefault();
18249
+ e.stopPropagation();
18250
+ setIsExpanded(true);
18251
+ }}
18252
+ className="shrink-0 px-1 text-sm font-medium text-semantic-text-muted hover:text-semantic-text-primary"
18253
+ >
18254
+ ...
18255
+ </button>
18256
+ )}
18257
+ </div>
18258
+ )}
18259
+
18260
+ {/* VarPopup */}
18261
+ <VarPopup
18262
+ variables={filtered}
18263
+ variableGroups={trigger ? variableGroups : undefined}
18264
+ filterQuery={trigger?.query ?? ""}
18265
+ onSelect={handleSelect}
18266
+ onAddVariable={onAddVariable}
18267
+ onEditVariable={onEditVariable}
18268
+ style={popupStyle}
18269
+ />
17485
18270
  </div>
17486
18271
  );
17487
18272
  }
@@ -17491,7 +18276,7 @@ const inputCls = cn(
17491
18276
  "w-full h-[42px] px-4 text-base rounded border",
17492
18277
  "border-semantic-border-input bg-semantic-bg-primary",
17493
18278
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17494
- "outline-none hover:border-semantic-border-input-focus",
18279
+ "outline-none",
17495
18280
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17496
18281
  "disabled:opacity-50 disabled:cursor-not-allowed"
17497
18282
  );
@@ -17500,7 +18285,7 @@ const textareaCls = cn(
17500
18285
  "w-full px-4 py-2.5 text-base rounded border resize-none",
17501
18286
  "border-semantic-border-input bg-semantic-bg-primary",
17502
18287
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17503
- "outline-none hover:border-semantic-border-input-focus",
18288
+ "outline-none",
17504
18289
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17505
18290
  "disabled:opacity-50 disabled:cursor-not-allowed"
17506
18291
  );
@@ -17518,6 +18303,9 @@ function KeyValueTable({
17518
18303
  keyRegex,
17519
18304
  keyRegexError,
17520
18305
  sessionVariables = [],
18306
+ variableGroups,
18307
+ onAddVariable,
18308
+ onEditVariable,
17521
18309
  disabled = false,
17522
18310
  }: {
17523
18311
  rows: KeyValuePair[];
@@ -17529,6 +18317,9 @@ function KeyValueTable({
17529
18317
  keyRegex?: RegExp;
17530
18318
  keyRegexError?: string;
17531
18319
  sessionVariables?: string[];
18320
+ variableGroups?: VariableGroup[];
18321
+ onAddVariable?: () => void;
18322
+ onEditVariable?: (variable: string) => void;
17532
18323
  disabled?: boolean;
17533
18324
  }) {
17534
18325
  const update = (id: string, patch: Partial<KeyValuePair>) => {
@@ -17560,14 +18351,14 @@ function KeyValueTable({
17560
18351
 
17561
18352
  return (
17562
18353
  <div className="flex flex-col gap-1.5">
17563
- <span className="text-xs text-semantic-text-muted">{label}</span>
17564
- <div className="border border-semantic-border-layout rounded overflow-hidden">
18354
+ <span className="text-sm text-semantic-text-muted">{label}</span>
18355
+ <div className="border border-semantic-border-layout rounded">
17565
18356
  {/* Column headers \u2014 desktop only; border-r on Key cell defines column boundary */}
17566
- <div className="hidden sm:flex bg-semantic-bg-ui border-b border-semantic-border-layout">
17567
- <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">
18357
+ <div className="hidden sm:flex border-b border-semantic-border-layout rounded-t">
18358
+ <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">
17568
18359
  Key
17569
18360
  </div>
17570
- <div className="flex-[2] min-w-0 px-3 py-2 text-xs font-semibold text-semantic-text-muted">
18361
+ <div className="flex-[2] min-w-0 px-3 py-2 text-sm font-semibold text-semantic-text-muted">
17571
18362
  Value
17572
18363
  </div>
17573
18364
  <div className="w-10 shrink-0" aria-hidden="true" />
@@ -17583,7 +18374,7 @@ function KeyValueTable({
17583
18374
  >
17584
18375
  {/* Key column \u2014 border-r on column (not input) so it aligns with header */}
17585
18376
  <div className="flex-1 flex flex-col min-w-0 sm:border-r sm:border-semantic-border-layout">
17586
- <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-[10px] font-semibold text-semantic-text-muted uppercase tracking-wide">
18377
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17587
18378
  Key
17588
18379
  </span>
17589
18380
  <input
@@ -17594,45 +18385,36 @@ function KeyValueTable({
17594
18385
  maxLength={keyMaxLength}
17595
18386
  disabled={disabled}
17596
18387
  className={cn(
17597
- "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",
18388
+ "w-full px-3 py-2.5 text-base text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none",
17598
18389
  "disabled:opacity-50 disabled:cursor-not-allowed",
17599
- errors.key && "border-semantic-error-primary"
18390
+ errors.key && "text-semantic-error-primary"
17600
18391
  )}
17601
18392
  aria-invalid={Boolean(errors.key)}
17602
- aria-describedby={errors.key ? \`err-key-\${row.id}\` : undefined}
17603
18393
  />
17604
- {errors.key && (
17605
- <p id={\`err-key-\${row.id}\`} className="m-0 px-3 pt-0.5 text-xs text-semantic-error-primary">
17606
- {errors.key}
17607
- </p>
17608
- )}
17609
18394
  </div>
17610
18395
 
17611
18396
  {/* Value column \u2014 uses VariableInput for {{ autocomplete */}
17612
18397
  <div className="flex-[2] flex flex-col min-w-0">
17613
- <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-[10px] font-semibold text-semantic-text-muted uppercase tracking-wide">
18398
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17614
18399
  Value
17615
18400
  </span>
17616
18401
  <VariableInput
17617
18402
  value={row.value}
17618
18403
  onChange={(v) => update(row.id, { value: v })}
17619
18404
  sessionVariables={sessionVariables}
18405
+ variableGroups={variableGroups}
18406
+ onAddVariable={onAddVariable}
18407
+ onEditVariable={onEditVariable}
17620
18408
  placeholder="Type {{ to add variables"
17621
18409
  maxLength={valueMaxLength}
17622
18410
  disabled={disabled}
17623
18411
  className={cn(
17624
- "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",
18412
+ "w-full px-3 py-2.5 text-base text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none",
17625
18413
  "disabled:opacity-50 disabled:cursor-not-allowed",
17626
- errors.value && "border-semantic-error-primary"
18414
+ errors.value && "text-semantic-error-primary"
17627
18415
  )}
17628
18416
  aria-invalid={Boolean(errors.value)}
17629
- aria-describedby={errors.value ? \`err-value-\${row.id}\` : undefined}
17630
18417
  />
17631
- {errors.value && (
17632
- <p id={\`err-value-\${row.id}\`} className="m-0 px-3 pt-0.5 text-xs text-semantic-error-primary">
17633
- {errors.value}
17634
- </p>
17635
- )}
17636
18418
  </div>
17637
18419
 
17638
18420
  {/* Action column \u2014 delete aligned with row (same as KeyValueRow / knowledge-base-card) */}
@@ -17659,7 +18441,7 @@ function KeyValueTable({
17659
18441
  onClick={add}
17660
18442
  disabled={disabled}
17661
18443
  className={cn(
17662
- "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",
18444
+ "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",
17663
18445
  disabled && "opacity-50 cursor-not-allowed"
17664
18446
  )}
17665
18447
  >
@@ -17667,15 +18449,35 @@ function KeyValueTable({
17667
18449
  <span>Add row</span>
17668
18450
  </button>
17669
18451
  </div>
18452
+
18453
+ {/* Collected row errors \u2014 shown below the table */}
18454
+ {(() => {
18455
+ const allErrors = rows
18456
+ .map((row) => {
18457
+ const errs = getErrors(row);
18458
+ const msgs: string[] = [];
18459
+ if (errs.key) msgs.push(errs.key);
18460
+ if (errs.value) msgs.push(errs.value);
18461
+ return msgs;
18462
+ })
18463
+ .flat();
18464
+ if (allErrors.length === 0) return null;
18465
+ // Deduplicate
18466
+ const unique = Array.from(new Set(allErrors));
18467
+ return (
18468
+ <div className="flex flex-col gap-0.5">
18469
+ {unique.map((msg) => (
18470
+ <p key={msg} className="m-0 text-sm text-semantic-error-primary">{msg}</p>
18471
+ ))}
18472
+ </div>
18473
+ );
18474
+ })()}
17670
18475
  </div>
17671
18476
  );
17672
18477
  }
17673
18478
 
17674
18479
  // \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
17675
- export const CreateFunctionModal = React.forwardRef<
17676
- HTMLDivElement,
17677
- CreateFunctionModalProps
17678
- >(
18480
+ export const CreateFunctionModal = React.forwardRef(
17679
18481
  (
17680
18482
  {
17681
18483
  open,
@@ -17689,10 +18491,13 @@ export const CreateFunctionModal = React.forwardRef<
17689
18491
  initialStep = 1,
17690
18492
  initialTab = "header",
17691
18493
  sessionVariables = DEFAULT_SESSION_VARIABLES,
18494
+ variableGroups,
18495
+ onAddVariable,
18496
+ onEditVariable,
17692
18497
  disabled = false,
17693
18498
  className,
17694
- },
17695
- ref
18499
+ }: CreateFunctionModalProps,
18500
+ ref: React.Ref<HTMLDivElement>
17696
18501
  ) => {
17697
18502
  const [step, setStep] = React.useState<1 | 2>(initialStep);
17698
18503
 
@@ -17713,6 +18518,35 @@ export const CreateFunctionModal = React.forwardRef<
17713
18518
  const [urlError, setUrlError] = React.useState("");
17714
18519
  const [bodyError, setBodyError] = React.useState("");
17715
18520
 
18521
+ // Variable modal state
18522
+ const [varModalOpen, setVarModalOpen] = React.useState(false);
18523
+ const [varModalMode, setVarModalMode] = React.useState<"create" | "edit">("create");
18524
+ const [varModalInitialData, setVarModalInitialData] = React.useState<VariableItem | undefined>();
18525
+
18526
+ const handleAddVariableClick = () => {
18527
+ setVarModalMode("create");
18528
+ setVarModalInitialData(undefined);
18529
+ setVarModalOpen(true);
18530
+ };
18531
+
18532
+ const handleEditVariableClick = (variableName: string) => {
18533
+ const variable = variableGroups
18534
+ ?.flatMap((g) => g.items)
18535
+ .find((item) => item.name === variableName);
18536
+ setVarModalMode("edit");
18537
+ setVarModalInitialData(variable ?? { name: variableName, editable: true });
18538
+ setVarModalOpen(true);
18539
+ };
18540
+
18541
+ const handleVariableSave = (data: VariableFormData) => {
18542
+ if (varModalMode === "create") {
18543
+ onAddVariable?.(data);
18544
+ } else {
18545
+ onEditVariable?.(varModalInitialData?.name ?? "", data);
18546
+ }
18547
+ setVarModalOpen(false);
18548
+ };
18549
+
17716
18550
  // Variable trigger state for URL and body
17717
18551
  const urlInputRef = React.useRef<HTMLInputElement>(null);
17718
18552
  const bodyTextareaRef = React.useRef<HTMLTextAreaElement>(null);
@@ -17807,14 +18641,7 @@ export const CreateFunctionModal = React.forwardRef<
17807
18641
  onOpenChange(false);
17808
18642
  }, [reset, onOpenChange]);
17809
18643
 
17810
- const supportsBody = METHODS_WITH_BODY.includes(method);
17811
-
17812
- // When switching to a method without body, reset to header tab if body was active
17813
- React.useEffect(() => {
17814
- if (!supportsBody && activeTab === "body") {
17815
- setActiveTab("header");
17816
- }
17817
- }, [supportsBody, activeTab]);
18644
+ // Body tab is always visible regardless of HTTP method
17818
18645
 
17819
18646
  const validateName = (value: string) => {
17820
18647
  if (value.trim() && !FUNCTION_NAME_REGEX.test(value.trim())) {
@@ -17949,11 +18776,10 @@ export const CreateFunctionModal = React.forwardRef<
17949
18776
  body: "Body",
17950
18777
  };
17951
18778
 
17952
- const visibleTabs: FunctionTabType[] = supportsBody
17953
- ? ["header", "queryParams", "body"]
17954
- : ["header", "queryParams"];
18779
+ const visibleTabs: FunctionTabType[] = ["header", "queryParams", "body"];
17955
18780
 
17956
18781
  return (
18782
+ <>
17957
18783
  <Dialog open={open} onOpenChange={onOpenChange}>
17958
18784
  <DialogContent
17959
18785
  ref={ref}
@@ -17961,7 +18787,7 @@ export const CreateFunctionModal = React.forwardRef<
17961
18787
  hideCloseButton
17962
18788
  className={cn(
17963
18789
  "flex flex-col gap-0 p-0 w-[calc(100vw-2rem)] sm:w-full",
17964
- "max-h-[calc(100svh-2rem)] overflow-hidden",
18790
+ "max-h-[calc(100vh-2rem)] overflow-hidden",
17965
18791
  className
17966
18792
  )}
17967
18793
  >
@@ -17981,7 +18807,7 @@ export const CreateFunctionModal = React.forwardRef<
17981
18807
  </div>
17982
18808
 
17983
18809
  {/* \u2500\u2500 Scrollable body \u2500\u2500 */}
17984
- <div className="flex-1 overflow-y-auto min-h-0 px-4 py-5 sm:px-6">
18810
+ <div className="flex-1 overflow-y-auto min-h-0 overscroll-contain px-4 py-5 sm:px-6">
17985
18811
  {/* \u2500 Step 1 \u2500 */}
17986
18812
  {step === 1 && (
17987
18813
  <div className="flex flex-col gap-5">
@@ -18008,44 +18834,33 @@ export const CreateFunctionModal = React.forwardRef<
18008
18834
  placeholder="Enter name of the function"
18009
18835
  className={cn(inputCls, "pr-16")}
18010
18836
  />
18011
- <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs italic text-semantic-text-muted pointer-events-none">
18837
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18012
18838
  {name.length}/{FUNCTION_NAME_MAX}
18013
18839
  </span>
18014
18840
  </div>
18015
18841
  {nameError && (
18016
- <p className="m-0 text-xs text-semantic-error-primary">{nameError}</p>
18842
+ <p className="m-0 text-sm text-semantic-error-primary">{nameError}</p>
18017
18843
  )}
18018
18844
  </div>
18019
18845
 
18020
- <div className="flex flex-col gap-1.5">
18021
- <label
18022
- htmlFor="fn-prompt"
18023
- className="text-sm font-semibold text-semantic-text-primary"
18024
- >
18025
- Prompt{" "}
18026
- <span className="text-semantic-error-primary">*</span>
18027
- </label>
18028
- <div className="relative">
18029
- <textarea
18030
- id="fn-prompt"
18031
- value={prompt}
18032
- maxLength={promptMaxLength}
18033
- disabled={disabled}
18034
- onChange={(e) => setPrompt(e.target.value)}
18035
- placeholder="Enter the description of the function"
18036
- rows={5}
18037
- className={cn(textareaCls, "pb-7")}
18038
- />
18039
- <span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted pointer-events-none">
18040
- {prompt.length}/{promptMaxLength}
18041
- </span>
18042
- </div>
18043
- {prompt.length > 0 && prompt.trim().length < promptMinLength && (
18044
- <p className="m-0 text-xs text-semantic-error-primary">
18045
- Minimum {promptMinLength} characters required
18046
- </p>
18047
- )}
18048
- </div>
18846
+ <Textarea
18847
+ id="fn-prompt"
18848
+ label="Prompt"
18849
+ required
18850
+ value={prompt}
18851
+ maxLength={promptMaxLength}
18852
+ showCount
18853
+ disabled={disabled}
18854
+ onChange={(e) => setPrompt(e.target.value)}
18855
+ placeholder="Enter the description of the function"
18856
+ rows={5}
18857
+ labelClassName="font-semibold text-semantic-text-primary"
18858
+ error={
18859
+ prompt.length > 0 && prompt.trim().length < promptMinLength
18860
+ ? \`Minimum \${promptMinLength} characters required\`
18861
+ : undefined
18862
+ }
18863
+ />
18049
18864
  </div>
18050
18865
  )}
18051
18866
 
@@ -18054,13 +18869,12 @@ export const CreateFunctionModal = React.forwardRef<
18054
18869
  <div className="flex flex-col gap-5">
18055
18870
  {/* API URL \u2014 always a single combined row */}
18056
18871
  <div className="flex flex-col gap-1.5">
18057
- <span className="text-xs text-semantic-text-muted tracking-[0.048px]">
18872
+ <span className="text-sm text-semantic-text-muted tracking-[0.048px]">
18058
18873
  API URL
18059
18874
  </span>
18060
18875
  <div
18061
18876
  className={cn(
18062
18877
  "flex h-[42px] rounded border border-semantic-border-input overflow-visible bg-semantic-bg-primary",
18063
- "hover:border-semantic-border-input-focus",
18064
18878
  "focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
18065
18879
  "transition-shadow"
18066
18880
  )}
@@ -18121,11 +18935,19 @@ export const CreateFunctionModal = React.forwardRef<
18121
18935
  disabled && "opacity-50 cursor-not-allowed"
18122
18936
  )}
18123
18937
  />
18124
- <VarPopup variables={filteredUrlVars} onSelect={handleUrlVarSelect} style={urlPopupStyle} />
18938
+ <VarPopup
18939
+ variables={filteredUrlVars}
18940
+ variableGroups={urlTrigger ? variableGroups : undefined}
18941
+ filterQuery={urlTrigger?.query ?? ""}
18942
+ onSelect={handleUrlVarSelect}
18943
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
18944
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
18945
+ style={urlPopupStyle}
18946
+ />
18125
18947
  </div>
18126
18948
  </div>
18127
18949
  {urlError && (
18128
- <p className="m-0 text-xs text-semantic-error-primary">{urlError}</p>
18950
+ <p className="m-0 text-sm text-semantic-error-primary">{urlError}</p>
18129
18951
  )}
18130
18952
  </div>
18131
18953
 
@@ -18165,6 +18987,9 @@ export const CreateFunctionModal = React.forwardRef<
18165
18987
  keyRegex={HEADER_KEY_REGEX}
18166
18988
  keyRegexError="Invalid header key. Use only alphanumeric and !#$%&'*+-.^_\`|~ characters."
18167
18989
  sessionVariables={sessionVariables}
18990
+ variableGroups={variableGroups}
18991
+ onAddVariable={handleAddVariableClick}
18992
+ onEditVariable={handleEditVariableClick}
18168
18993
  disabled={disabled}
18169
18994
  />
18170
18995
  )}
@@ -18184,12 +19009,15 @@ export const CreateFunctionModal = React.forwardRef<
18184
19009
  };
18185
19010
  }}
18186
19011
  sessionVariables={sessionVariables}
19012
+ variableGroups={variableGroups}
19013
+ onAddVariable={handleAddVariableClick}
19014
+ onEditVariable={handleEditVariableClick}
18187
19015
  disabled={disabled}
18188
19016
  />
18189
19017
  )}
18190
19018
  {activeTab === "body" && (
18191
19019
  <div className="flex flex-col gap-1.5">
18192
- <span className="text-xs text-semantic-text-muted">
19020
+ <span className="text-sm text-semantic-text-muted">
18193
19021
  Body
18194
19022
  </span>
18195
19023
  <div className={cn("relative")}>
@@ -18219,13 +19047,21 @@ export const CreateFunctionModal = React.forwardRef<
18219
19047
  rows={6}
18220
19048
  className={cn(textareaCls, "pb-7")}
18221
19049
  />
18222
- <span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted pointer-events-none">
19050
+ <span className="absolute bottom-2 right-3 text-sm text-semantic-text-muted pointer-events-none">
18223
19051
  {body.length}/{BODY_MAX}
18224
19052
  </span>
18225
- <VarPopup variables={filteredBodyVars} onSelect={handleBodyVarSelect} style={bodyPopupStyle} />
19053
+ <VarPopup
19054
+ variables={filteredBodyVars}
19055
+ variableGroups={bodyTrigger ? variableGroups : undefined}
19056
+ filterQuery={bodyTrigger?.query ?? ""}
19057
+ onSelect={handleBodyVarSelect}
19058
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
19059
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
19060
+ style={bodyPopupStyle}
19061
+ />
18226
19062
  </div>
18227
19063
  {bodyError && (
18228
- <p className="m-0 text-xs text-semantic-error-primary">{bodyError}</p>
19064
+ <p className="m-0 text-sm text-semantic-error-primary">{bodyError}</p>
18229
19065
  )}
18230
19066
  </div>
18231
19067
  )}
@@ -18234,7 +19070,7 @@ export const CreateFunctionModal = React.forwardRef<
18234
19070
  {/* Test Your API */}
18235
19071
  <div className="flex flex-col gap-4">
18236
19072
  <div className="flex flex-col gap-1.5">
18237
- <span className="text-xs font-semibold text-semantic-text-muted tracking-[0.048px]">
19073
+ <span className="text-sm font-semibold text-semantic-text-muted tracking-[0.048px]">
18238
19074
  Test Your API
18239
19075
  </span>
18240
19076
  <div className="border-t border-semantic-border-layout" />
@@ -18243,12 +19079,12 @@ export const CreateFunctionModal = React.forwardRef<
18243
19079
  {/* Variable test values \u2014 shown when URL/body/params contain {{variables}} */}
18244
19080
  {testableVars.length > 0 && (
18245
19081
  <div className="flex flex-col gap-2">
18246
- <span className="text-xs text-semantic-text-muted">
19082
+ <span className="text-sm text-semantic-text-muted">
18247
19083
  Variable values for testing
18248
19084
  </span>
18249
19085
  {testableVars.map((variable) => (
18250
19086
  <div key={variable} className="flex items-center gap-3">
18251
- <span className="text-xs text-semantic-text-muted font-mono shrink-0 min-w-[120px]">
19087
+ <span className="text-sm text-semantic-text-muted font-mono shrink-0 min-w-[120px]">
18252
19088
  {variable}
18253
19089
  </span>
18254
19090
  <input
@@ -18278,7 +19114,7 @@ export const CreateFunctionModal = React.forwardRef<
18278
19114
  </button>
18279
19115
 
18280
19116
  <div className="flex flex-col gap-1.5">
18281
- <span className="text-xs text-semantic-text-muted">
19117
+ <span className="text-sm text-semantic-text-muted">
18282
19118
  Response from API
18283
19119
  </span>
18284
19120
  <textarea
@@ -18336,6 +19172,15 @@ export const CreateFunctionModal = React.forwardRef<
18336
19172
  </div>
18337
19173
  </DialogContent>
18338
19174
  </Dialog>
19175
+
19176
+ <VariableFormModal
19177
+ open={varModalOpen}
19178
+ onOpenChange={setVarModalOpen}
19179
+ mode={varModalMode}
19180
+ initialData={varModalInitialData}
19181
+ onSave={handleVariableSave}
19182
+ />
19183
+ </>
18339
19184
  );
18340
19185
  }
18341
19186
  );
@@ -18547,7 +19392,7 @@ const DEFAULT_LANGUAGE_OPTIONS: LanguageOption[] = [
18547
19392
 
18548
19393
  // \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
18549
19394
 
18550
- const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
19395
+ const BotIdentityCard = React.forwardRef(
18551
19396
  (
18552
19397
  {
18553
19398
  data,
@@ -18561,8 +19406,8 @@ const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
18561
19406
  playingVoice,
18562
19407
  disabled,
18563
19408
  className,
18564
- },
18565
- ref
19409
+ }: BotIdentityCardProps,
19410
+ ref: React.Ref<HTMLDivElement>
18566
19411
  ) => {
18567
19412
  return (
18568
19413
  <div
@@ -18907,7 +19752,7 @@ function SectionCard({
18907
19752
 
18908
19753
  // \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
18909
19754
 
18910
- const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
19755
+ const BotBehaviorCard = React.forwardRef(
18911
19756
  (
18912
19757
  {
18913
19758
  data,
@@ -18917,8 +19762,8 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
18917
19762
  maxLength = 5000,
18918
19763
  disabled,
18919
19764
  className,
18920
- },
18921
- ref
19765
+ }: BotBehaviorCardProps,
19766
+ ref: React.Ref<HTMLDivElement>
18922
19767
  ) => {
18923
19768
  const prompt = data.systemPrompt ?? "";
18924
19769
  const MAX = maxLength;
@@ -19145,7 +19990,7 @@ const STATUS_CONFIG: Record<BOT_KNOWLEDGE_STATUS, { label: string; variant: Badg
19145
19990
 
19146
19991
  // \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
19147
19992
 
19148
- const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProps>(
19993
+ const KnowledgeBaseCard = React.forwardRef(
19149
19994
  (
19150
19995
  {
19151
19996
  files,
@@ -19157,8 +20002,8 @@ const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProp
19157
20002
  downloadDisabled,
19158
20003
  deleteDisabled,
19159
20004
  className,
19160
- },
19161
- ref
20005
+ }: KnowledgeBaseCardProps,
20006
+ ref: React.Ref<HTMLDivElement>
19162
20007
  ) => {
19163
20008
  return (
19164
20009
  <div
@@ -19310,8 +20155,8 @@ export interface FunctionsCardProps {
19310
20155
 
19311
20156
  // \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
19312
20157
 
19313
- const FunctionsCard = React.forwardRef<HTMLDivElement, FunctionsCardProps>(
19314
- ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }, ref) => {
20158
+ const FunctionsCard = React.forwardRef(
20159
+ ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }: FunctionsCardProps, ref: React.Ref<HTMLDivElement>) => {
19315
20160
  return (
19316
20161
  <div
19317
20162
  ref={ref}
@@ -19497,8 +20342,8 @@ function Field({
19497
20342
 
19498
20343
  // \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
19499
20344
 
19500
- const FrustrationHandoverCard = React.forwardRef<HTMLDivElement, FrustrationHandoverCardProps>(
19501
- ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }, ref) => {
20345
+ const FrustrationHandoverCard = React.forwardRef(
20346
+ ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }: FrustrationHandoverCardProps, ref: React.Ref<HTMLDivElement>) => {
19502
20347
  return (
19503
20348
  <div
19504
20349
  ref={ref}
@@ -19671,7 +20516,7 @@ function NumberSpinner({
19671
20516
 
19672
20517
  // \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
19673
20518
 
19674
- const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCardProps>(
20519
+ const AdvancedSettingsCard = React.forwardRef(
19675
20520
  (
19676
20521
  {
19677
20522
  data,
@@ -19682,8 +20527,8 @@ const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCa
19682
20527
  callEndThresholdMax = 10,
19683
20528
  disabled,
19684
20529
  className,
19685
- },
19686
- ref
20530
+ }: AdvancedSettingsCardProps,
20531
+ ref: React.Ref<HTMLDivElement>
19687
20532
  ) => {
19688
20533
  return (
19689
20534
  <div
@@ -19849,10 +20694,7 @@ function PromptField({
19849
20694
 
19850
20695
  // \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
19851
20696
 
19852
- const FallbackPromptsCard = React.forwardRef<
19853
- HTMLDivElement,
19854
- FallbackPromptsCardProps
19855
- >(
20697
+ const FallbackPromptsCard = React.forwardRef(
19856
20698
  (
19857
20699
  {
19858
20700
  data,
@@ -19863,8 +20705,8 @@ const FallbackPromptsCard = React.forwardRef<
19863
20705
  disabled,
19864
20706
  defaultOpen = false,
19865
20707
  className,
19866
- },
19867
- ref
20708
+ }: FallbackPromptsCardProps,
20709
+ ref: React.Ref<HTMLDivElement>
19868
20710
  ) => {
19869
20711
  return (
19870
20712
  <div
@@ -19945,6 +20787,35 @@ export interface KeyValuePair {
19945
20787
  value: string;
19946
20788
  }
19947
20789
 
20790
+ /** A single variable shown in the {{ autocomplete popup */
20791
+ export interface VariableItem {
20792
+ /** Display name (e.g., "Order_id") */
20793
+ name: string;
20794
+ /** Value inserted into the input. Defaults to \`{{name}}\` if omitted */
20795
+ value?: string;
20796
+ /** When true, an edit icon is shown next to this variable */
20797
+ editable?: boolean;
20798
+ /** Description of what this variable represents */
20799
+ description?: string;
20800
+ /** Whether this variable is required */
20801
+ required?: boolean;
20802
+ }
20803
+
20804
+ /** Data shape for creating or editing a variable */
20805
+ export interface VariableFormData {
20806
+ name: string;
20807
+ description?: string;
20808
+ required?: boolean;
20809
+ }
20810
+
20811
+ /** A labelled group of variables in the autocomplete popup */
20812
+ export interface VariableGroup {
20813
+ /** Group header text (e.g., "Function variables", "Session variables") */
20814
+ label: string;
20815
+ /** Variables in this group */
20816
+ items: VariableItem[];
20817
+ }
20818
+
19948
20819
  export interface FunctionItem {
19949
20820
  id: string;
19950
20821
  name: string;
@@ -19995,6 +20866,12 @@ export interface CreateFunctionModalProps {
19995
20866
  initialTab?: FunctionTabType;
19996
20867
  /** Session variables available for {{ autocomplete in URL, body, header values, and query param values */
19997
20868
  sessionVariables?: string[];
20869
+ /** Grouped variables shown in the {{ autocomplete popup (overrides flat list display when provided) */
20870
+ variableGroups?: VariableGroup[];
20871
+ /** Called when user saves a new variable from the autocomplete popup */
20872
+ onAddVariable?: (data: VariableFormData) => void;
20873
+ /** Called when user edits a variable from the autocomplete popup */
20874
+ onEditVariable?: (originalName: string, data: VariableFormData) => void;
19998
20875
  /** When true, all form fields are disabled (view mode) but Next is enabled so user can browse steps */
19999
20876
  disabled?: boolean;
20000
20877
  className?: string;
@@ -20155,6 +21032,9 @@ export type {
20155
21032
  HttpMethod,
20156
21033
  FunctionTabType,
20157
21034
  SelectOption,
21035
+ VariableItem,
21036
+ VariableGroup,
21037
+ VariableFormData,
20158
21038
  } from "./types";
20159
21039
  `, prefix)
20160
21040
  }
@@ -20224,7 +21104,7 @@ function formatCurrency(amount: number, symbol: string = "\u20B9"): string {
20224
21104
  * />
20225
21105
  * \`\`\`
20226
21106
  */
20227
- export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
21107
+ export const WalletTopup = React.forwardRef(
20228
21108
  (
20229
21109
  {
20230
21110
  title = "Instant wallet top-up",
@@ -20271,8 +21151,8 @@ export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
20271
21151
  open,
20272
21152
  onOpenChange,
20273
21153
  className,
20274
- },
20275
- ref
21154
+ }: WalletTopupProps,
21155
+ ref: React.Ref<HTMLDivElement>
20276
21156
  ) => {
20277
21157
  const isOpenControlled = open !== undefined;
20278
21158
 
@@ -22274,22 +23154,99 @@ async function sync(options) {
22274
23154
  }
22275
23155
  let selectedToAdd = toAdd;
22276
23156
  let selectedToUpdate = toUpdate;
23157
+ const CUSTOM_GROUPS = {
23158
+ "attachment-preview": "Chat",
23159
+ "audio-media": "Chat",
23160
+ "carousel-media": "Chat",
23161
+ "chat-bubble": "Chat",
23162
+ "chat-composer": "Chat",
23163
+ "contact-list-item": "Chat",
23164
+ "date-divider": "Chat",
23165
+ "doc-media": "Chat",
23166
+ "image-media": "Chat",
23167
+ "reply-quote": "Chat",
23168
+ "system-message": "Chat",
23169
+ "unread-separator": "Chat",
23170
+ "video-media": "Chat",
23171
+ "event-selector": "Webhook",
23172
+ "key-value-input": "Webhook",
23173
+ "api-feature-card": "Webhook",
23174
+ "endpoint-details": "Webhook",
23175
+ "alert-configuration": "Webhook",
23176
+ "auto-pay-setup": "Plan & Payment",
23177
+ "bank-details": "Plan & Payment",
23178
+ "date-range-modal": "Plan & Payment",
23179
+ "payment-option-card": "Plan & Payment",
23180
+ "plan-upgrade-modal": "Plan & Payment",
23181
+ "plan-upgrade-summary-modal": "Plan & Payment",
23182
+ "payment-summary": "Plan & Payment",
23183
+ "let-us-drive-card": "Plan & Payment",
23184
+ "power-up-card": "Plan & Payment",
23185
+ "pricing-card": "Plan & Payment",
23186
+ "pricing-page": "Plan & Payment",
23187
+ "pricing-toggle": "Plan & Payment",
23188
+ "talk-to-us-modal": "Plan & Payment",
23189
+ "wallet-topup": "Plan & Payment",
23190
+ "file-upload-modal": "Plan & Payment",
23191
+ "plan-detail-modal": "Plan & Payment",
23192
+ "bots": "AI Bot",
23193
+ "ivr-bot": "AI Bot"
23194
+ };
22277
23195
  if (!options.yes && toAdd.length > 0) {
22278
- const { selected } = await prompts3({
22279
- type: "multiselect",
22280
- name: "selected",
22281
- message: "Select new components to add",
22282
- choices: toAdd.map((c) => {
22283
- const comp = registry[c];
22284
- const fileCount = comp.isMultiFile ? ` (${comp.files.length} files)` : "";
22285
- return { title: `${c}${fileCount}`, value: c, selected: true };
22286
- })
22287
- });
22288
- if (!selected) {
22289
- console.log(chalk5.yellow("\n Sync cancelled.\n"));
22290
- process.exit(0);
23196
+ const uiToAdd = toAdd.filter((c) => !CUSTOM_GROUPS[c]);
23197
+ const customToAdd = toAdd.filter((c) => !!CUSTOM_GROUPS[c]);
23198
+ const picked = [];
23199
+ if (uiToAdd.length > 0) {
23200
+ console.log(chalk5.cyan.bold(" \u2500\u2500 Components \u2500\u2500\n"));
23201
+ const { selected } = await prompts3({
23202
+ type: "multiselect",
23203
+ name: "selected",
23204
+ message: "Select new components to add",
23205
+ choices: uiToAdd.map((c) => ({
23206
+ title: c,
23207
+ value: c,
23208
+ selected: false
23209
+ }))
23210
+ });
23211
+ if (!selected) {
23212
+ console.log(chalk5.yellow("\n Sync cancelled.\n"));
23213
+ process.exit(0);
23214
+ }
23215
+ picked.push(...selected);
23216
+ }
23217
+ if (customToAdd.length > 0) {
23218
+ const grouped = /* @__PURE__ */ new Map();
23219
+ for (const c of customToAdd) {
23220
+ const group = CUSTOM_GROUPS[c] || "Other";
23221
+ if (!grouped.has(group)) grouped.set(group, []);
23222
+ grouped.get(group).push(c);
23223
+ }
23224
+ const sortedGroups = [...grouped.keys()].sort();
23225
+ console.log(chalk5.cyan.bold("\n \u2500\u2500 Custom \u2500\u2500\n"));
23226
+ const { selected } = await prompts3({
23227
+ type: "multiselect",
23228
+ name: "selected",
23229
+ message: "Select custom component folders to add",
23230
+ choices: sortedGroups.map((group) => {
23231
+ const components = grouped.get(group);
23232
+ const count = components.length;
23233
+ return {
23234
+ title: group,
23235
+ value: group,
23236
+ selected: false,
23237
+ description: `${count} component${count === 1 ? "" : "s"}`
23238
+ };
23239
+ })
23240
+ });
23241
+ if (!selected) {
23242
+ console.log(chalk5.yellow("\n Sync cancelled.\n"));
23243
+ process.exit(0);
23244
+ }
23245
+ for (const group of selected) {
23246
+ picked.push(...grouped.get(group));
23247
+ }
22291
23248
  }
22292
- selectedToAdd = selected;
23249
+ selectedToAdd = picked;
22293
23250
  }
22294
23251
  if (!options.yes && toUpdate.length > 0) {
22295
23252
  const { selected } = await prompts3({