myoperator-ui 0.0.216-beta.9 → 0.0.217

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 +1514 -683
  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;
@@ -12384,7 +12806,7 @@ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
12384
12806
  <div
12385
12807
  ref={ref}
12386
12808
  className={cn(
12387
- "flex h-full min-h-0 flex-col gap-6 rounded-[14px] border border-semantic-border-layout bg-card p-5 shadow-sm",
12809
+ "flex min-h-0 flex-col gap-6 rounded-[14px] border border-semantic-border-layout bg-card p-5 shadow-sm",
12388
12810
  className
12389
12811
  )}
12390
12812
  {...props}
@@ -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");
@@ -12809,9 +13231,6 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12809
13231
  {/* Header */}
12810
13232
  <div
12811
13233
  className="flex flex-col gap-4 rounded-t-xl rounded-b-lg p-4"
12812
- style={
12813
- headerBgColor ? { backgroundColor: headerBgColor } : undefined
12814
- }
12815
13234
  >
12816
13235
  {/* Plan name + badge */}
12817
13236
  <div className="flex items-center gap-4">
@@ -12869,11 +13288,11 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12869
13288
  </div>
12870
13289
  )}
12871
13290
  <Button
12872
- variant={isCurrentPlan ? "outline" : "default"}
13291
+ variant={isCurrentPlan ? "secondary" : "default"}
12873
13292
  className="w-full"
12874
13293
  onClick={onCtaClick}
12875
13294
  loading={ctaLoading}
12876
- disabled={ctaDisabled}
13295
+ disabled={ctaDisabled || isCurrentPlan}
12877
13296
  >
12878
13297
  {buttonText}
12879
13298
  </Button>
@@ -12920,29 +13339,34 @@ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
12920
13339
  </div>
12921
13340
  )}
12922
13341
 
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]" />
13342
+ {/* Bottom sections pushed to card bottom for grid alignment */}
13343
+ {(addon || (usageDetails && usageDetails.length > 0)) && (
13344
+ <div className="mt-auto flex flex-col gap-6">
13345
+ {/* Addon */}
13346
+ {addon && (
13347
+ <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
13348
+ {addon.icon && (
13349
+ <div className="size-5 shrink-0">{addon.icon}</div>
13350
+ )}
12941
13351
  <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
12942
- <strong>{detail.label}:</strong> {detail.value}
13352
+ {addon.text}
12943
13353
  </span>
12944
13354
  </div>
12945
- ))}
13355
+ )}
13356
+
13357
+ {/* Usage Details */}
13358
+ {usageDetails && usageDetails.length > 0 && (
13359
+ <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
13360
+ {usageDetails.map((detail, index) => (
13361
+ <div key={index} className="flex items-start gap-2">
13362
+ <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
13363
+ <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
13364
+ <strong>{detail.label}:</strong> {detail.value}
13365
+ </span>
13366
+ </div>
13367
+ ))}
13368
+ </div>
13369
+ )}
12946
13370
  </div>
12947
13371
  )}
12948
13372
  </div>
@@ -12963,8 +13387,8 @@ interface PlanIconProps extends React.SVGAttributes<SVGElement> {
12963
13387
  className?: string;
12964
13388
  }
12965
13389
 
12966
- const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
12967
- ({ className, ...props }, ref) => (
13390
+ const CompactCarIcon = React.forwardRef(
13391
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
12968
13392
  <svg
12969
13393
  ref={ref}
12970
13394
  className={className}
@@ -13003,8 +13427,8 @@ const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13003
13427
  );
13004
13428
  CompactCarIcon.displayName = "CompactCarIcon";
13005
13429
 
13006
- const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13007
- ({ className, ...props }, ref) => (
13430
+ const SedanCarIcon = React.forwardRef(
13431
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13008
13432
  <svg
13009
13433
  ref={ref}
13010
13434
  className={className}
@@ -13055,8 +13479,8 @@ const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13055
13479
  );
13056
13480
  SedanCarIcon.displayName = "SedanCarIcon";
13057
13481
 
13058
- const SuvCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
13059
- ({ className, ...props }, ref) => (
13482
+ const SuvCarIcon = React.forwardRef(
13483
+ ({ className, ...props }: PlanIconProps, ref: React.Ref<SVGSVGElement>) => (
13060
13484
  <svg
13061
13485
  ref={ref}
13062
13486
  className={className}
@@ -13269,7 +13693,7 @@ import type { PricingPageProps } from "./types";
13269
13693
  * />
13270
13694
  * \`\`\`
13271
13695
  */
13272
- const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13696
+ const PricingPage = React.forwardRef(
13273
13697
  (
13274
13698
  {
13275
13699
  title = "Select business plan",
@@ -13289,11 +13713,10 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13289
13713
  onFeatureComparisonClick,
13290
13714
  letUsDriveCards = [],
13291
13715
  letUsDriveTitle = "Let us drive \u2014 Full-service management",
13292
- letUsDriveExpandMode,
13293
13716
  className,
13294
13717
  ...props
13295
- },
13296
- ref
13718
+ }: PricingPageProps,
13719
+ ref: React.Ref<HTMLDivElement>
13297
13720
  ) => {
13298
13721
  // Internal state for uncontrolled mode
13299
13722
  const [internalTab, setInternalTab] = React.useState(
@@ -13302,9 +13725,6 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13302
13725
  const [internalBilling, setInternalBilling] = React.useState<
13303
13726
  "monthly" | "yearly"
13304
13727
  >("monthly");
13305
- const [expandedLetUsDriveIndices, setExpandedLetUsDriveIndices] =
13306
- React.useState<number[]>([]);
13307
-
13308
13728
  const currentTab = controlledTab ?? internalTab;
13309
13729
  const currentBilling = controlledBilling ?? internalBilling;
13310
13730
 
@@ -13313,33 +13733,9 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13313
13733
  onTabChange?.(value);
13314
13734
  };
13315
13735
 
13316
- const handleBillingChange = (period: "monthly" | "yearly") => {
13317
- if (!controlledBilling) setInternalBilling(period);
13318
- onBillingPeriodChange?.(period);
13319
- };
13320
-
13321
- const cardCount = letUsDriveCards.length;
13322
-
13323
- const handleLetUsDriveExpandedChange = (index: number, expanded: boolean) => {
13324
- if (letUsDriveExpandMode === "all") {
13325
- if (expanded) {
13326
- setExpandedLetUsDriveIndices(
13327
- Array.from({ length: cardCount }, (_, i) => i)
13328
- );
13329
- } else {
13330
- setExpandedLetUsDriveIndices((prev) =>
13331
- prev.filter((i) => i !== index)
13332
- );
13333
- }
13334
- } else {
13335
- if (expanded) {
13336
- setExpandedLetUsDriveIndices([index]);
13337
- } else {
13338
- setExpandedLetUsDriveIndices((prev) =>
13339
- prev.filter((i) => i !== index)
13340
- );
13341
- }
13342
- }
13736
+ const handleBillingChange = (period: "monthly" | "yearly") => {
13737
+ if (!controlledBilling) setInternalBilling(period);
13738
+ onBillingPeriodChange?.(period);
13343
13739
  };
13344
13740
 
13345
13741
  const hasPowerUps = powerUpCards.length > 0;
@@ -13437,22 +13833,11 @@ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
13437
13833
  {letUsDriveTitle}
13438
13834
  </h2>
13439
13835
 
13440
- {/* Service cards \u2014 items-stretch + card h-full + mt-auto on actions align Talk to us buttons */}
13441
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-stretch">
13442
- {letUsDriveCards.map((cardProps, index) => {
13443
- const hasDetailsContent =
13444
- cardProps.detailsContent &&
13445
- cardProps.detailsContent.items.length > 0;
13446
- const useControlledExpand =
13447
- letUsDriveExpandMode && hasDetailsContent;
13448
- const merged = { ...cardProps };
13449
- if (useControlledExpand) {
13450
- merged.expanded = expandedLetUsDriveIndices.includes(index);
13451
- merged.onExpandedChange = (expanded: boolean) =>
13452
- handleLetUsDriveExpandedChange(index, expanded);
13453
- }
13454
- return <LetUsDriveCard key={index} {...merged} />;
13455
- })}
13836
+ {/* Service cards \u2014 items-start so expanding one card doesn't stretch others */}
13837
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-start">
13838
+ {letUsDriveCards.map((cardProps, index) => (
13839
+ <LetUsDriveCard key={index} {...cardProps} />
13840
+ ))}
13456
13841
  </div>
13457
13842
  </div>
13458
13843
  </div>
@@ -13541,13 +13926,6 @@ export interface PricingPageProps
13541
13926
  letUsDriveCards?: LetUsDriveCardProps[];
13542
13927
  /** Let-us-drive section heading (default: "Let us drive \u2014 Full-service management") */
13543
13928
  letUsDriveTitle?: string;
13544
- /**
13545
- * When set, controls how "Show details" expands across cards.
13546
- * - "single": only the clicked card expands (accordion).
13547
- * - "all": clicking "Show details" on any card expands all cards that have detailsContent.
13548
- * Ignored when cards are used without detailsContent or without controlled expanded state.
13549
- */
13550
- letUsDriveExpandMode?: "single" | "all";
13551
13929
  }
13552
13930
  `, prefix)
13553
13931
  },
@@ -13604,7 +13982,7 @@ import type { PricingToggleProps } from "./types";
13604
13982
  * />
13605
13983
  * \`\`\`
13606
13984
  */
13607
- const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13985
+ const PricingToggle = React.forwardRef(
13608
13986
  (
13609
13987
  {
13610
13988
  tabs,
@@ -13617,8 +13995,8 @@ const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
13617
13995
  yearlyLabel = "Yearly (Save 20%)",
13618
13996
  className,
13619
13997
  ...props
13620
- },
13621
- ref
13998
+ }: PricingToggleProps,
13999
+ ref: React.Ref<HTMLDivElement>
13622
14000
  ) => {
13623
14001
  const isYearly = billingPeriod === "yearly";
13624
14002
 
@@ -13863,8 +14241,8 @@ interface BrandIconProps extends React.SVGAttributes<SVGElement> {
13863
14241
  * Used in TalkToUsModal and available for any component that needs
13864
14242
  * the MyOperator contact/chat branding.
13865
14243
  */
13866
- const MyOperatorChatIcon = React.forwardRef<SVGSVGElement, BrandIconProps>(
13867
- ({ className, ...props }, ref) => (
14244
+ const MyOperatorChatIcon = React.forwardRef(
14245
+ ({ className, ...props }: BrandIconProps, ref: React.Ref<SVGSVGElement>) => (
13868
14246
  <svg
13869
14247
  ref={ref}
13870
14248
  className={className}
@@ -13997,8 +14375,8 @@ function getTypeLabel(
13997
14375
  * All displayed data (icon, badge, name, count, last published) comes from the \`bot\` prop.
13998
14376
  * Set bot.type to "chatbot" or "voicebot"; no separate card components needed.
13999
14377
  */
14000
- export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14001
- ({ bot, typeLabels, onEdit, onDelete, className, ...props }, ref) => {
14378
+ export const BotCard = React.forwardRef(
14379
+ ({ bot, typeLabels, onEdit, onDelete, className, ...props }: BotCardProps, ref: React.Ref<HTMLDivElement>) => {
14002
14380
  const typeLabel = getTypeLabel(bot, typeLabels);
14003
14381
  const isChatbot = bot.type === "chatbot";
14004
14382
 
@@ -14085,7 +14463,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14085
14463
  </div>
14086
14464
 
14087
14465
  {/* Bot name */}
14088
- <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary truncate mb-1 min-w-0">
14466
+ <h3 className="m-0 text-sm sm:text-base font-normal text-semantic-text-primary line-clamp-1 mb-1 min-w-0">
14089
14467
  {bot.name}
14090
14468
  </h3>
14091
14469
 
@@ -14113,7 +14491,7 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
14113
14491
  </span>
14114
14492
  )}
14115
14493
  {(bot.lastPublishedBy || bot.lastPublishedDate) ? (
14116
- <p className="m-0 text-xs sm:text-sm text-semantic-text-muted truncate">
14494
+ <p className="m-0 text-xs sm:text-sm text-semantic-text-muted line-clamp-1">
14117
14495
  {bot.lastPublishedBy
14118
14496
  ? \`\${bot.lastPublishedBy} | \${bot.lastPublishedDate ?? "\u2014"}\`
14119
14497
  : bot.lastPublishedDate}
@@ -14163,10 +14541,7 @@ const BOT_TYPE_OPTIONS: BotTypeOption[] = [
14163
14541
  },
14164
14542
  ];
14165
14543
 
14166
- export const CreateBotModal = React.forwardRef<
14167
- HTMLDivElement,
14168
- CreateBotModalProps
14169
- >(({ open, onOpenChange, onSubmit, isLoading, className }, ref) => {
14544
+ export const CreateBotModal = React.forwardRef(({ open, onOpenChange, onSubmit, isLoading, className }: CreateBotModalProps, ref: React.Ref<HTMLDivElement>) => {
14170
14545
  const [name, setName] = React.useState("");
14171
14546
  const [selectedType, setSelectedType] = React.useState<BotType>("chatbot");
14172
14547
 
@@ -14314,15 +14689,15 @@ import type { CreateBotFlowProps } from "./types";
14314
14689
  * Create bot flow: "Create new bot" card + Create Bot modal. No header (title/subtitle/search).
14315
14690
  * Use when you want the create-bot experience without the list header.
14316
14691
  */
14317
- export const CreateBotFlow = React.forwardRef<HTMLDivElement, CreateBotFlowProps>(
14692
+ export const CreateBotFlow = React.forwardRef(
14318
14693
  (
14319
14694
  {
14320
14695
  createCardLabel = "Create new bot",
14321
14696
  onSubmit,
14322
14697
  className,
14323
14698
  ...props
14324
- },
14325
- ref
14699
+ }: CreateBotFlowProps,
14700
+ ref: React.Ref<HTMLDivElement>
14326
14701
  ) => {
14327
14702
  const [modalOpen, setModalOpen] = React.useState(false);
14328
14703
 
@@ -14438,7 +14813,7 @@ import { BotListGrid } from "./bot-list-grid";
14438
14813
  import { CreateBotModal } from "./create-bot-modal";
14439
14814
  import type { BotListProps } from "./types";
14440
14815
 
14441
- export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14816
+ export const BotList = React.forwardRef(
14442
14817
  (
14443
14818
  {
14444
14819
  bots = [],
@@ -14454,8 +14829,8 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
14454
14829
  createCardLabel = "Create new bot",
14455
14830
  className,
14456
14831
  ...props
14457
- },
14458
- ref
14832
+ }: BotListProps,
14833
+ ref: React.Ref<HTMLDivElement>
14459
14834
  ) => {
14460
14835
  const [searchQuery, setSearchQuery] = React.useState("");
14461
14836
  const [createModalOpen, setCreateModalOpen] = React.useState(false);
@@ -14565,10 +14940,10 @@ const botListHeaderVariants = cva("min-w-0", {
14565
14940
  },
14566
14941
  });
14567
14942
 
14568
- export const BotListHeader = React.forwardRef<HTMLDivElement, BotListHeaderProps>(
14943
+ export const BotListHeader = React.forwardRef(
14569
14944
  (
14570
- { title, subtitle, variant = "default", rightContent, className, ...props },
14571
- ref
14945
+ { title, subtitle, variant = "default", rightContent, className, ...props }: BotListHeaderProps,
14946
+ ref: React.Ref<HTMLDivElement>
14572
14947
  ) => {
14573
14948
  const rootClassName = cn(botListHeaderVariants({ variant }), className);
14574
14949
  const titleBlock = (
@@ -14615,7 +14990,7 @@ import { Search } from "lucide-react";
14615
14990
  import { cn } from "../../../lib/utils";
14616
14991
  import type { BotListSearchProps } from "./types";
14617
14992
 
14618
- export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps>(
14993
+ export const BotListSearch = React.forwardRef(
14619
14994
  (
14620
14995
  {
14621
14996
  value,
@@ -14624,8 +14999,8 @@ export const BotListSearch = React.forwardRef<HTMLDivElement, BotListSearchProps
14624
14999
  defaultValue,
14625
15000
  className,
14626
15001
  ...props
14627
- },
14628
- ref
15002
+ }: BotListSearchProps,
15003
+ ref: React.Ref<HTMLDivElement>
14629
15004
  ) => {
14630
15005
  const [internalValue, setInternalValue] = React.useState(defaultValue ?? "");
14631
15006
  const isControlled = value !== undefined;
@@ -14672,18 +15047,15 @@ import { Plus } from "lucide-react";
14672
15047
  import { cn } from "../../../lib/utils";
14673
15048
  import type { BotListCreateCardProps } from "./types";
14674
15049
 
14675
- export const BotListCreateCard = React.forwardRef<
14676
- HTMLButtonElement,
14677
- BotListCreateCardProps
14678
- >(
15050
+ export const BotListCreateCard = React.forwardRef(
14679
15051
  (
14680
15052
  {
14681
15053
  label = "Create new bot",
14682
15054
  onClick,
14683
15055
  className,
14684
15056
  ...props
14685
- },
14686
- ref
15057
+ }: BotListCreateCardProps,
15058
+ ref: React.Ref<HTMLButtonElement>
14687
15059
  ) => (
14688
15060
  <button
14689
15061
  ref={ref}
@@ -14732,8 +15104,8 @@ BotListCreateCard.displayName = "BotListCreateCard";
14732
15104
  import { cn } from "../../../lib/utils";
14733
15105
  import type { BotListGridProps } from "./types";
14734
15106
 
14735
- export const BotListGrid = React.forwardRef<HTMLDivElement, BotListGridProps>(
14736
- ({ children, className, ...props }, ref) => (
15107
+ export const BotListGrid = React.forwardRef(
15108
+ ({ children, className, ...props }: BotListGridProps, ref: React.Ref<HTMLDivElement>) => (
14737
15109
  <div
14738
15110
  ref={ref}
14739
15111
  className={cn(
@@ -15034,7 +15406,7 @@ function getTimeRemaining(progress: number) {
15034
15406
  : \`\${secs} seconds remaining\`;
15035
15407
  }
15036
15408
 
15037
- const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15409
+ const FileUploadModal = React.forwardRef(
15038
15410
  (
15039
15411
  {
15040
15412
  open,
@@ -15057,8 +15429,8 @@ const FileUploadModal = React.forwardRef<HTMLDivElement, FileUploadModalProps>(
15057
15429
  loading = false,
15058
15430
  className,
15059
15431
  ...props
15060
- },
15061
- ref
15432
+ }: FileUploadModalProps,
15433
+ ref: React.Ref<HTMLDivElement>
15062
15434
  ) => {
15063
15435
  const [items, setItems] = React.useState<UploadItem[]>([]);
15064
15436
  const fileInputRef = React.useRef<HTMLInputElement>(null);
@@ -15428,8 +15800,8 @@ import { X, Play, File } from "lucide-react";
15428
15800
  import { cn } from "../../../lib/utils";
15429
15801
  import type { AttachmentPreviewProps } from "./types";
15430
15802
 
15431
- const AttachmentPreview = React.forwardRef<HTMLDivElement, AttachmentPreviewProps>(
15432
- ({ className, file, onRemove, ...props }, ref) => {
15803
+ const AttachmentPreview = React.forwardRef(
15804
+ ({ className, file, onRemove, ...props }: AttachmentPreviewProps, ref: React.Ref<HTMLDivElement>) => {
15433
15805
  const url = React.useMemo(() => URL.createObjectURL(file), [file]);
15434
15806
 
15435
15807
  const isImage = file.type.startsWith("image/");
@@ -15587,7 +15959,7 @@ const BAR_WIDTH = 2;
15587
15959
  const BAR_GAP = 1.5;
15588
15960
  const SVG_HEIGHT = 32;
15589
15961
 
15590
- const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15962
+ const AudioMedia = React.forwardRef(
15591
15963
  (
15592
15964
  {
15593
15965
  className,
@@ -15601,8 +15973,8 @@ const AudioMedia = React.forwardRef<HTMLDivElement, AudioMediaProps>(
15601
15973
  onPlayChange,
15602
15974
  onSpeedChange,
15603
15975
  ...props
15604
- },
15605
- ref
15976
+ }: AudioMediaProps,
15977
+ ref: React.Ref<HTMLDivElement>
15606
15978
  ) => {
15607
15979
  const [playing, setPlaying] = React.useState(false);
15608
15980
  const [speed, setSpeed] = React.useState(1);
@@ -15802,8 +16174,8 @@ import { Reply, ExternalLink, ChevronLeft, ChevronRight } from "lucide-react";
15802
16174
  import { cn } from "../../../lib/utils";
15803
16175
  import type { CarouselMediaProps } from "./types";
15804
16176
 
15805
- const CarouselMedia = React.forwardRef<HTMLDivElement, CarouselMediaProps>(
15806
- ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }, ref) => {
16177
+ const CarouselMedia = React.forwardRef(
16178
+ ({ className, cards, cardWidth = 260, imageHeight = 200, ...props }: CarouselMediaProps, ref: React.Ref<HTMLDivElement>) => {
15807
16179
  const scrollRef = useRef<HTMLDivElement>(null);
15808
16180
  const [canScrollLeft, setCanScrollLeft] = useState(false);
15809
16181
  const [canScrollRight, setCanScrollRight] = useState(
@@ -16057,7 +16429,7 @@ function DeliveryFooter({
16057
16429
  * </ChatBubble>
16058
16430
  * \`\`\`
16059
16431
  */
16060
- const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16432
+ const ChatBubble = React.forwardRef(
16061
16433
  (
16062
16434
  {
16063
16435
  variant,
@@ -16072,8 +16444,8 @@ const ChatBubble = React.forwardRef<HTMLDivElement, ChatBubbleProps>(
16072
16444
  children,
16073
16445
  className,
16074
16446
  ...props
16075
- },
16076
- ref
16447
+ }: ChatBubbleProps,
16448
+ ref: React.Ref<HTMLDivElement>
16077
16449
  ) => {
16078
16450
  const hasMedia = !!media;
16079
16451
 
@@ -16246,7 +16618,7 @@ import type { ChatComposerProps } from "./types";
16246
16618
  * />
16247
16619
  * \`\`\`
16248
16620
  */
16249
- const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16621
+ const ChatComposer = React.forwardRef(
16250
16622
  (
16251
16623
  {
16252
16624
  className,
@@ -16270,8 +16642,8 @@ const ChatComposer = React.forwardRef<HTMLDivElement, ChatComposerProps>(
16270
16642
  expiredMessage = "This chat has expired. Send a template to continue.",
16271
16643
  onTemplateClick,
16272
16644
  ...props
16273
- },
16274
- ref
16645
+ }: ChatComposerProps,
16646
+ ref: React.Ref<HTMLDivElement>
16275
16647
  ) => {
16276
16648
  const textareaRef = React.useRef<HTMLTextAreaElement>(null);
16277
16649
 
@@ -16488,7 +16860,7 @@ import { cn } from "../../../lib/utils";
16488
16860
  import { File, FileSpreadsheet, ArrowDownToLine } from "lucide-react";
16489
16861
  import type { DocMediaProps } from "./types";
16490
16862
 
16491
- const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16863
+ const DocMedia = React.forwardRef(
16492
16864
  (
16493
16865
  {
16494
16866
  className,
@@ -16501,8 +16873,8 @@ const DocMedia = React.forwardRef<HTMLDivElement, DocMediaProps>(
16501
16873
  caption,
16502
16874
  onDownload,
16503
16875
  ...props
16504
- },
16505
- ref
16876
+ }: DocMediaProps,
16877
+ ref: React.Ref<HTMLDivElement>
16506
16878
  ) => {
16507
16879
  if (variant === "preview") {
16508
16880
  return (
@@ -16689,7 +17061,7 @@ import type { VideoMediaProps } from "./types";
16689
17061
 
16690
17062
  const DEFAULT_SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
16691
17063
 
16692
- const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
17064
+ const VideoMedia = React.forwardRef(
16693
17065
  (
16694
17066
  {
16695
17067
  className,
@@ -16701,8 +17073,8 @@ const VideoMedia = React.forwardRef<HTMLDivElement, VideoMediaProps>(
16701
17073
  onSpeedChange,
16702
17074
  onClick,
16703
17075
  ...props
16704
- },
16705
- ref
17076
+ }: VideoMediaProps,
17077
+ ref: React.Ref<HTMLDivElement>
16706
17078
  ) => {
16707
17079
  const [playing, setPlaying] = useState(false);
16708
17080
  const [muted, setMuted] = useState(false);
@@ -16935,7 +17307,10 @@ export type { VideoMediaProps } from "./types";
16935
17307
  "creatable-multi-select",
16936
17308
  "page-header",
16937
17309
  "tag",
16938
- "file-upload-modal"
17310
+ "file-upload-modal",
17311
+ "form-modal",
17312
+ "text-field",
17313
+ "textarea"
16939
17314
  ],
16940
17315
  isMultiFile: true,
16941
17316
  directory: "ivr-bot",
@@ -16987,7 +17362,7 @@ const DEFAULT_DATA: IvrBotConfigData = {
16987
17362
  };
16988
17363
 
16989
17364
  // \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>(
17365
+ export const IvrBotConfig = React.forwardRef(
16991
17366
  (
16992
17367
  {
16993
17368
  botTitle = "IVR bot",
@@ -17034,8 +17409,8 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
17034
17409
  callEndThresholdMin,
17035
17410
  callEndThresholdMax,
17036
17411
  className,
17037
- },
17038
- ref
17412
+ }: IvrBotConfigProps,
17413
+ ref: React.Ref<HTMLDivElement>
17039
17414
  ) => {
17040
17415
  const [data, setData] = React.useState<IvrBotConfigData>({
17041
17416
  ...DEFAULT_DATA,
@@ -17238,7 +17613,7 @@ IvrBotConfig.displayName = "IvrBotConfig";
17238
17613
  {
17239
17614
  name: "create-function-modal.tsx",
17240
17615
  content: prefixTailwindClasses(`import * as React from "react";
17241
- import { Trash2, ChevronDown, X, Plus } from "lucide-react";
17616
+ import { Trash2, ChevronDown, X, Plus, Pencil } from "lucide-react";
17242
17617
  import { cn } from "../../../lib/utils";
17243
17618
  import {
17244
17619
  Dialog,
@@ -17246,6 +17621,9 @@ import {
17246
17621
  DialogTitle,
17247
17622
  } from "../dialog";
17248
17623
  import { Button } from "../button";
17624
+ import { FormModal } from "../form-modal";
17625
+ import { TextField } from "../text-field";
17626
+ import { Textarea } from "../textarea";
17249
17627
  import type {
17250
17628
  CreateFunctionModalProps,
17251
17629
  CreateFunctionData,
@@ -17253,10 +17631,12 @@ import type {
17253
17631
  FunctionTabType,
17254
17632
  HttpMethod,
17255
17633
  KeyValuePair,
17634
+ VariableGroup,
17635
+ VariableItem,
17636
+ VariableFormData,
17256
17637
  } from "./types";
17257
17638
 
17258
17639
  const HTTP_METHODS: HttpMethod[] = ["GET", "POST", "PUT", "DELETE", "PATCH"];
17259
- const METHODS_WITH_BODY: HttpMethod[] = ["POST", "PUT", "PATCH"];
17260
17640
  const FUNCTION_NAME_MAX = 100;
17261
17641
  const BODY_MAX = 4000;
17262
17642
  const URL_MAX = 500;
@@ -17264,6 +17644,8 @@ const HEADER_KEY_MAX = 512;
17264
17644
  const HEADER_VALUE_MAX = 2048;
17265
17645
 
17266
17646
  const FUNCTION_NAME_REGEX = /^(?!_+$)(?=.*[a-zA-Z])[a-zA-Z][a-zA-Z0-9_]*$/;
17647
+ const VARIABLE_NAME_MAX = 30;
17648
+ const VARIABLE_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;
17267
17649
  const URL_REGEX = /^https?:\\/\\//;
17268
17650
  const HEADER_KEY_REGEX = /^[!#$%&'*+\\-.^_\`|~0-9a-zA-Z]+$/;
17269
17651
  // Query parameter validation (aligned with apiIntegrationSchema.queryParams)
@@ -17319,6 +17701,30 @@ function extractVarRefs(texts: string[]): string[] {
17319
17701
  return Array.from(new Set(all));
17320
17702
  }
17321
17703
 
17704
+ // \u2500\u2500 Value segment parser \u2014 splits "text {{var}} text" into typed segments \u2500\u2500\u2500\u2500\u2500
17705
+
17706
+ type ValueSegment =
17707
+ | { type: "text"; content: string }
17708
+ | { type: "var"; name: string; raw: string };
17709
+
17710
+ function parseValueSegments(value: string): ValueSegment[] {
17711
+ const segments: ValueSegment[] = [];
17712
+ const regex = /\\{\\{([^}]+)\\}\\}/g;
17713
+ let lastIndex = 0;
17714
+ let match;
17715
+ while ((match = regex.exec(value)) !== null) {
17716
+ if (match.index > lastIndex) {
17717
+ segments.push({ type: "text", content: value.slice(lastIndex, match.index) });
17718
+ }
17719
+ segments.push({ type: "var", name: match[1], raw: match[0] });
17720
+ lastIndex = regex.lastIndex;
17721
+ }
17722
+ if (lastIndex < value.length) {
17723
+ segments.push({ type: "text", content: value.slice(lastIndex) });
17724
+ }
17725
+ return segments;
17726
+ }
17727
+
17322
17728
  /** Mirror-div technique \u2014 returns { top, left } relative to the element's top-left corner. */
17323
17729
  function getCaretPixelPos(
17324
17730
  el: HTMLTextAreaElement | HTMLInputElement,
@@ -17368,70 +17774,320 @@ function getCaretPixelPos(
17368
17774
 
17369
17775
  // Uses same visual classes as DropdownMenuContent + DropdownMenuItem.
17370
17776
  // Position is cursor-anchored via getCaretPixelPos.
17777
+ // No search bar \u2014 typing after {{ already filters via filterQuery.
17371
17778
  function VarPopup({
17372
17779
  variables,
17780
+ variableGroups,
17781
+ filterQuery = "",
17373
17782
  onSelect,
17783
+ onAddVariable,
17784
+ onEditVariable,
17374
17785
  style,
17375
17786
  }: {
17376
17787
  variables: string[];
17788
+ variableGroups?: VariableGroup[];
17789
+ filterQuery?: string;
17377
17790
  onSelect: (v: string) => void;
17791
+ onAddVariable?: () => void;
17792
+ onEditVariable?: (variable: string) => void;
17378
17793
  style?: React.CSSProperties;
17379
17794
  }) {
17380
- if (variables.length === 0) return null;
17795
+ const hasGroups = variableGroups && variableGroups.length > 0;
17796
+
17797
+ if (!hasGroups && variables.length === 0) return null;
17798
+
17799
+ // Flat mode \u2014 variables are already pre-filtered by VariableInput
17800
+ if (!hasGroups) {
17801
+ return (
17802
+ <div
17803
+ role="listbox"
17804
+ style={style}
17805
+ 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"
17806
+ >
17807
+ {/* Add new variable */}
17808
+ {onAddVariable && (
17809
+ <button
17810
+ type="button"
17811
+ onMouseDown={(e) => { e.preventDefault(); onAddVariable(); }}
17812
+ 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"
17813
+ >
17814
+ <Plus className="size-3.5 shrink-0" />
17815
+ Add new variable
17816
+ </button>
17817
+ )}
17818
+
17819
+ {/* Variable list */}
17820
+ <div className="max-h-48 overflow-y-auto p-1">
17821
+ {variables.map((v) => (
17822
+ <button
17823
+ key={v}
17824
+ type="button"
17825
+ role="option"
17826
+ onMouseDown={(e) => { e.preventDefault(); onSelect(v); }}
17827
+ 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"
17828
+ >
17829
+ {v}
17830
+ </button>
17831
+ ))}
17832
+ {variables.length === 0 && (
17833
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
17834
+ )}
17835
+ </div>
17836
+ </div>
17837
+ );
17838
+ }
17839
+
17840
+ // Grouped mode \u2014 filter by the {{ trigger query
17841
+ const lowerQuery = filterQuery.toLowerCase();
17842
+ const filteredGroups = variableGroups.map((g) => ({
17843
+ ...g,
17844
+ items: g.items.filter((item) =>
17845
+ item.name.toLowerCase().includes(lowerQuery)
17846
+ ),
17847
+ })).filter((g) => g.items.length > 0);
17848
+
17381
17849
  return (
17382
17850
  <div
17383
17851
  role="listbox"
17384
17852
  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"
17853
+ 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
17854
  >
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
- ))}
17855
+ {/* Add new variable */}
17856
+ {onAddVariable && (
17857
+ <>
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
+ <div className="border-t border-semantic-border-layout" />
17867
+ </>
17868
+ )}
17869
+
17870
+ {/* Grouped variable list */}
17871
+ <div className="max-h-48 overflow-y-auto p-1">
17872
+ {filteredGroups.map((group) => (
17873
+ <div key={group.label}>
17874
+ <p className="m-0 px-2 pt-2 pb-1 text-sm font-medium text-semantic-text-muted">
17875
+ {group.label}
17876
+ </p>
17877
+ {group.items.map((item) => {
17878
+ const insertValue = item.value ?? \`{{\${item.name}}}\`;
17879
+ return (
17880
+ <div key={item.name} className="flex items-center rounded-sm transition-colors hover:bg-semantic-bg-ui">
17881
+ <button
17882
+ type="button"
17883
+ role="option"
17884
+ onMouseDown={(e) => { e.preventDefault(); onSelect(insertValue); }}
17885
+ className="relative flex flex-1 min-w-0 cursor-pointer select-none items-center px-2 py-1.5 text-sm outline-none"
17886
+ >
17887
+ {\`{{\${item.name}}}\`}
17888
+ </button>
17889
+ {item.editable && onEditVariable && (
17890
+ <button
17891
+ type="button"
17892
+ onMouseDown={(e) => { e.preventDefault(); onEditVariable(item.name); }}
17893
+ className="shrink-0 p-1.5 rounded text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
17894
+ aria-label={\`Edit \${item.name}\`}
17895
+ >
17896
+ <Pencil className="size-3.5" />
17897
+ </button>
17898
+ )}
17899
+ </div>
17900
+ );
17901
+ })}
17902
+ </div>
17903
+ ))}
17904
+ {filteredGroups.length === 0 && (
17905
+ <p className="m-0 px-2 py-1.5 text-sm text-semantic-text-muted">No variables found</p>
17906
+ )}
17907
+ </div>
17401
17908
  </div>
17402
17909
  );
17403
17910
  }
17404
17911
 
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
17912
+ // \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
17913
+
17914
+ function VariableFormModal({
17915
+ open,
17916
+ onOpenChange,
17917
+ mode,
17918
+ initialData,
17919
+ onSave,
17920
+ }: {
17921
+ open: boolean;
17922
+ onOpenChange: (open: boolean) => void;
17923
+ mode: "create" | "edit";
17924
+ initialData?: VariableItem;
17925
+ onSave: (data: VariableFormData) => void;
17926
+ }) {
17927
+ const [name, setName] = React.useState("");
17928
+ const [description, setDescription] = React.useState("");
17929
+ const [required, setRequired] = React.useState(false);
17930
+ const [nameError, setNameError] = React.useState("");
17931
+
17932
+ // Reset form when modal opens
17933
+ React.useEffect(() => {
17934
+ if (open) {
17935
+ setName(initialData?.name ?? "");
17936
+ setDescription(initialData?.description ?? "");
17937
+ setRequired(initialData?.required ?? false);
17938
+ setNameError("");
17939
+ }
17940
+ }, [open, initialData]);
17941
+
17942
+ const validateName = (v: string) => {
17943
+ if (!v.trim()) return "";
17944
+ if (!VARIABLE_NAME_REGEX.test(v)) {
17945
+ return "Variable name should start with alphabet; Cannot have special characters except underscore (_)";
17946
+ }
17947
+ return "";
17948
+ };
17949
+
17950
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
17951
+ const v = e.target.value;
17952
+ setName(v);
17953
+ setNameError(validateName(v));
17954
+ };
17955
+
17956
+ const handleSave = () => {
17957
+ const error = validateName(name);
17958
+ if (error || !name.trim()) {
17959
+ setNameError(error || "Variable name is required");
17960
+ return;
17961
+ }
17962
+ onSave({ name: name.trim(), description: description.trim() || undefined, required });
17963
+ };
17964
+
17965
+ return (
17966
+ <FormModal
17967
+ open={open}
17968
+ onOpenChange={onOpenChange}
17969
+ title={mode === "create" ? "Create new variable" : "Edit variable"}
17970
+ saveButtonText={mode === "create" ? "Save" : "Save Changes"}
17971
+ disableSave={!name.trim() || !!nameError}
17972
+ onSave={handleSave}
17973
+ size="default"
17974
+ >
17975
+ <div className="flex flex-col gap-4">
17976
+ <div className="flex flex-col gap-1.5">
17977
+ <label className="text-sm font-medium text-semantic-text-muted">
17978
+ Variable name{" "}
17979
+ <span className="text-semantic-error-primary">*</span>
17980
+ </label>
17981
+ <div className="relative">
17982
+ <input
17983
+ type="text"
17984
+ value={name}
17985
+ onChange={handleNameChange}
17986
+ placeholder="e.g., customer_name"
17987
+ maxLength={VARIABLE_NAME_MAX}
17988
+ className={cn(inputCls, "pr-16")}
17989
+ />
17990
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
17991
+ {name.length}/{VARIABLE_NAME_MAX}
17992
+ </span>
17993
+ </div>
17994
+ <span className={cn("text-sm", nameError ? "text-semantic-error-primary" : "text-semantic-text-muted")}>
17995
+ {nameError || "Variable name should start with alphabet; Cannot have special characters except underscore (_)"}
17996
+ </span>
17997
+ </div>
17998
+ <TextField
17999
+ label="Description (optional)"
18000
+ placeholder="What this variable represents"
18001
+ value={description}
18002
+ onChange={(e) => setDescription(e.target.value)}
18003
+ />
18004
+ <div className="flex flex-col gap-1.5">
18005
+ <span className="text-sm font-medium text-semantic-text-muted">Required</span>
18006
+ <div className="flex items-center gap-6">
18007
+ <label className="flex items-center gap-2 cursor-pointer">
18008
+ <input
18009
+ type="radio"
18010
+ name="variable-required"
18011
+ checked={required}
18012
+ onChange={() => setRequired(true)}
18013
+ className="size-4 accent-semantic-primary"
18014
+ />
18015
+ <span className="text-base text-semantic-text-primary">Yes</span>
18016
+ </label>
18017
+ <label className="flex items-center gap-2 cursor-pointer">
18018
+ <input
18019
+ type="radio"
18020
+ name="variable-required"
18021
+ checked={!required}
18022
+ onChange={() => setRequired(false)}
18023
+ className="size-4 accent-semantic-primary"
18024
+ />
18025
+ <span className="text-base text-semantic-text-primary">No</span>
18026
+ </label>
18027
+ </div>
18028
+ </div>
18029
+ </div>
18030
+ </FormModal>
18031
+ );
18032
+ }
18033
+
18034
+ // \u2500\u2500 VariableInput \u2014 input with {{ autocomplete + badge display \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17406
18035
 
17407
18036
  function VariableInput({
17408
18037
  value,
17409
18038
  onChange,
17410
18039
  sessionVariables,
18040
+ variableGroups,
18041
+ onAddVariable,
18042
+ onEditVariable,
17411
18043
  placeholder,
17412
18044
  maxLength,
17413
18045
  className,
17414
18046
  inputRef: externalInputRef,
18047
+ disabled,
17415
18048
  ...inputProps
17416
18049
  }: {
17417
18050
  value: string;
17418
18051
  onChange: (v: string) => void;
17419
18052
  sessionVariables: string[];
18053
+ variableGroups?: VariableGroup[];
18054
+ onAddVariable?: () => void;
18055
+ onEditVariable?: (variable: string) => void;
17420
18056
  placeholder?: string;
17421
18057
  maxLength?: number;
17422
18058
  className?: string;
17423
18059
  inputRef?: React.RefObject<HTMLInputElement>;
18060
+ disabled?: boolean;
17424
18061
  [k: string]: unknown;
17425
18062
  }) {
17426
18063
  const internalRef = React.useRef<HTMLInputElement>(null);
17427
18064
  const inputRef = externalInputRef ?? internalRef;
18065
+ const displayRef = React.useRef<HTMLDivElement>(null);
17428
18066
  const [trigger, setTrigger] = React.useState<TriggerState | null>(null);
17429
18067
  const [popupStyle, setPopupStyle] = React.useState<React.CSSProperties | undefined>();
18068
+ const [isEditing, setIsEditing] = React.useState(false);
18069
+ const [isExpanded, setIsExpanded] = React.useState(false);
18070
+ const [isOverflowing, setIsOverflowing] = React.useState(false);
17430
18071
 
17431
18072
  const filtered = trigger
17432
18073
  ? sessionVariables.filter((v) => v.toLowerCase().includes(trigger.query))
17433
18074
  : [];
17434
18075
 
18076
+ // Parse value into text + variable segments
18077
+ const segments = React.useMemo(() => parseValueSegments(value), [value]);
18078
+ const hasVariables = segments.some((s) => s.type === "var");
18079
+ const showDisplay = !isEditing && value.length > 0 && hasVariables;
18080
+
18081
+ // Check overflow in display mode
18082
+ React.useEffect(() => {
18083
+ if (showDisplay && displayRef.current && !isExpanded) {
18084
+ const el = displayRef.current;
18085
+ setIsOverflowing(el.scrollWidth > el.clientWidth);
18086
+ } else {
18087
+ setIsOverflowing(false);
18088
+ }
18089
+ }, [showDisplay, value, isExpanded]);
18090
+
17435
18091
  const updatePopupPos = (el: HTMLInputElement, cursor: number) => {
17436
18092
  const caret = getCaretPixelPos(el, cursor);
17437
18093
  const lineHeight = parseFloat(window.getComputedStyle(el).lineHeight) || 20;
@@ -17460,13 +18116,15 @@ function VariableInput({
17460
18116
 
17461
18117
  return (
17462
18118
  <div className="relative w-full">
18119
+ {/* Input \u2014 always in DOM, hidden when display mode is active */}
17463
18120
  <input
17464
18121
  ref={inputRef}
17465
18122
  type="text"
17466
18123
  value={value}
17467
18124
  placeholder={placeholder}
17468
18125
  maxLength={maxLength}
17469
- className={className}
18126
+ disabled={disabled}
18127
+ className={cn(className, showDisplay && "opacity-0 pointer-events-none")}
17470
18128
  onChange={(e) => {
17471
18129
  onChange(e.target.value);
17472
18130
  const cursor = e.target.selectionStart ?? e.target.value.length;
@@ -17478,10 +18136,88 @@ function VariableInput({
17478
18136
  onKeyDown={(e) => {
17479
18137
  if (e.key === "Escape") clearTrigger();
17480
18138
  }}
17481
- onBlur={() => clearTrigger()}
18139
+ onFocus={() => setIsEditing(true)}
18140
+ onBlur={() => {
18141
+ clearTrigger();
18142
+ setIsEditing(false);
18143
+ setIsExpanded(false);
18144
+ }}
17482
18145
  {...inputProps}
17483
18146
  />
17484
- <VarPopup variables={filtered} onSelect={handleSelect} style={popupStyle} />
18147
+
18148
+ {/* Display mode \u2014 variable badges + text + overflow */}
18149
+ {showDisplay && (
18150
+ <div
18151
+ className={cn(
18152
+ "absolute cursor-text",
18153
+ !isExpanded && "inset-0 flex items-center",
18154
+ isExpanded && "inset-x-0 top-0 z-10",
18155
+ disabled && "opacity-50 cursor-not-allowed"
18156
+ )}
18157
+ onClick={() => {
18158
+ if (!disabled) inputRef.current?.focus();
18159
+ }}
18160
+ >
18161
+ <div
18162
+ ref={displayRef}
18163
+ className={cn(
18164
+ "flex items-center gap-1 px-2",
18165
+ !isExpanded && "flex-1 min-w-0 overflow-hidden",
18166
+ isExpanded && "flex-wrap bg-semantic-bg-primary border border-semantic-border-input rounded py-1.5 shadow-sm"
18167
+ )}
18168
+ >
18169
+ {segments.map((seg, i) =>
18170
+ seg.type === "text" ? (
18171
+ <span key={i} className="text-sm text-semantic-text-primary whitespace-pre shrink-0">{seg.content}</span>
18172
+ ) : (
18173
+ <span
18174
+ key={i}
18175
+ 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"
18176
+ >
18177
+ {seg.name}
18178
+ {onEditVariable && (
18179
+ <button
18180
+ type="button"
18181
+ onMouseDown={(e) => {
18182
+ e.preventDefault();
18183
+ e.stopPropagation();
18184
+ onEditVariable(seg.name);
18185
+ }}
18186
+ className="p-0.5 text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
18187
+ >
18188
+ <Pencil className="size-3" />
18189
+ </button>
18190
+ )}
18191
+ </span>
18192
+ )
18193
+ )}
18194
+ </div>
18195
+ {isOverflowing && !isExpanded && (
18196
+ <button
18197
+ type="button"
18198
+ onMouseDown={(e) => {
18199
+ e.preventDefault();
18200
+ e.stopPropagation();
18201
+ setIsExpanded(true);
18202
+ }}
18203
+ className="shrink-0 px-1 text-sm font-medium text-semantic-text-muted hover:text-semantic-text-primary"
18204
+ >
18205
+ ...
18206
+ </button>
18207
+ )}
18208
+ </div>
18209
+ )}
18210
+
18211
+ {/* VarPopup */}
18212
+ <VarPopup
18213
+ variables={filtered}
18214
+ variableGroups={trigger ? variableGroups : undefined}
18215
+ filterQuery={trigger?.query ?? ""}
18216
+ onSelect={handleSelect}
18217
+ onAddVariable={onAddVariable}
18218
+ onEditVariable={onEditVariable}
18219
+ style={popupStyle}
18220
+ />
17485
18221
  </div>
17486
18222
  );
17487
18223
  }
@@ -17491,7 +18227,7 @@ const inputCls = cn(
17491
18227
  "w-full h-[42px] px-4 text-base rounded border",
17492
18228
  "border-semantic-border-input bg-semantic-bg-primary",
17493
18229
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17494
- "outline-none hover:border-semantic-border-input-focus",
18230
+ "outline-none",
17495
18231
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17496
18232
  "disabled:opacity-50 disabled:cursor-not-allowed"
17497
18233
  );
@@ -17500,7 +18236,7 @@ const textareaCls = cn(
17500
18236
  "w-full px-4 py-2.5 text-base rounded border resize-none",
17501
18237
  "border-semantic-border-input bg-semantic-bg-primary",
17502
18238
  "text-semantic-text-primary placeholder:text-semantic-text-muted",
17503
- "outline-none hover:border-semantic-border-input-focus",
18239
+ "outline-none",
17504
18240
  "focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
17505
18241
  "disabled:opacity-50 disabled:cursor-not-allowed"
17506
18242
  );
@@ -17518,6 +18254,9 @@ function KeyValueTable({
17518
18254
  keyRegex,
17519
18255
  keyRegexError,
17520
18256
  sessionVariables = [],
18257
+ variableGroups,
18258
+ onAddVariable,
18259
+ onEditVariable,
17521
18260
  disabled = false,
17522
18261
  }: {
17523
18262
  rows: KeyValuePair[];
@@ -17529,6 +18268,9 @@ function KeyValueTable({
17529
18268
  keyRegex?: RegExp;
17530
18269
  keyRegexError?: string;
17531
18270
  sessionVariables?: string[];
18271
+ variableGroups?: VariableGroup[];
18272
+ onAddVariable?: () => void;
18273
+ onEditVariable?: (variable: string) => void;
17532
18274
  disabled?: boolean;
17533
18275
  }) {
17534
18276
  const update = (id: string, patch: Partial<KeyValuePair>) => {
@@ -17560,14 +18302,14 @@ function KeyValueTable({
17560
18302
 
17561
18303
  return (
17562
18304
  <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">
18305
+ <span className="text-sm text-semantic-text-muted">{label}</span>
18306
+ <div className="border border-semantic-border-layout rounded">
17565
18307
  {/* 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">
18308
+ <div className="hidden sm:flex border-b border-semantic-border-layout rounded-t">
18309
+ <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
18310
  Key
17569
18311
  </div>
17570
- <div className="flex-[2] min-w-0 px-3 py-2 text-xs font-semibold text-semantic-text-muted">
18312
+ <div className="flex-[2] min-w-0 px-3 py-2 text-sm font-semibold text-semantic-text-muted">
17571
18313
  Value
17572
18314
  </div>
17573
18315
  <div className="w-10 shrink-0" aria-hidden="true" />
@@ -17583,7 +18325,7 @@ function KeyValueTable({
17583
18325
  >
17584
18326
  {/* Key column \u2014 border-r on column (not input) so it aligns with header */}
17585
18327
  <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">
18328
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17587
18329
  Key
17588
18330
  </span>
17589
18331
  <input
@@ -17594,45 +18336,36 @@ function KeyValueTable({
17594
18336
  maxLength={keyMaxLength}
17595
18337
  disabled={disabled}
17596
18338
  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",
18339
+ "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
18340
  "disabled:opacity-50 disabled:cursor-not-allowed",
17599
- errors.key && "border-semantic-error-primary"
18341
+ errors.key && "text-semantic-error-primary"
17600
18342
  )}
17601
18343
  aria-invalid={Boolean(errors.key)}
17602
- aria-describedby={errors.key ? \`err-key-\${row.id}\` : undefined}
17603
18344
  />
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
18345
  </div>
17610
18346
 
17611
18347
  {/* Value column \u2014 uses VariableInput for {{ autocomplete */}
17612
18348
  <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">
18349
+ <span className="sm:hidden px-3 pt-2.5 pb-0.5 text-sm font-semibold text-semantic-text-muted uppercase tracking-wide">
17614
18350
  Value
17615
18351
  </span>
17616
18352
  <VariableInput
17617
18353
  value={row.value}
17618
18354
  onChange={(v) => update(row.id, { value: v })}
17619
18355
  sessionVariables={sessionVariables}
18356
+ variableGroups={variableGroups}
18357
+ onAddVariable={onAddVariable}
18358
+ onEditVariable={onEditVariable}
17620
18359
  placeholder="Type {{ to add variables"
17621
18360
  maxLength={valueMaxLength}
17622
18361
  disabled={disabled}
17623
18362
  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",
18363
+ "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
18364
  "disabled:opacity-50 disabled:cursor-not-allowed",
17626
- errors.value && "border-semantic-error-primary"
18365
+ errors.value && "text-semantic-error-primary"
17627
18366
  )}
17628
18367
  aria-invalid={Boolean(errors.value)}
17629
- aria-describedby={errors.value ? \`err-value-\${row.id}\` : undefined}
17630
18368
  />
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
18369
  </div>
17637
18370
 
17638
18371
  {/* Action column \u2014 delete aligned with row (same as KeyValueRow / knowledge-base-card) */}
@@ -17659,7 +18392,7 @@ function KeyValueTable({
17659
18392
  onClick={add}
17660
18393
  disabled={disabled}
17661
18394
  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",
18395
+ "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
18396
  disabled && "opacity-50 cursor-not-allowed"
17664
18397
  )}
17665
18398
  >
@@ -17667,15 +18400,35 @@ function KeyValueTable({
17667
18400
  <span>Add row</span>
17668
18401
  </button>
17669
18402
  </div>
18403
+
18404
+ {/* Collected row errors \u2014 shown below the table */}
18405
+ {(() => {
18406
+ const allErrors = rows
18407
+ .map((row) => {
18408
+ const errs = getErrors(row);
18409
+ const msgs: string[] = [];
18410
+ if (errs.key) msgs.push(errs.key);
18411
+ if (errs.value) msgs.push(errs.value);
18412
+ return msgs;
18413
+ })
18414
+ .flat();
18415
+ if (allErrors.length === 0) return null;
18416
+ // Deduplicate
18417
+ const unique = Array.from(new Set(allErrors));
18418
+ return (
18419
+ <div className="flex flex-col gap-0.5">
18420
+ {unique.map((msg) => (
18421
+ <p key={msg} className="m-0 text-sm text-semantic-error-primary">{msg}</p>
18422
+ ))}
18423
+ </div>
18424
+ );
18425
+ })()}
17670
18426
  </div>
17671
18427
  );
17672
18428
  }
17673
18429
 
17674
18430
  // \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
- >(
18431
+ export const CreateFunctionModal = React.forwardRef(
17679
18432
  (
17680
18433
  {
17681
18434
  open,
@@ -17689,10 +18442,13 @@ export const CreateFunctionModal = React.forwardRef<
17689
18442
  initialStep = 1,
17690
18443
  initialTab = "header",
17691
18444
  sessionVariables = DEFAULT_SESSION_VARIABLES,
18445
+ variableGroups,
18446
+ onAddVariable,
18447
+ onEditVariable,
17692
18448
  disabled = false,
17693
18449
  className,
17694
- },
17695
- ref
18450
+ }: CreateFunctionModalProps,
18451
+ ref: React.Ref<HTMLDivElement>
17696
18452
  ) => {
17697
18453
  const [step, setStep] = React.useState<1 | 2>(initialStep);
17698
18454
 
@@ -17713,6 +18469,35 @@ export const CreateFunctionModal = React.forwardRef<
17713
18469
  const [urlError, setUrlError] = React.useState("");
17714
18470
  const [bodyError, setBodyError] = React.useState("");
17715
18471
 
18472
+ // Variable modal state
18473
+ const [varModalOpen, setVarModalOpen] = React.useState(false);
18474
+ const [varModalMode, setVarModalMode] = React.useState<"create" | "edit">("create");
18475
+ const [varModalInitialData, setVarModalInitialData] = React.useState<VariableItem | undefined>();
18476
+
18477
+ const handleAddVariableClick = () => {
18478
+ setVarModalMode("create");
18479
+ setVarModalInitialData(undefined);
18480
+ setVarModalOpen(true);
18481
+ };
18482
+
18483
+ const handleEditVariableClick = (variableName: string) => {
18484
+ const variable = variableGroups
18485
+ ?.flatMap((g) => g.items)
18486
+ .find((item) => item.name === variableName);
18487
+ setVarModalMode("edit");
18488
+ setVarModalInitialData(variable ?? { name: variableName, editable: true });
18489
+ setVarModalOpen(true);
18490
+ };
18491
+
18492
+ const handleVariableSave = (data: VariableFormData) => {
18493
+ if (varModalMode === "create") {
18494
+ onAddVariable?.(data);
18495
+ } else {
18496
+ onEditVariable?.(varModalInitialData?.name ?? "", data);
18497
+ }
18498
+ setVarModalOpen(false);
18499
+ };
18500
+
17716
18501
  // Variable trigger state for URL and body
17717
18502
  const urlInputRef = React.useRef<HTMLInputElement>(null);
17718
18503
  const bodyTextareaRef = React.useRef<HTMLTextAreaElement>(null);
@@ -17807,14 +18592,7 @@ export const CreateFunctionModal = React.forwardRef<
17807
18592
  onOpenChange(false);
17808
18593
  }, [reset, onOpenChange]);
17809
18594
 
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]);
18595
+ // Body tab is always visible regardless of HTTP method
17818
18596
 
17819
18597
  const validateName = (value: string) => {
17820
18598
  if (value.trim() && !FUNCTION_NAME_REGEX.test(value.trim())) {
@@ -17949,11 +18727,10 @@ export const CreateFunctionModal = React.forwardRef<
17949
18727
  body: "Body",
17950
18728
  };
17951
18729
 
17952
- const visibleTabs: FunctionTabType[] = supportsBody
17953
- ? ["header", "queryParams", "body"]
17954
- : ["header", "queryParams"];
18730
+ const visibleTabs: FunctionTabType[] = ["header", "queryParams", "body"];
17955
18731
 
17956
18732
  return (
18733
+ <>
17957
18734
  <Dialog open={open} onOpenChange={onOpenChange}>
17958
18735
  <DialogContent
17959
18736
  ref={ref}
@@ -17961,7 +18738,7 @@ export const CreateFunctionModal = React.forwardRef<
17961
18738
  hideCloseButton
17962
18739
  className={cn(
17963
18740
  "flex flex-col gap-0 p-0 w-[calc(100vw-2rem)] sm:w-full",
17964
- "max-h-[calc(100svh-2rem)] overflow-hidden",
18741
+ "max-h-[calc(100vh-2rem)] overflow-hidden",
17965
18742
  className
17966
18743
  )}
17967
18744
  >
@@ -17981,7 +18758,7 @@ export const CreateFunctionModal = React.forwardRef<
17981
18758
  </div>
17982
18759
 
17983
18760
  {/* \u2500\u2500 Scrollable body \u2500\u2500 */}
17984
- <div className="flex-1 overflow-y-auto min-h-0 px-4 py-5 sm:px-6">
18761
+ <div className="flex-1 overflow-y-auto min-h-0 overscroll-contain px-4 py-5 sm:px-6">
17985
18762
  {/* \u2500 Step 1 \u2500 */}
17986
18763
  {step === 1 && (
17987
18764
  <div className="flex flex-col gap-5">
@@ -18008,44 +18785,33 @@ export const CreateFunctionModal = React.forwardRef<
18008
18785
  placeholder="Enter name of the function"
18009
18786
  className={cn(inputCls, "pr-16")}
18010
18787
  />
18011
- <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs italic text-semantic-text-muted pointer-events-none">
18788
+ <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-semantic-text-muted pointer-events-none">
18012
18789
  {name.length}/{FUNCTION_NAME_MAX}
18013
18790
  </span>
18014
18791
  </div>
18015
18792
  {nameError && (
18016
- <p className="m-0 text-xs text-semantic-error-primary">{nameError}</p>
18793
+ <p className="m-0 text-sm text-semantic-error-primary">{nameError}</p>
18017
18794
  )}
18018
18795
  </div>
18019
18796
 
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>
18797
+ <Textarea
18798
+ id="fn-prompt"
18799
+ label="Prompt"
18800
+ required
18801
+ value={prompt}
18802
+ maxLength={promptMaxLength}
18803
+ showCount
18804
+ disabled={disabled}
18805
+ onChange={(e) => setPrompt(e.target.value)}
18806
+ placeholder="Enter the description of the function"
18807
+ rows={5}
18808
+ labelClassName="font-semibold text-semantic-text-primary"
18809
+ error={
18810
+ prompt.length > 0 && prompt.trim().length < promptMinLength
18811
+ ? \`Minimum \${promptMinLength} characters required\`
18812
+ : undefined
18813
+ }
18814
+ />
18049
18815
  </div>
18050
18816
  )}
18051
18817
 
@@ -18054,13 +18820,12 @@ export const CreateFunctionModal = React.forwardRef<
18054
18820
  <div className="flex flex-col gap-5">
18055
18821
  {/* API URL \u2014 always a single combined row */}
18056
18822
  <div className="flex flex-col gap-1.5">
18057
- <span className="text-xs text-semantic-text-muted tracking-[0.048px]">
18823
+ <span className="text-sm text-semantic-text-muted tracking-[0.048px]">
18058
18824
  API URL
18059
18825
  </span>
18060
18826
  <div
18061
18827
  className={cn(
18062
18828
  "flex h-[42px] rounded border border-semantic-border-input overflow-visible bg-semantic-bg-primary",
18063
- "hover:border-semantic-border-input-focus",
18064
18829
  "focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
18065
18830
  "transition-shadow"
18066
18831
  )}
@@ -18121,11 +18886,19 @@ export const CreateFunctionModal = React.forwardRef<
18121
18886
  disabled && "opacity-50 cursor-not-allowed"
18122
18887
  )}
18123
18888
  />
18124
- <VarPopup variables={filteredUrlVars} onSelect={handleUrlVarSelect} style={urlPopupStyle} />
18889
+ <VarPopup
18890
+ variables={filteredUrlVars}
18891
+ variableGroups={urlTrigger ? variableGroups : undefined}
18892
+ filterQuery={urlTrigger?.query ?? ""}
18893
+ onSelect={handleUrlVarSelect}
18894
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
18895
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
18896
+ style={urlPopupStyle}
18897
+ />
18125
18898
  </div>
18126
18899
  </div>
18127
18900
  {urlError && (
18128
- <p className="m-0 text-xs text-semantic-error-primary">{urlError}</p>
18901
+ <p className="m-0 text-sm text-semantic-error-primary">{urlError}</p>
18129
18902
  )}
18130
18903
  </div>
18131
18904
 
@@ -18165,6 +18938,9 @@ export const CreateFunctionModal = React.forwardRef<
18165
18938
  keyRegex={HEADER_KEY_REGEX}
18166
18939
  keyRegexError="Invalid header key. Use only alphanumeric and !#$%&'*+-.^_\`|~ characters."
18167
18940
  sessionVariables={sessionVariables}
18941
+ variableGroups={variableGroups}
18942
+ onAddVariable={handleAddVariableClick}
18943
+ onEditVariable={handleEditVariableClick}
18168
18944
  disabled={disabled}
18169
18945
  />
18170
18946
  )}
@@ -18184,12 +18960,15 @@ export const CreateFunctionModal = React.forwardRef<
18184
18960
  };
18185
18961
  }}
18186
18962
  sessionVariables={sessionVariables}
18963
+ variableGroups={variableGroups}
18964
+ onAddVariable={handleAddVariableClick}
18965
+ onEditVariable={handleEditVariableClick}
18187
18966
  disabled={disabled}
18188
18967
  />
18189
18968
  )}
18190
18969
  {activeTab === "body" && (
18191
18970
  <div className="flex flex-col gap-1.5">
18192
- <span className="text-xs text-semantic-text-muted">
18971
+ <span className="text-sm text-semantic-text-muted">
18193
18972
  Body
18194
18973
  </span>
18195
18974
  <div className={cn("relative")}>
@@ -18219,13 +18998,21 @@ export const CreateFunctionModal = React.forwardRef<
18219
18998
  rows={6}
18220
18999
  className={cn(textareaCls, "pb-7")}
18221
19000
  />
18222
- <span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted pointer-events-none">
19001
+ <span className="absolute bottom-2 right-3 text-sm text-semantic-text-muted pointer-events-none">
18223
19002
  {body.length}/{BODY_MAX}
18224
19003
  </span>
18225
- <VarPopup variables={filteredBodyVars} onSelect={handleBodyVarSelect} style={bodyPopupStyle} />
19004
+ <VarPopup
19005
+ variables={filteredBodyVars}
19006
+ variableGroups={bodyTrigger ? variableGroups : undefined}
19007
+ filterQuery={bodyTrigger?.query ?? ""}
19008
+ onSelect={handleBodyVarSelect}
19009
+ onAddVariable={onAddVariable ? handleAddVariableClick : undefined}
19010
+ onEditVariable={onEditVariable ? handleEditVariableClick : undefined}
19011
+ style={bodyPopupStyle}
19012
+ />
18226
19013
  </div>
18227
19014
  {bodyError && (
18228
- <p className="m-0 text-xs text-semantic-error-primary">{bodyError}</p>
19015
+ <p className="m-0 text-sm text-semantic-error-primary">{bodyError}</p>
18229
19016
  )}
18230
19017
  </div>
18231
19018
  )}
@@ -18234,7 +19021,7 @@ export const CreateFunctionModal = React.forwardRef<
18234
19021
  {/* Test Your API */}
18235
19022
  <div className="flex flex-col gap-4">
18236
19023
  <div className="flex flex-col gap-1.5">
18237
- <span className="text-xs font-semibold text-semantic-text-muted tracking-[0.048px]">
19024
+ <span className="text-sm font-semibold text-semantic-text-muted tracking-[0.048px]">
18238
19025
  Test Your API
18239
19026
  </span>
18240
19027
  <div className="border-t border-semantic-border-layout" />
@@ -18243,12 +19030,12 @@ export const CreateFunctionModal = React.forwardRef<
18243
19030
  {/* Variable test values \u2014 shown when URL/body/params contain {{variables}} */}
18244
19031
  {testableVars.length > 0 && (
18245
19032
  <div className="flex flex-col gap-2">
18246
- <span className="text-xs text-semantic-text-muted">
19033
+ <span className="text-sm text-semantic-text-muted">
18247
19034
  Variable values for testing
18248
19035
  </span>
18249
19036
  {testableVars.map((variable) => (
18250
19037
  <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]">
19038
+ <span className="text-sm text-semantic-text-muted font-mono shrink-0 min-w-[120px]">
18252
19039
  {variable}
18253
19040
  </span>
18254
19041
  <input
@@ -18278,7 +19065,7 @@ export const CreateFunctionModal = React.forwardRef<
18278
19065
  </button>
18279
19066
 
18280
19067
  <div className="flex flex-col gap-1.5">
18281
- <span className="text-xs text-semantic-text-muted">
19068
+ <span className="text-sm text-semantic-text-muted">
18282
19069
  Response from API
18283
19070
  </span>
18284
19071
  <textarea
@@ -18336,6 +19123,15 @@ export const CreateFunctionModal = React.forwardRef<
18336
19123
  </div>
18337
19124
  </DialogContent>
18338
19125
  </Dialog>
19126
+
19127
+ <VariableFormModal
19128
+ open={varModalOpen}
19129
+ onOpenChange={setVarModalOpen}
19130
+ mode={varModalMode}
19131
+ initialData={varModalInitialData}
19132
+ onSave={handleVariableSave}
19133
+ />
19134
+ </>
18339
19135
  );
18340
19136
  }
18341
19137
  );
@@ -18547,7 +19343,7 @@ const DEFAULT_LANGUAGE_OPTIONS: LanguageOption[] = [
18547
19343
 
18548
19344
  // \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
19345
 
18550
- const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
19346
+ const BotIdentityCard = React.forwardRef(
18551
19347
  (
18552
19348
  {
18553
19349
  data,
@@ -18561,8 +19357,8 @@ const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
18561
19357
  playingVoice,
18562
19358
  disabled,
18563
19359
  className,
18564
- },
18565
- ref
19360
+ }: BotIdentityCardProps,
19361
+ ref: React.Ref<HTMLDivElement>
18566
19362
  ) => {
18567
19363
  return (
18568
19364
  <div
@@ -18907,7 +19703,7 @@ function SectionCard({
18907
19703
 
18908
19704
  // \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
19705
 
18910
- const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
19706
+ const BotBehaviorCard = React.forwardRef(
18911
19707
  (
18912
19708
  {
18913
19709
  data,
@@ -18917,8 +19713,8 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
18917
19713
  maxLength = 5000,
18918
19714
  disabled,
18919
19715
  className,
18920
- },
18921
- ref
19716
+ }: BotBehaviorCardProps,
19717
+ ref: React.Ref<HTMLDivElement>
18922
19718
  ) => {
18923
19719
  const prompt = data.systemPrompt ?? "";
18924
19720
  const MAX = maxLength;
@@ -19145,7 +19941,7 @@ const STATUS_CONFIG: Record<BOT_KNOWLEDGE_STATUS, { label: string; variant: Badg
19145
19941
 
19146
19942
  // \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
19943
 
19148
- const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProps>(
19944
+ const KnowledgeBaseCard = React.forwardRef(
19149
19945
  (
19150
19946
  {
19151
19947
  files,
@@ -19157,8 +19953,8 @@ const KnowledgeBaseCard = React.forwardRef<HTMLDivElement, KnowledgeBaseCardProp
19157
19953
  downloadDisabled,
19158
19954
  deleteDisabled,
19159
19955
  className,
19160
- },
19161
- ref
19956
+ }: KnowledgeBaseCardProps,
19957
+ ref: React.Ref<HTMLDivElement>
19162
19958
  ) => {
19163
19959
  return (
19164
19960
  <div
@@ -19310,8 +20106,8 @@ export interface FunctionsCardProps {
19310
20106
 
19311
20107
  // \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
20108
 
19313
- const FunctionsCard = React.forwardRef<HTMLDivElement, FunctionsCardProps>(
19314
- ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }, ref) => {
20109
+ const FunctionsCard = React.forwardRef(
20110
+ ({ functions, onAddFunction, onEditFunction, onDeleteFunction, infoTooltip, disabled, editDisabled, deleteDisabled, className }: FunctionsCardProps, ref: React.Ref<HTMLDivElement>) => {
19315
20111
  return (
19316
20112
  <div
19317
20113
  ref={ref}
@@ -19497,8 +20293,8 @@ function Field({
19497
20293
 
19498
20294
  // \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
20295
 
19500
- const FrustrationHandoverCard = React.forwardRef<HTMLDivElement, FrustrationHandoverCardProps>(
19501
- ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }, ref) => {
20296
+ const FrustrationHandoverCard = React.forwardRef(
20297
+ ({ data, onChange, departmentOptions = DEFAULT_DEPARTMENT_OPTIONS, disabled, className }: FrustrationHandoverCardProps, ref: React.Ref<HTMLDivElement>) => {
19502
20298
  return (
19503
20299
  <div
19504
20300
  ref={ref}
@@ -19671,7 +20467,7 @@ function NumberSpinner({
19671
20467
 
19672
20468
  // \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
20469
 
19674
- const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCardProps>(
20470
+ const AdvancedSettingsCard = React.forwardRef(
19675
20471
  (
19676
20472
  {
19677
20473
  data,
@@ -19682,8 +20478,8 @@ const AdvancedSettingsCard = React.forwardRef<HTMLDivElement, AdvancedSettingsCa
19682
20478
  callEndThresholdMax = 10,
19683
20479
  disabled,
19684
20480
  className,
19685
- },
19686
- ref
20481
+ }: AdvancedSettingsCardProps,
20482
+ ref: React.Ref<HTMLDivElement>
19687
20483
  ) => {
19688
20484
  return (
19689
20485
  <div
@@ -19849,10 +20645,7 @@ function PromptField({
19849
20645
 
19850
20646
  // \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
20647
 
19852
- const FallbackPromptsCard = React.forwardRef<
19853
- HTMLDivElement,
19854
- FallbackPromptsCardProps
19855
- >(
20648
+ const FallbackPromptsCard = React.forwardRef(
19856
20649
  (
19857
20650
  {
19858
20651
  data,
@@ -19863,8 +20656,8 @@ const FallbackPromptsCard = React.forwardRef<
19863
20656
  disabled,
19864
20657
  defaultOpen = false,
19865
20658
  className,
19866
- },
19867
- ref
20659
+ }: FallbackPromptsCardProps,
20660
+ ref: React.Ref<HTMLDivElement>
19868
20661
  ) => {
19869
20662
  return (
19870
20663
  <div
@@ -19945,6 +20738,35 @@ export interface KeyValuePair {
19945
20738
  value: string;
19946
20739
  }
19947
20740
 
20741
+ /** A single variable shown in the {{ autocomplete popup */
20742
+ export interface VariableItem {
20743
+ /** Display name (e.g., "Order_id") */
20744
+ name: string;
20745
+ /** Value inserted into the input. Defaults to \`{{name}}\` if omitted */
20746
+ value?: string;
20747
+ /** When true, an edit icon is shown next to this variable */
20748
+ editable?: boolean;
20749
+ /** Description of what this variable represents */
20750
+ description?: string;
20751
+ /** Whether this variable is required */
20752
+ required?: boolean;
20753
+ }
20754
+
20755
+ /** Data shape for creating or editing a variable */
20756
+ export interface VariableFormData {
20757
+ name: string;
20758
+ description?: string;
20759
+ required?: boolean;
20760
+ }
20761
+
20762
+ /** A labelled group of variables in the autocomplete popup */
20763
+ export interface VariableGroup {
20764
+ /** Group header text (e.g., "Function variables", "Session variables") */
20765
+ label: string;
20766
+ /** Variables in this group */
20767
+ items: VariableItem[];
20768
+ }
20769
+
19948
20770
  export interface FunctionItem {
19949
20771
  id: string;
19950
20772
  name: string;
@@ -19995,6 +20817,12 @@ export interface CreateFunctionModalProps {
19995
20817
  initialTab?: FunctionTabType;
19996
20818
  /** Session variables available for {{ autocomplete in URL, body, header values, and query param values */
19997
20819
  sessionVariables?: string[];
20820
+ /** Grouped variables shown in the {{ autocomplete popup (overrides flat list display when provided) */
20821
+ variableGroups?: VariableGroup[];
20822
+ /** Called when user saves a new variable from the autocomplete popup */
20823
+ onAddVariable?: (data: VariableFormData) => void;
20824
+ /** Called when user edits a variable from the autocomplete popup */
20825
+ onEditVariable?: (originalName: string, data: VariableFormData) => void;
19998
20826
  /** When true, all form fields are disabled (view mode) but Next is enabled so user can browse steps */
19999
20827
  disabled?: boolean;
20000
20828
  className?: string;
@@ -20155,6 +20983,9 @@ export type {
20155
20983
  HttpMethod,
20156
20984
  FunctionTabType,
20157
20985
  SelectOption,
20986
+ VariableItem,
20987
+ VariableGroup,
20988
+ VariableFormData,
20158
20989
  } from "./types";
20159
20990
  `, prefix)
20160
20991
  }
@@ -20224,7 +21055,7 @@ function formatCurrency(amount: number, symbol: string = "\u20B9"): string {
20224
21055
  * />
20225
21056
  * \`\`\`
20226
21057
  */
20227
- export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
21058
+ export const WalletTopup = React.forwardRef(
20228
21059
  (
20229
21060
  {
20230
21061
  title = "Instant wallet top-up",
@@ -20271,8 +21102,8 @@ export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
20271
21102
  open,
20272
21103
  onOpenChange,
20273
21104
  className,
20274
- },
20275
- ref
21105
+ }: WalletTopupProps,
21106
+ ref: React.Ref<HTMLDivElement>
20276
21107
  ) => {
20277
21108
  const isOpenControlled = open !== undefined;
20278
21109