@copilotkitnext/react 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -50,6 +50,8 @@ __export(index_exports, {
50
50
  CopilotKitInspector: () => CopilotKitInspector,
51
51
  CopilotKitProvider: () => CopilotKitProvider,
52
52
  CopilotModalHeader: () => CopilotModalHeader,
53
+ CopilotPopup: () => CopilotPopup,
54
+ CopilotPopupView: () => CopilotPopupView,
53
55
  CopilotSidebar: () => CopilotSidebar,
54
56
  CopilotSidebarView: () => CopilotSidebarView,
55
57
  WildcardToolCallRender: () => WildcardToolCallRender,
@@ -560,6 +562,8 @@ function renderSlot(slot, DefaultComponent, props) {
560
562
 
561
563
  // src/components/chat/CopilotChatInput.tsx
562
564
  var import_jsx_runtime6 = require("react/jsx-runtime");
565
+ var SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
566
+ var SLASH_MENU_ITEM_HEIGHT_PX = 40;
563
567
  function CopilotChatInput({
564
568
  mode = "input",
565
569
  onSubmitMessage,
@@ -571,15 +575,12 @@ function CopilotChatInput({
571
575
  value,
572
576
  toolsMenu,
573
577
  autoFocus = true,
574
- additionalToolbarItems,
575
578
  textArea,
576
579
  sendButton,
577
580
  startTranscribeButton,
578
581
  cancelTranscribeButton,
579
582
  finishTranscribeButton,
580
- addFileButton,
581
- toolsButton,
582
- toolbar,
583
+ addMenuButton,
583
584
  audioRecorder,
584
585
  children,
585
586
  className,
@@ -593,10 +594,82 @@ function CopilotChatInput({
593
594
  }
594
595
  }, [isControlled, value]);
595
596
  const resolvedValue = isControlled ? value ?? "" : internalValue;
597
+ const [layout, setLayout] = (0, import_react4.useState)("compact");
598
+ const ignoreResizeRef = (0, import_react4.useRef)(false);
599
+ const resizeEvaluationRafRef = (0, import_react4.useRef)(null);
600
+ const isExpanded = mode === "input" && layout === "expanded";
601
+ const [commandQuery, setCommandQuery] = (0, import_react4.useState)(null);
602
+ const [slashHighlightIndex, setSlashHighlightIndex] = (0, import_react4.useState)(0);
596
603
  const inputRef = (0, import_react4.useRef)(null);
604
+ const gridRef = (0, import_react4.useRef)(null);
605
+ const addButtonContainerRef = (0, import_react4.useRef)(null);
606
+ const actionsContainerRef = (0, import_react4.useRef)(null);
597
607
  const audioRecorderRef = (0, import_react4.useRef)(null);
608
+ const slashMenuRef = (0, import_react4.useRef)(null);
598
609
  const config = useCopilotChatConfiguration();
610
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
599
611
  const previousModalStateRef = (0, import_react4.useRef)(void 0);
612
+ const measurementCanvasRef = (0, import_react4.useRef)(null);
613
+ const measurementsRef = (0, import_react4.useRef)({
614
+ singleLineHeight: 0,
615
+ maxHeight: 0,
616
+ paddingLeft: 0,
617
+ paddingRight: 0
618
+ });
619
+ const commandItems = (0, import_react4.useMemo)(() => {
620
+ const entries = [];
621
+ const seen = /* @__PURE__ */ new Set();
622
+ const pushItem = (item) => {
623
+ if (item === "-") {
624
+ return;
625
+ }
626
+ if (item.items && item.items.length > 0) {
627
+ for (const nested of item.items) {
628
+ pushItem(nested);
629
+ }
630
+ return;
631
+ }
632
+ if (!seen.has(item.label)) {
633
+ seen.add(item.label);
634
+ entries.push(item);
635
+ }
636
+ };
637
+ if (onAddFile) {
638
+ pushItem({
639
+ label: labels.chatInputToolbarAddButtonLabel,
640
+ action: onAddFile
641
+ });
642
+ }
643
+ if (toolsMenu && toolsMenu.length > 0) {
644
+ for (const item of toolsMenu) {
645
+ pushItem(item);
646
+ }
647
+ }
648
+ return entries;
649
+ }, [labels.chatInputToolbarAddButtonLabel, onAddFile, toolsMenu]);
650
+ const filteredCommands = (0, import_react4.useMemo)(() => {
651
+ if (commandQuery === null) {
652
+ return [];
653
+ }
654
+ if (commandItems.length === 0) {
655
+ return [];
656
+ }
657
+ const query = commandQuery.trim().toLowerCase();
658
+ if (query.length === 0) {
659
+ return commandItems;
660
+ }
661
+ const startsWith = [];
662
+ const contains = [];
663
+ for (const item of commandItems) {
664
+ const label = item.label.toLowerCase();
665
+ if (label.startsWith(query)) {
666
+ startsWith.push(item);
667
+ } else if (label.includes(query)) {
668
+ contains.push(item);
669
+ }
670
+ }
671
+ return [...startsWith, ...contains];
672
+ }, [commandItems, commandQuery]);
600
673
  (0, import_react4.useEffect)(() => {
601
674
  if (!autoFocus) {
602
675
  previousModalStateRef.current = config?.isModalOpen;
@@ -607,6 +680,29 @@ function CopilotChatInput({
607
680
  }
608
681
  previousModalStateRef.current = config?.isModalOpen;
609
682
  }, [config?.isModalOpen, autoFocus]);
683
+ (0, import_react4.useEffect)(() => {
684
+ if (commandItems.length === 0 && commandQuery !== null) {
685
+ setCommandQuery(null);
686
+ }
687
+ }, [commandItems.length, commandQuery]);
688
+ const previousCommandQueryRef = (0, import_react4.useRef)(null);
689
+ (0, import_react4.useEffect)(() => {
690
+ if (commandQuery !== null && commandQuery !== previousCommandQueryRef.current && filteredCommands.length > 0) {
691
+ setSlashHighlightIndex(0);
692
+ }
693
+ previousCommandQueryRef.current = commandQuery;
694
+ }, [commandQuery, filteredCommands.length]);
695
+ (0, import_react4.useEffect)(() => {
696
+ if (commandQuery === null) {
697
+ setSlashHighlightIndex(0);
698
+ return;
699
+ }
700
+ if (filteredCommands.length === 0) {
701
+ setSlashHighlightIndex(-1);
702
+ } else if (slashHighlightIndex < 0 || slashHighlightIndex >= filteredCommands.length) {
703
+ setSlashHighlightIndex(0);
704
+ }
705
+ }, [commandQuery, filteredCommands, slashHighlightIndex]);
610
706
  (0, import_react4.useEffect)(() => {
611
707
  const recorder = audioRecorderRef.current;
612
708
  if (!recorder) {
@@ -620,14 +716,103 @@ function CopilotChatInput({
620
716
  }
621
717
  }
622
718
  }, [mode]);
719
+ (0, import_react4.useEffect)(() => {
720
+ if (mode !== "input") {
721
+ setLayout("compact");
722
+ setCommandQuery(null);
723
+ }
724
+ }, [mode]);
725
+ const updateSlashState = (0, import_react4.useCallback)(
726
+ (value2) => {
727
+ if (commandItems.length === 0) {
728
+ setCommandQuery((prev) => prev === null ? prev : null);
729
+ return;
730
+ }
731
+ if (value2.startsWith("/")) {
732
+ const firstLine = value2.split(/\r?\n/, 1)[0] ?? "";
733
+ const query = firstLine.slice(1);
734
+ setCommandQuery((prev) => prev === query ? prev : query);
735
+ } else {
736
+ setCommandQuery((prev) => prev === null ? prev : null);
737
+ }
738
+ },
739
+ [commandItems.length]
740
+ );
741
+ (0, import_react4.useEffect)(() => {
742
+ updateSlashState(resolvedValue);
743
+ }, [resolvedValue, updateSlashState]);
623
744
  const handleChange = (e) => {
624
745
  const nextValue = e.target.value;
625
746
  if (!isControlled) {
626
747
  setInternalValue(nextValue);
627
748
  }
628
749
  onChange?.(nextValue);
750
+ updateSlashState(nextValue);
629
751
  };
752
+ const clearInputValue = (0, import_react4.useCallback)(() => {
753
+ if (!isControlled) {
754
+ setInternalValue("");
755
+ }
756
+ if (onChange) {
757
+ onChange("");
758
+ }
759
+ }, [isControlled, onChange]);
760
+ const runCommand = (0, import_react4.useCallback)(
761
+ (item) => {
762
+ clearInputValue();
763
+ item.action?.();
764
+ setCommandQuery(null);
765
+ setSlashHighlightIndex(0);
766
+ requestAnimationFrame(() => {
767
+ inputRef.current?.focus();
768
+ });
769
+ },
770
+ [clearInputValue]
771
+ );
630
772
  const handleKeyDown = (e) => {
773
+ if (commandQuery !== null && mode === "input") {
774
+ if (e.key === "ArrowDown") {
775
+ if (filteredCommands.length > 0) {
776
+ e.preventDefault();
777
+ setSlashHighlightIndex((prev) => {
778
+ if (filteredCommands.length === 0) {
779
+ return prev;
780
+ }
781
+ const next = prev === -1 ? 0 : (prev + 1) % filteredCommands.length;
782
+ return next;
783
+ });
784
+ }
785
+ return;
786
+ }
787
+ if (e.key === "ArrowUp") {
788
+ if (filteredCommands.length > 0) {
789
+ e.preventDefault();
790
+ setSlashHighlightIndex((prev) => {
791
+ if (filteredCommands.length === 0) {
792
+ return prev;
793
+ }
794
+ if (prev === -1) {
795
+ return filteredCommands.length - 1;
796
+ }
797
+ return prev <= 0 ? filteredCommands.length - 1 : prev - 1;
798
+ });
799
+ }
800
+ return;
801
+ }
802
+ if (e.key === "Enter") {
803
+ const selected = slashHighlightIndex >= 0 ? filteredCommands[slashHighlightIndex] : void 0;
804
+ if (selected) {
805
+ e.preventDefault();
806
+ runCommand(selected);
807
+ return;
808
+ }
809
+ }
810
+ if (e.key === "Escape") {
811
+ e.preventDefault();
812
+ setCommandQuery(null);
813
+ return;
814
+ }
815
+ }
631
816
  if (e.key === "Enter" && !e.shiftKey) {
632
817
  e.preventDefault();
633
818
  send();
@@ -655,7 +840,11 @@ function CopilotChatInput({
655
840
  value: resolvedValue,
656
841
  onChange: handleChange,
657
842
  onKeyDown: handleKeyDown,
658
- autoFocus
843
+ autoFocus,
844
+ className: (0, import_tailwind_merge3.twMerge)(
845
+ "w-full py-3",
846
+ isExpanded ? "px-5" : "pr-5"
847
+ )
659
848
  });
660
849
  const BoundAudioRecorder = renderSlot(audioRecorder, CopilotChatAudioRecorder, {
661
850
  ref: audioRecorderRef
@@ -673,45 +862,20 @@ function CopilotChatInput({
673
862
  const BoundFinishTranscribeButton = renderSlot(finishTranscribeButton, CopilotChatInput.FinishTranscribeButton, {
674
863
  onClick: onFinishTranscribe
675
864
  });
676
- const BoundAddFileButton = renderSlot(addFileButton, CopilotChatInput.AddFileButton, {
677
- onClick: onAddFile,
678
- disabled: mode === "transcribe"
679
- });
680
- const BoundToolsButton = renderSlot(toolsButton, CopilotChatInput.ToolsButton, {
865
+ const BoundAddMenuButton = renderSlot(addMenuButton, CopilotChatInput.AddMenuButton, {
681
866
  disabled: mode === "transcribe",
867
+ onAddFile,
682
868
  toolsMenu
683
869
  });
684
- const BoundToolbar = renderSlot(
685
- typeof toolbar === "string" || toolbar === void 0 ? (0, import_tailwind_merge3.twMerge)(toolbar, "w-full h-[60px] bg-transparent flex items-center justify-between") : toolbar,
686
- CopilotChatInput.Toolbar,
687
- {
688
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
689
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center", children: [
690
- onAddFile && BoundAddFileButton,
691
- BoundToolsButton,
692
- additionalToolbarItems
693
- ] }),
694
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-center", children: mode === "transcribe" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
695
- onCancelTranscribe && BoundCancelTranscribeButton,
696
- onFinishTranscribe && BoundFinishTranscribeButton
697
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
698
- onStartTranscribe && BoundStartTranscribeButton,
699
- BoundSendButton
700
- ] }) })
701
- ] })
702
- }
703
- );
704
870
  if (children) {
705
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: children({
871
+ const childProps = {
706
872
  textArea: BoundTextArea,
707
873
  audioRecorder: BoundAudioRecorder,
708
874
  sendButton: BoundSendButton,
709
875
  startTranscribeButton: BoundStartTranscribeButton,
710
876
  cancelTranscribeButton: BoundCancelTranscribeButton,
711
877
  finishTranscribeButton: BoundFinishTranscribeButton,
712
- addFileButton: BoundAddFileButton,
713
- toolsButton: BoundToolsButton,
714
- toolbar: BoundToolbar,
878
+ addMenuButton: BoundAddMenuButton,
715
879
  onSubmitMessage,
716
880
  onStartTranscribe,
717
881
  onCancelTranscribe,
@@ -719,9 +883,9 @@ function CopilotChatInput({
719
883
  onAddFile,
720
884
  mode,
721
885
  toolsMenu,
722
- autoFocus,
723
- additionalToolbarItems
724
- }) });
886
+ autoFocus
887
+ };
888
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: children(childProps) });
725
889
  }
726
890
  const handleContainerClick = (e) => {
727
891
  const target = e.target;
@@ -729,7 +893,227 @@ function CopilotChatInput({
729
893
  inputRef.current.focus();
730
894
  }
731
895
  };
732
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
896
+ const ensureMeasurements = (0, import_react4.useCallback)(() => {
897
+ const textarea = inputRef.current;
898
+ if (!textarea) {
899
+ return;
900
+ }
901
+ const previousValue = textarea.value;
902
+ const previousHeight = textarea.style.height;
903
+ textarea.style.height = "auto";
904
+ const computedStyle = window.getComputedStyle(textarea);
905
+ const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;
906
+ const paddingRight = parseFloat(computedStyle.paddingRight) || 0;
907
+ const paddingTop = parseFloat(computedStyle.paddingTop) || 0;
908
+ const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0;
909
+ textarea.value = "";
910
+ const singleLineHeight = textarea.scrollHeight;
911
+ textarea.value = previousValue;
912
+ const contentHeight = singleLineHeight - paddingTop - paddingBottom;
913
+ const maxHeight = contentHeight * 5 + paddingTop + paddingBottom;
914
+ measurementsRef.current = {
915
+ singleLineHeight,
916
+ maxHeight,
917
+ paddingLeft,
918
+ paddingRight
919
+ };
920
+ textarea.style.height = previousHeight;
921
+ textarea.style.maxHeight = `${maxHeight}px`;
922
+ }, []);
923
+ const adjustTextareaHeight = (0, import_react4.useCallback)(() => {
924
+ const textarea = inputRef.current;
925
+ if (!textarea) {
926
+ return 0;
927
+ }
928
+ if (measurementsRef.current.singleLineHeight === 0) {
929
+ ensureMeasurements();
930
+ }
931
+ const { maxHeight } = measurementsRef.current;
932
+ if (maxHeight) {
933
+ textarea.style.maxHeight = `${maxHeight}px`;
934
+ }
935
+ textarea.style.height = "auto";
936
+ const scrollHeight = textarea.scrollHeight;
937
+ if (maxHeight) {
938
+ textarea.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
939
+ } else {
940
+ textarea.style.height = `${scrollHeight}px`;
941
+ }
942
+ return scrollHeight;
943
+ }, [ensureMeasurements]);
944
+ const updateLayout = (0, import_react4.useCallback)((nextLayout) => {
945
+ setLayout((prev) => {
946
+ if (prev === nextLayout) {
947
+ return prev;
948
+ }
949
+ ignoreResizeRef.current = true;
950
+ return nextLayout;
951
+ });
952
+ }, []);
953
+ const evaluateLayout = (0, import_react4.useCallback)(() => {
954
+ if (mode !== "input") {
955
+ updateLayout("compact");
956
+ return;
957
+ }
958
+ if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
959
+ const isMobileViewport = window.matchMedia("(max-width: 767px)").matches;
960
+ if (isMobileViewport) {
961
+ ensureMeasurements();
962
+ adjustTextareaHeight();
963
+ updateLayout("expanded");
964
+ return;
965
+ }
966
+ }
967
+ const textarea = inputRef.current;
968
+ const grid = gridRef.current;
969
+ const addContainer = addButtonContainerRef.current;
970
+ const actionsContainer = actionsContainerRef.current;
971
+ if (!textarea || !grid || !addContainer || !actionsContainer) {
972
+ return;
973
+ }
974
+ if (measurementsRef.current.singleLineHeight === 0) {
975
+ ensureMeasurements();
976
+ }
977
+ const scrollHeight = adjustTextareaHeight();
978
+ const baseline = measurementsRef.current.singleLineHeight;
979
+ const hasExplicitBreak = resolvedValue.includes("\n");
980
+ const renderedMultiline = baseline > 0 ? scrollHeight > baseline + 1 : false;
981
+ let shouldExpand = hasExplicitBreak || renderedMultiline;
982
+ if (!shouldExpand) {
983
+ const gridStyles = window.getComputedStyle(grid);
984
+ const paddingLeft = parseFloat(gridStyles.paddingLeft) || 0;
985
+ const paddingRight = parseFloat(gridStyles.paddingRight) || 0;
986
+ const columnGap = parseFloat(gridStyles.columnGap) || 0;
987
+ const gridAvailableWidth = grid.clientWidth - paddingLeft - paddingRight;
988
+ if (gridAvailableWidth > 0) {
989
+ const addWidth = addContainer.getBoundingClientRect().width;
990
+ const actionsWidth = actionsContainer.getBoundingClientRect().width;
991
+ const compactWidth = Math.max(gridAvailableWidth - addWidth - actionsWidth - columnGap * 2, 0);
992
+ const canvas = measurementCanvasRef.current ?? document.createElement("canvas");
993
+ if (!measurementCanvasRef.current) {
994
+ measurementCanvasRef.current = canvas;
995
+ }
996
+ const context = canvas.getContext("2d");
997
+ if (context) {
998
+ const textareaStyles = window.getComputedStyle(textarea);
999
+ const font = textareaStyles.font || `${textareaStyles.fontStyle} ${textareaStyles.fontVariant} ${textareaStyles.fontWeight} ${textareaStyles.fontSize}/${textareaStyles.lineHeight} ${textareaStyles.fontFamily}`;
1000
+ context.font = font;
1001
+ const compactInnerWidth = Math.max(
1002
+ compactWidth - (measurementsRef.current.paddingLeft || 0) - (measurementsRef.current.paddingRight || 0),
1003
+ 0
1004
+ );
1005
+ if (compactInnerWidth > 0) {
1006
+ const lines = resolvedValue.length > 0 ? resolvedValue.split("\n") : [""];
1007
+ let longestWidth = 0;
1008
+ for (const line of lines) {
1009
+ const metrics = context.measureText(line || " ");
1010
+ if (metrics.width > longestWidth) {
1011
+ longestWidth = metrics.width;
1012
+ }
1013
+ }
1014
+ if (longestWidth > compactInnerWidth) {
1015
+ shouldExpand = true;
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ const nextLayout = shouldExpand ? "expanded" : "compact";
1022
+ updateLayout(nextLayout);
1023
+ }, [adjustTextareaHeight, ensureMeasurements, mode, resolvedValue, updateLayout]);
1024
+ (0, import_react4.useLayoutEffect)(() => {
1025
+ evaluateLayout();
1026
+ }, [evaluateLayout]);
1027
+ (0, import_react4.useEffect)(() => {
1028
+ if (typeof ResizeObserver === "undefined") {
1029
+ return;
1030
+ }
1031
+ const textarea = inputRef.current;
1032
+ const grid = gridRef.current;
1033
+ const addContainer = addButtonContainerRef.current;
1034
+ const actionsContainer = actionsContainerRef.current;
1035
+ if (!textarea || !grid || !addContainer || !actionsContainer) {
1036
+ return;
1037
+ }
1038
+ const scheduleEvaluation = () => {
1039
+ if (ignoreResizeRef.current) {
1040
+ ignoreResizeRef.current = false;
1041
+ return;
1042
+ }
1043
+ if (typeof window === "undefined") {
1044
+ evaluateLayout();
1045
+ return;
1046
+ }
1047
+ if (resizeEvaluationRafRef.current !== null) {
1048
+ cancelAnimationFrame(resizeEvaluationRafRef.current);
1049
+ }
1050
+ resizeEvaluationRafRef.current = window.requestAnimationFrame(() => {
1051
+ resizeEvaluationRafRef.current = null;
1052
+ evaluateLayout();
1053
+ });
1054
+ };
1055
+ const observer = new ResizeObserver(() => {
1056
+ scheduleEvaluation();
1057
+ });
1058
+ observer.observe(grid);
1059
+ observer.observe(addContainer);
1060
+ observer.observe(actionsContainer);
1061
+ observer.observe(textarea);
1062
+ return () => {
1063
+ observer.disconnect();
1064
+ if (typeof window !== "undefined" && resizeEvaluationRafRef.current !== null) {
1065
+ cancelAnimationFrame(resizeEvaluationRafRef.current);
1066
+ resizeEvaluationRafRef.current = null;
1067
+ }
1068
+ };
1069
+ }, [evaluateLayout]);
1070
+ const slashMenuVisible = commandQuery !== null && commandItems.length > 0;
1071
+ (0, import_react4.useEffect)(() => {
1072
+ if (!slashMenuVisible || slashHighlightIndex < 0) {
1073
+ return;
1074
+ }
1075
+ const active = slashMenuRef.current?.querySelector(
1076
+ `[data-slash-index="${slashHighlightIndex}"]`
1077
+ );
1078
+ active?.scrollIntoView({ block: "nearest" });
1079
+ }, [slashMenuVisible, slashHighlightIndex]);
1080
+ const slashMenu = slashMenuVisible ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1081
+ "div",
1082
+ {
1083
+ "data-testid": "copilot-slash-menu",
1084
+ role: "listbox",
1085
+ "aria-label": "Slash commands",
1086
+ ref: slashMenuRef,
1087
+ className: "absolute bottom-full left-0 right-0 z-30 mb-2 max-h-64 overflow-y-auto rounded-lg border border-border bg-white shadow-lg dark:border-[#3a3a3a] dark:bg-[#1f1f1f]",
1088
+ style: { maxHeight: `${SLASH_MENU_MAX_VISIBLE_ITEMS * SLASH_MENU_ITEM_HEIGHT_PX}px` },
1089
+ children: filteredCommands.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "No commands found" }) : filteredCommands.map((item, index) => {
1090
+ const isActive = index === slashHighlightIndex;
1091
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1092
+ "button",
1093
+ {
1094
+ type: "button",
1095
+ role: "option",
1096
+ "aria-selected": isActive,
1097
+ "data-active": isActive ? "true" : void 0,
1098
+ "data-slash-index": index,
1099
+ className: (0, import_tailwind_merge3.twMerge)(
1100
+ "w-full px-3 py-2 text-left text-sm transition-colors",
1101
+ "hover:bg-muted dark:hover:bg-[#2f2f2f]",
1102
+ isActive ? "bg-muted dark:bg-[#2f2f2f]" : "bg-transparent"
1103
+ ),
1104
+ onMouseEnter: () => setSlashHighlightIndex(index),
1105
+ onMouseDown: (event) => {
1106
+ event.preventDefault();
1107
+ runCommand(item);
1108
+ },
1109
+ children: item.label
1110
+ },
1111
+ `${item.label}-${index}`
1112
+ );
1113
+ })
1114
+ }
1115
+ ) : null;
1116
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
733
1117
  "div",
734
1118
  {
735
1119
  className: (0, import_tailwind_merge3.twMerge)(
@@ -747,10 +1131,62 @@ function CopilotChatInput({
747
1131
  ),
748
1132
  onClick: handleContainerClick,
749
1133
  ...props,
750
- children: [
751
- mode === "transcribe" ? BoundAudioRecorder : BoundTextArea,
752
- BoundToolbar
753
- ]
1134
+ "data-layout": isExpanded ? "expanded" : "compact",
1135
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1136
+ "div",
1137
+ {
1138
+ ref: gridRef,
1139
+ className: (0, import_tailwind_merge3.twMerge)(
1140
+ "grid w-full gap-x-3 gap-y-3 px-3 py-2",
1141
+ isExpanded ? "grid-cols-[auto_minmax(0,1fr)_auto] grid-rows-[auto_auto]" : "grid-cols-[auto_minmax(0,1fr)_auto] items-center"
1142
+ ),
1143
+ "data-layout": isExpanded ? "expanded" : "compact",
1144
+ children: [
1145
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1146
+ "div",
1147
+ {
1148
+ ref: addButtonContainerRef,
1149
+ className: (0, import_tailwind_merge3.twMerge)(
1150
+ "flex items-center",
1151
+ isExpanded ? "row-start-2" : "row-start-1",
1152
+ "col-start-1"
1153
+ ),
1154
+ children: BoundAddMenuButton
1155
+ }
1156
+ ),
1157
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1158
+ "div",
1159
+ {
1160
+ className: (0, import_tailwind_merge3.twMerge)(
1161
+ "relative flex min-w-0 flex-col",
1162
+ isExpanded ? "col-span-3 row-start-1" : "col-start-2 row-start-1"
1163
+ ),
1164
+ children: mode === "transcribe" ? BoundAudioRecorder : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1165
+ BoundTextArea,
1166
+ slashMenu
1167
+ ] })
1168
+ }
1169
+ ),
1170
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1171
+ "div",
1172
+ {
1173
+ ref: actionsContainerRef,
1174
+ className: (0, import_tailwind_merge3.twMerge)(
1175
+ "flex items-center justify-end gap-2",
1176
+ isExpanded ? "col-start-3 row-start-2" : "col-start-3 row-start-1"
1177
+ ),
1178
+ children: mode === "transcribe" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1179
+ onCancelTranscribe && BoundCancelTranscribeButton,
1180
+ onFinishTranscribe && BoundFinishTranscribeButton
1181
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1182
+ onStartTranscribe && BoundStartTranscribeButton,
1183
+ BoundSendButton
1184
+ ] })
1185
+ }
1186
+ )
1187
+ ]
1188
+ }
1189
+ )
754
1190
  }
755
1191
  );
756
1192
  }
@@ -811,124 +1247,110 @@ function CopilotChatInput({
811
1247
  ...props
812
1248
  }
813
1249
  );
814
- CopilotChatInput2.AddFileButton = (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
815
- CopilotChatInput2.ToolbarButton,
816
- {
817
- icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Plus, { className: "size-[20px]" }),
818
- labelKey: "chatInputToolbarAddButtonLabel",
819
- defaultClassName: "ml-2",
820
- ...props
821
- }
822
- );
823
- CopilotChatInput2.ToolsButton = ({ className, toolsMenu, ...props }) => {
1250
+ CopilotChatInput2.AddMenuButton = ({ className, toolsMenu, onAddFile, disabled, ...props }) => {
824
1251
  const config = useCopilotChatConfiguration();
825
1252
  const labels = config?.labels ?? CopilotChatDefaultLabels;
826
- const renderMenuItems = (items) => {
827
- return items.map((item, index) => {
1253
+ const menuItems = (0, import_react4.useMemo)(() => {
1254
+ const items = [];
1255
+ if (onAddFile) {
1256
+ items.push({
1257
+ label: labels.chatInputToolbarAddButtonLabel,
1258
+ action: onAddFile
1259
+ });
1260
+ }
1261
+ if (toolsMenu && toolsMenu.length > 0) {
1262
+ if (items.length > 0) {
1263
+ items.push("-");
1264
+ }
1265
+ for (const item of toolsMenu) {
1266
+ if (item === "-") {
1267
+ if (items.length === 0 || items[items.length - 1] === "-") {
1268
+ continue;
1269
+ }
1270
+ items.push(item);
1271
+ } else {
1272
+ items.push(item);
1273
+ }
1274
+ }
1275
+ while (items.length > 0 && items[items.length - 1] === "-") {
1276
+ items.pop();
1277
+ }
1278
+ }
1279
+ return items;
1280
+ }, [onAddFile, toolsMenu, labels.chatInputToolbarAddButtonLabel]);
1281
+ const renderMenuItems = (0, import_react4.useCallback)(
1282
+ (items) => items.map((item, index) => {
828
1283
  if (item === "-") {
829
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuSeparator, {}, index);
830
- } else if (item.items && item.items.length > 0) {
1284
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuSeparator, {}, `separator-${index}`);
1285
+ }
1286
+ if (item.items && item.items.length > 0) {
831
1287
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenuSub, { children: [
832
1288
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuSubTrigger, { children: item.label }),
833
1289
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuSubContent, { children: renderMenuItems(item.items) })
834
- ] }, index);
835
- } else {
836
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuItem, { onClick: item.action, children: item.label }, index);
1290
+ ] }, `group-${index}`);
837
1291
  }
838
- });
839
- };
840
- if (!toolsMenu || toolsMenu.length === 0) {
841
- return null;
842
- }
1292
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuItem, { onClick: item.action, children: item.label }, `item-${index}`);
1293
+ }),
1294
+ []
1295
+ );
1296
+ const hasMenuItems = menuItems.length > 0;
1297
+ const isDisabled = disabled || !hasMenuItems;
843
1298
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenu, { children: [
844
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
845
- Button,
846
- {
847
- type: "button",
848
- variant: "chatInputToolbarSecondary",
849
- size: "chatInputToolbarIconLabel",
850
- className,
851
- ...props,
852
- children: [
853
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Settings2, { className: "size-[18px]" }),
854
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-normal", children: labels.chatInputToolbarToolsButtonLabel })
855
- ]
856
- }
857
- ) }),
858
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuContent, { side: "top", align: "end", children: renderMenuItems(toolsMenu) })
1299
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Tooltip, { children: [
1300
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1301
+ Button,
1302
+ {
1303
+ type: "button",
1304
+ variant: "chatInputToolbarSecondary",
1305
+ size: "chatInputToolbarIcon",
1306
+ className: (0, import_tailwind_merge3.twMerge)("ml-1", className),
1307
+ disabled: isDisabled,
1308
+ ...props,
1309
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Plus, { className: "size-[20px]" })
1310
+ }
1311
+ ) }) }),
1312
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipContent, { side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "flex items-center gap-1 text-xs font-medium", children: [
1313
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Add files and more" }),
1314
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "rounded bg-[#4a4a4a] px-1 py-[1px] font-mono text-[11px] text-white dark:bg-[#e0e0e0] dark:text-black", children: "/" })
1315
+ ] }) })
1316
+ ] }),
1317
+ hasMenuItems && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuContent, { side: "top", align: "start", children: renderMenuItems(menuItems) })
859
1318
  ] });
860
1319
  };
861
- CopilotChatInput2.Toolbar = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("w-full h-[60px] bg-transparent flex items-center", className), ...props });
862
- CopilotChatInput2.TextArea = (0, import_react4.forwardRef)(function TextArea2({ maxRows = 5, style, className, ...props }, ref) {
1320
+ CopilotChatInput2.TextArea = (0, import_react4.forwardRef)(function TextArea2({ style, className, autoFocus, ...props }, ref) {
863
1321
  const internalTextareaRef = (0, import_react4.useRef)(null);
864
- const [maxHeight, setMaxHeight] = (0, import_react4.useState)(0);
865
1322
  const config = useCopilotChatConfiguration();
866
1323
  const labels = config?.labels ?? CopilotChatDefaultLabels;
867
1324
  (0, import_react4.useImperativeHandle)(ref, () => internalTextareaRef.current);
868
- const adjustHeight = () => {
869
- const textarea = internalTextareaRef.current;
870
- if (textarea && maxHeight > 0) {
871
- textarea.style.height = "auto";
872
- textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
873
- }
874
- };
875
1325
  (0, import_react4.useEffect)(() => {
876
- const calculateMaxHeight = () => {
877
- const textarea = internalTextareaRef.current;
878
- if (textarea) {
879
- const currentValue = textarea.value;
880
- textarea.value = "";
881
- textarea.style.height = "auto";
882
- const computedStyle = window.getComputedStyle(textarea);
883
- const paddingTop = parseFloat(computedStyle.paddingTop);
884
- const paddingBottom = parseFloat(computedStyle.paddingBottom);
885
- const contentHeight = textarea.scrollHeight - paddingTop - paddingBottom;
886
- setMaxHeight(contentHeight * maxRows + paddingTop + paddingBottom);
887
- textarea.value = currentValue;
888
- if (currentValue) {
889
- textarea.style.height = "auto";
890
- textarea.style.height = `${Math.min(textarea.scrollHeight, contentHeight * maxRows + paddingTop + paddingBottom)}px`;
891
- }
892
- if (props.autoFocus) {
893
- textarea.focus();
894
- }
895
- }
1326
+ const textarea = internalTextareaRef.current;
1327
+ if (!textarea) return;
1328
+ const handleFocus = () => {
1329
+ setTimeout(() => {
1330
+ textarea.scrollIntoView({ behavior: "smooth", block: "nearest" });
1331
+ }, 300);
896
1332
  };
897
- calculateMaxHeight();
898
- }, [maxRows, props.autoFocus]);
1333
+ textarea.addEventListener("focus", handleFocus);
1334
+ return () => textarea.removeEventListener("focus", handleFocus);
1335
+ }, []);
899
1336
  (0, import_react4.useEffect)(() => {
900
- adjustHeight();
901
- }, [props.value, maxHeight]);
902
- const handleInput = (e) => {
903
- adjustHeight();
904
- if (props.onChange) {
905
- props.onChange(e);
1337
+ if (autoFocus) {
1338
+ internalTextareaRef.current?.focus();
906
1339
  }
907
- };
1340
+ }, [autoFocus]);
908
1341
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
909
1342
  "textarea",
910
1343
  {
911
1344
  ref: internalTextareaRef,
912
1345
  ...props,
913
- onChange: handleInput,
914
1346
  style: {
915
1347
  overflow: "auto",
916
1348
  resize: "none",
917
- maxHeight: `${maxHeight}px`,
918
1349
  ...style
919
1350
  },
920
1351
  placeholder: labels.chatInputPlaceholder,
921
1352
  className: (0, import_tailwind_merge3.twMerge)(
922
- // Layout and sizing
923
- "w-full p-5 pb-0",
924
- // Behavior
925
- "outline-none resize-none",
926
- // Background
927
- "bg-transparent",
928
- // Typography
929
- "antialiased font-regular leading-relaxed text-[16px]",
930
- // Placeholder styles
931
- "placeholder:text-[#00000077] dark:placeholder:text-[#fffc]",
1353
+ "bg-transparent outline-none antialiased font-regular leading-relaxed text-[16px] placeholder:text-[#00000077] dark:placeholder:text-[#fffc]",
932
1354
  className
933
1355
  ),
934
1356
  rows: 1
@@ -943,9 +1365,7 @@ CopilotChatInput.ToolbarButton.displayName = "CopilotChatInput.ToolbarButton";
943
1365
  CopilotChatInput.StartTranscribeButton.displayName = "CopilotChatInput.StartTranscribeButton";
944
1366
  CopilotChatInput.CancelTranscribeButton.displayName = "CopilotChatInput.CancelTranscribeButton";
945
1367
  CopilotChatInput.FinishTranscribeButton.displayName = "CopilotChatInput.FinishTranscribeButton";
946
- CopilotChatInput.AddFileButton.displayName = "CopilotChatInput.AddButton";
947
- CopilotChatInput.ToolsButton.displayName = "CopilotChatInput.ToolsButton";
948
- CopilotChatInput.Toolbar.displayName = "CopilotChatInput.Toolbar";
1368
+ CopilotChatInput.AddMenuButton.displayName = "CopilotChatInput.AddMenuButton";
949
1369
  var CopilotChatInput_default = CopilotChatInput;
950
1370
 
951
1371
  // src/components/chat/CopilotChatAssistantMessage.tsx
@@ -2251,7 +2671,7 @@ var CopilotChatUserMessage_default = CopilotChatUserMessage;
2251
2671
  var import_react18 = __toESM(require("react"));
2252
2672
  var import_lucide_react5 = require("lucide-react");
2253
2673
  var import_jsx_runtime14 = require("react/jsx-runtime");
2254
- var baseClasses = "group inline-flex h-8 items-center gap-1.5 rounded-full border border-border/60 bg-background px-3 text-xs leading-none text-foreground transition-colors cursor-pointer hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:text-muted-foreground disabled:hover:bg-background disabled:hover:text-muted-foreground pointer-events-auto";
2674
+ var baseClasses = "group inline-flex h-7 sm:h-8 items-center gap-1 sm:gap-1.5 rounded-full border border-border/60 bg-background px-2.5 sm:px-3 text-[11px] sm:text-xs leading-none text-foreground transition-colors cursor-pointer hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:text-muted-foreground disabled:hover:bg-background disabled:hover:text-muted-foreground pointer-events-auto";
2255
2675
  var labelClasses = "whitespace-nowrap font-medium leading-none";
2256
2676
  var CopilotChatSuggestionPill = import_react18.default.forwardRef(function CopilotChatSuggestionPill2({ className, children, icon, isLoading, type, ...props }, ref) {
2257
2677
  const showIcon = !isLoading && icon;
@@ -2266,7 +2686,7 @@ var CopilotChatSuggestionPill = import_react18.default.forwardRef(function Copil
2266
2686
  disabled: isLoading || props.disabled,
2267
2687
  ...props,
2268
2688
  children: [
2269
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex h-4 w-4 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }) }) : showIcon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex h-4 w-4 items-center justify-center text-muted-foreground", children: icon }),
2689
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex h-3.5 sm:h-4 w-3.5 sm:w-4 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Loader2, { className: "h-3.5 sm:h-4 w-3.5 sm:w-4 animate-spin", "aria-hidden": "true" }) }) : showIcon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex h-3.5 sm:h-4 w-3.5 sm:w-4 items-center justify-center text-muted-foreground", children: icon }),
2270
2690
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: labelClasses, children })
2271
2691
  ]
2272
2692
  }
@@ -2284,7 +2704,7 @@ var DefaultContainer = import_react19.default.forwardRef(function DefaultContain
2284
2704
  {
2285
2705
  ref,
2286
2706
  className: cn(
2287
- "flex flex-wrap items-center gap-2 px-4 sm:px-0 pointer-events-none",
2707
+ "flex flex-wrap items-center gap-1.5 sm:gap-2 pl-0 pr-4 sm:px-0 pointer-events-none",
2288
2708
  className
2289
2709
  ),
2290
2710
  ...props
@@ -2427,10 +2847,52 @@ CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
2427
2847
  var CopilotChatMessageView_default = CopilotChatMessageView;
2428
2848
 
2429
2849
  // src/components/chat/CopilotChatView.tsx
2430
- var import_react20 = __toESM(require("react"));
2850
+ var import_react21 = __toESM(require("react"));
2431
2851
  var import_tailwind_merge7 = require("tailwind-merge");
2432
2852
  var import_use_stick_to_bottom = require("use-stick-to-bottom");
2433
2853
  var import_lucide_react6 = require("lucide-react");
2854
+
2855
+ // src/hooks/use-keyboard-height.tsx
2856
+ var import_react20 = require("react");
2857
+ function useKeyboardHeight() {
2858
+ const [keyboardState, setKeyboardState] = (0, import_react20.useState)({
2859
+ isKeyboardOpen: false,
2860
+ keyboardHeight: 0,
2861
+ availableHeight: typeof window !== "undefined" ? window.innerHeight : 0,
2862
+ viewportHeight: typeof window !== "undefined" ? window.innerHeight : 0
2863
+ });
2864
+ (0, import_react20.useEffect)(() => {
2865
+ if (typeof window === "undefined") {
2866
+ return;
2867
+ }
2868
+ const visualViewport = window.visualViewport;
2869
+ if (!visualViewport) {
2870
+ return;
2871
+ }
2872
+ const updateKeyboardState = () => {
2873
+ const layoutHeight = window.innerHeight;
2874
+ const visualHeight = visualViewport.height;
2875
+ const keyboardHeight = Math.max(0, layoutHeight - visualHeight);
2876
+ const isKeyboardOpen = keyboardHeight > 150;
2877
+ setKeyboardState({
2878
+ isKeyboardOpen,
2879
+ keyboardHeight,
2880
+ availableHeight: visualHeight,
2881
+ viewportHeight: layoutHeight
2882
+ });
2883
+ };
2884
+ updateKeyboardState();
2885
+ visualViewport.addEventListener("resize", updateKeyboardState);
2886
+ visualViewport.addEventListener("scroll", updateKeyboardState);
2887
+ return () => {
2888
+ visualViewport.removeEventListener("resize", updateKeyboardState);
2889
+ visualViewport.removeEventListener("scroll", updateKeyboardState);
2890
+ };
2891
+ }, []);
2892
+ return keyboardState;
2893
+ }
2894
+
2895
+ // src/components/chat/CopilotChatView.tsx
2434
2896
  var import_jsx_runtime17 = require("react/jsx-runtime");
2435
2897
  function CopilotChatView({
2436
2898
  messageView,
@@ -2452,11 +2914,12 @@ function CopilotChatView({
2452
2914
  className,
2453
2915
  ...props
2454
2916
  }) {
2455
- const inputContainerRef = (0, import_react20.useRef)(null);
2456
- const [inputContainerHeight, setInputContainerHeight] = (0, import_react20.useState)(0);
2457
- const [isResizing, setIsResizing] = (0, import_react20.useState)(false);
2458
- const resizeTimeoutRef = (0, import_react20.useRef)(null);
2459
- (0, import_react20.useEffect)(() => {
2917
+ const inputContainerRef = (0, import_react21.useRef)(null);
2918
+ const [inputContainerHeight, setInputContainerHeight] = (0, import_react21.useState)(0);
2919
+ const [isResizing, setIsResizing] = (0, import_react21.useState)(false);
2920
+ const resizeTimeoutRef = (0, import_react21.useRef)(null);
2921
+ const { isKeyboardOpen, keyboardHeight, availableHeight } = useKeyboardHeight();
2922
+ (0, import_react21.useEffect)(() => {
2460
2923
  const element = inputContainerRef.current;
2461
2924
  if (!element) return;
2462
2925
  const resizeObserver = new ResizeObserver((entries) => {
@@ -2510,15 +2973,16 @@ function CopilotChatView({
2510
2973
  isResizing,
2511
2974
  children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { paddingBottom: `${inputContainerHeight + (hasSuggestions ? 4 : 32)}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "max-w-3xl mx-auto", children: [
2512
2975
  BoundMessageView,
2513
- hasSuggestions ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "px-4 sm:px-0 mt-4", children: BoundSuggestionView }) : null
2976
+ hasSuggestions ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "pl-0 pr-4 sm:px-0 mt-4", children: BoundSuggestionView }) : null
2514
2977
  ] }) })
2515
2978
  });
2516
2979
  const BoundScrollToBottomButton = renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, {});
2517
2980
  const BoundDisclaimer = renderSlot(disclaimer, CopilotChatView.Disclaimer, {});
2518
2981
  const BoundInputContainer = renderSlot(inputContainer, CopilotChatView.InputContainer, {
2519
2982
  ref: inputContainerRef,
2983
+ keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
2520
2984
  children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2521
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "max-w-3xl mx-auto py-0 px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 pointer-events-auto", children: BoundInput }),
2985
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "max-w-3xl mx-auto py-0 px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6 pointer-events-auto", children: BoundInput }),
2522
2986
  BoundDisclaimer
2523
2987
  ] })
2524
2988
  });
@@ -2544,7 +3008,7 @@ function CopilotChatView({
2544
3008
  const ScrollContent = ({ children, scrollToBottomButton, inputContainerHeight, isResizing }) => {
2545
3009
  const { isAtBottom, scrollToBottom } = (0, import_use_stick_to_bottom.useStickToBottomContext)();
2546
3010
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2547
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_use_stick_to_bottom.StickToBottom.Content, { className: "overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8", children }) }),
3011
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_use_stick_to_bottom.StickToBottom.Content, { className: "overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6", children }) }),
2548
3012
  !isAtBottom && !isResizing && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2549
3013
  "div",
2550
3014
  {
@@ -2568,13 +3032,13 @@ function CopilotChatView({
2568
3032
  className,
2569
3033
  ...props
2570
3034
  }) => {
2571
- const [hasMounted, setHasMounted] = (0, import_react20.useState)(false);
3035
+ const [hasMounted, setHasMounted] = (0, import_react21.useState)(false);
2572
3036
  const { scrollRef, contentRef, scrollToBottom } = (0, import_use_stick_to_bottom.useStickToBottom)();
2573
- const [showScrollButton, setShowScrollButton] = (0, import_react20.useState)(false);
2574
- (0, import_react20.useEffect)(() => {
3037
+ const [showScrollButton, setShowScrollButton] = (0, import_react21.useState)(false);
3038
+ (0, import_react21.useEffect)(() => {
2575
3039
  setHasMounted(true);
2576
3040
  }, []);
2577
- (0, import_react20.useEffect)(() => {
3041
+ (0, import_react21.useEffect)(() => {
2578
3042
  if (autoScroll) return;
2579
3043
  const scrollElement = scrollRef.current;
2580
3044
  if (!scrollElement) return;
@@ -2592,7 +3056,7 @@ function CopilotChatView({
2592
3056
  };
2593
3057
  }, [scrollRef, autoScroll]);
2594
3058
  if (!hasMounted) {
2595
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8", children }) });
3059
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6", children }) });
2596
3060
  }
2597
3061
  if (!autoScroll) {
2598
3062
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
@@ -2605,7 +3069,7 @@ function CopilotChatView({
2605
3069
  ),
2606
3070
  ...props,
2607
3071
  children: [
2608
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: contentRef, className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8", children }),
3072
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: contentRef, className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6", children }),
2609
3073
  showScrollButton && !isResizing && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2610
3074
  "div",
2611
3075
  {
@@ -2674,7 +3138,20 @@ function CopilotChatView({
2674
3138
  ...props
2675
3139
  }
2676
3140
  );
2677
- CopilotChatView2.InputContainer = import_react20.default.forwardRef(({ children, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref, className: cn("absolute bottom-0 left-0 right-0 z-20 pointer-events-none", className), ...props, children }));
3141
+ CopilotChatView2.InputContainer = import_react21.default.forwardRef(({ children, className, keyboardHeight = 0, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3142
+ "div",
3143
+ {
3144
+ ref,
3145
+ className: cn("absolute bottom-0 left-0 right-0 z-20 pointer-events-none", className),
3146
+ style: {
3147
+ // Adjust position when keyboard is open to keep input visible
3148
+ transform: keyboardHeight > 0 ? `translateY(-${keyboardHeight}px)` : void 0,
3149
+ transition: "transform 0.2s ease-out"
3150
+ },
3151
+ ...props,
3152
+ children
3153
+ }
3154
+ ));
2678
3155
  CopilotChatView2.InputContainer.displayName = "CopilotChatView.InputContainer";
2679
3156
  CopilotChatView2.Disclaimer = ({ className, ...props }) => {
2680
3157
  const config = useCopilotChatConfiguration();
@@ -2693,14 +3170,14 @@ var CopilotChatView_default = CopilotChatView;
2693
3170
 
2694
3171
  // src/components/chat/CopilotChat.tsx
2695
3172
  var import_shared7 = require("@copilotkitnext/shared");
2696
- var import_react21 = require("react");
3173
+ var import_react22 = require("react");
2697
3174
  var import_ts_deepmerge = require("ts-deepmerge");
2698
3175
  var import_client = require("@ag-ui/client");
2699
3176
  var import_jsx_runtime18 = require("react/jsx-runtime");
2700
3177
  function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, ...props }) {
2701
3178
  const existingConfig = useCopilotChatConfiguration();
2702
3179
  const resolvedAgentId = agentId ?? existingConfig?.agentId ?? import_shared7.DEFAULT_AGENT_ID;
2703
- const resolvedThreadId = (0, import_react21.useMemo)(
3180
+ const resolvedThreadId = (0, import_react22.useMemo)(
2704
3181
  () => threadId ?? existingConfig?.threadId ?? (0, import_shared7.randomUUID)(),
2705
3182
  [threadId, existingConfig?.threadId]
2706
3183
  );
@@ -2713,7 +3190,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
2713
3190
  suggestionView: providedSuggestionView,
2714
3191
  ...restProps
2715
3192
  } = props;
2716
- (0, import_react21.useEffect)(() => {
3193
+ (0, import_react22.useEffect)(() => {
2717
3194
  const connect = async (agent2) => {
2718
3195
  try {
2719
3196
  await copilotkit.connectAgent({ agent: agent2 });
@@ -2731,7 +3208,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
2731
3208
  return () => {
2732
3209
  };
2733
3210
  }, [resolvedThreadId, agent, copilotkit, resolvedAgentId]);
2734
- const onSubmitInput = (0, import_react21.useCallback)(
3211
+ const onSubmitInput = (0, import_react22.useCallback)(
2735
3212
  async (value) => {
2736
3213
  agent?.addMessage({
2737
3214
  id: (0, import_shared7.randomUUID)(),
@@ -2748,7 +3225,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
2748
3225
  },
2749
3226
  [agent, copilotkit]
2750
3227
  );
2751
- const handleSelectSuggestion = (0, import_react21.useCallback)(
3228
+ const handleSelectSuggestion = (0, import_react22.useCallback)(
2752
3229
  async (suggestion) => {
2753
3230
  if (!agent) {
2754
3231
  return;
@@ -2802,7 +3279,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
2802
3279
  })(CopilotChat || (CopilotChat = {}));
2803
3280
 
2804
3281
  // src/components/chat/CopilotChatToggleButton.tsx
2805
- var import_react22 = __toESM(require("react"));
3282
+ var import_react23 = __toESM(require("react"));
2806
3283
  var import_lucide_react7 = require("lucide-react");
2807
3284
  var import_jsx_runtime19 = require("react/jsx-runtime");
2808
3285
  var DefaultOpenIcon = ({
@@ -2829,11 +3306,11 @@ var BUTTON_BASE_CLASSES = cn(
2829
3306
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2830
3307
  "disabled:pointer-events-none disabled:opacity-60"
2831
3308
  );
2832
- var CopilotChatToggleButton = import_react22.default.forwardRef(function CopilotChatToggleButton2({ openIcon, closeIcon, className, ...buttonProps }, ref) {
3309
+ var CopilotChatToggleButton = import_react23.default.forwardRef(function CopilotChatToggleButton2({ openIcon, closeIcon, className, ...buttonProps }, ref) {
2833
3310
  const { onClick, type, disabled, ...restProps } = buttonProps;
2834
3311
  const configuration = useCopilotChatConfiguration();
2835
3312
  const labels = configuration?.labels ?? CopilotChatDefaultLabels;
2836
- const [fallbackOpen, setFallbackOpen] = (0, import_react22.useState)(false);
3313
+ const [fallbackOpen, setFallbackOpen] = (0, import_react23.useState)(false);
2837
3314
  const isOpen = configuration?.isModalOpen ?? fallbackOpen;
2838
3315
  const setModalOpen = configuration?.setModalOpen ?? setFallbackOpen;
2839
3316
  const handleClick = (event) => {
@@ -2919,10 +3396,10 @@ CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
2919
3396
  var CopilotChatToggleButton_default = CopilotChatToggleButton;
2920
3397
 
2921
3398
  // src/components/chat/CopilotSidebarView.tsx
2922
- var import_react24 = require("react");
3399
+ var import_react25 = require("react");
2923
3400
 
2924
3401
  // src/components/chat/CopilotModalHeader.tsx
2925
- var import_react23 = require("react");
3402
+ var import_react24 = require("react");
2926
3403
  var import_lucide_react8 = require("lucide-react");
2927
3404
  var import_jsx_runtime20 = require("react/jsx-runtime");
2928
3405
  function CopilotModalHeader({
@@ -2936,7 +3413,7 @@ function CopilotModalHeader({
2936
3413
  const configuration = useCopilotChatConfiguration();
2937
3414
  const fallbackTitle = configuration?.labels.modalHeaderTitle ?? CopilotChatDefaultLabels.modalHeaderTitle;
2938
3415
  const resolvedTitle = title ?? fallbackTitle;
2939
- const handleClose = (0, import_react23.useCallback)(() => {
3416
+ const handleClose = (0, import_react24.useCallback)(() => {
2940
3417
  configuration?.setModalOpen(false);
2941
3418
  }, [configuration]);
2942
3419
  const BoundTitle = renderSlot(titleContent, CopilotModalHeader.Title, {
@@ -3012,8 +3489,8 @@ var SIDEBAR_TRANSITION_MS = 260;
3012
3489
  function CopilotSidebarView({ header, width, ...props }) {
3013
3490
  const configuration = useCopilotChatConfiguration();
3014
3491
  const isSidebarOpen = configuration?.isModalOpen ?? false;
3015
- const sidebarRef = (0, import_react24.useRef)(null);
3016
- const [sidebarWidth, setSidebarWidth] = (0, import_react24.useState)(width ?? DEFAULT_SIDEBAR_WIDTH);
3492
+ const sidebarRef = (0, import_react25.useRef)(null);
3493
+ const [sidebarWidth, setSidebarWidth] = (0, import_react25.useState)(width ?? DEFAULT_SIDEBAR_WIDTH);
3017
3494
  const widthToCss = (w) => {
3018
3495
  return typeof w === "number" ? `${w}px` : w;
3019
3496
  };
@@ -3023,7 +3500,7 @@ function CopilotSidebarView({ header, width, ...props }) {
3023
3500
  }
3024
3501
  return w;
3025
3502
  };
3026
- (0, import_react24.useEffect)(() => {
3503
+ (0, import_react25.useEffect)(() => {
3027
3504
  if (width !== void 0) {
3028
3505
  return;
3029
3506
  }
@@ -3055,10 +3532,13 @@ function CopilotSidebarView({ header, width, ...props }) {
3055
3532
  "style",
3056
3533
  {
3057
3534
  dangerouslySetInnerHTML: {
3058
- __html: `body {
3059
- margin-inline-end: ${widthToMargin(sidebarWidth)};
3060
- transition: margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease;
3061
- }`
3535
+ __html: `
3536
+ @media (min-width: 768px) {
3537
+ body {
3538
+ margin-inline-end: ${widthToMargin(sidebarWidth)};
3539
+ transition: margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease;
3540
+ }
3541
+ }`
3062
3542
  }
3063
3543
  }
3064
3544
  ),
@@ -3069,12 +3549,22 @@ function CopilotSidebarView({ header, width, ...props }) {
3069
3549
  ref: sidebarRef,
3070
3550
  "data-copilot-sidebar": true,
3071
3551
  className: cn(
3072
- "fixed right-0 top-0 z-[1200] flex h-dvh max-h-screen",
3552
+ "fixed right-0 top-0 z-[1200] flex",
3553
+ // Height with dvh fallback and safe area support
3554
+ "h-[100vh] h-[100dvh] max-h-screen",
3555
+ // Responsive width: full on mobile, custom on desktop
3556
+ "w-full",
3073
3557
  "border-l border-border bg-background text-foreground shadow-xl",
3074
3558
  "transition-transform duration-300 ease-out",
3075
3559
  isSidebarOpen ? "translate-x-0" : "translate-x-full pointer-events-none"
3076
3560
  ),
3077
- style: { width: widthToCss(sidebarWidth) },
3561
+ style: {
3562
+ // Use CSS custom property for responsive width
3563
+ ["--sidebar-width"]: widthToCss(sidebarWidth),
3564
+ // Safe area insets for iOS
3565
+ paddingTop: "env(safe-area-inset-top)",
3566
+ paddingBottom: "env(safe-area-inset-bottom)"
3567
+ },
3078
3568
  "aria-hidden": !isSidebarOpen,
3079
3569
  "aria-label": "Copilot chat sidebar",
3080
3570
  role: "complementary",
@@ -3088,14 +3578,173 @@ function CopilotSidebarView({ header, width, ...props }) {
3088
3578
  }
3089
3579
  CopilotSidebarView.displayName = "CopilotSidebarView";
3090
3580
 
3091
- // src/components/chat/CopilotSidebar.tsx
3092
- var import_react25 = require("react");
3581
+ // src/components/chat/CopilotPopupView.tsx
3582
+ var import_react26 = require("react");
3093
3583
  var import_jsx_runtime22 = require("react/jsx-runtime");
3584
+ var DEFAULT_POPUP_WIDTH = 420;
3585
+ var DEFAULT_POPUP_HEIGHT = 560;
3586
+ var dimensionToCss = (value, fallback) => {
3587
+ if (typeof value === "number" && Number.isFinite(value)) {
3588
+ return `${value}px`;
3589
+ }
3590
+ if (typeof value === "string" && value.trim().length > 0) {
3591
+ return value;
3592
+ }
3593
+ return `${fallback}px`;
3594
+ };
3595
+ function CopilotPopupView({
3596
+ header,
3597
+ width,
3598
+ height,
3599
+ clickOutsideToClose,
3600
+ className,
3601
+ ...restProps
3602
+ }) {
3603
+ const configuration = useCopilotChatConfiguration();
3604
+ const isPopupOpen = configuration?.isModalOpen ?? false;
3605
+ const setModalOpen = configuration?.setModalOpen;
3606
+ const labels = configuration?.labels ?? CopilotChatDefaultLabels;
3607
+ const containerRef = (0, import_react26.useRef)(null);
3608
+ const [isRendered, setIsRendered] = (0, import_react26.useState)(isPopupOpen);
3609
+ const [isAnimatingOut, setIsAnimatingOut] = (0, import_react26.useState)(false);
3610
+ (0, import_react26.useEffect)(() => {
3611
+ if (isPopupOpen) {
3612
+ setIsRendered(true);
3613
+ setIsAnimatingOut(false);
3614
+ return;
3615
+ }
3616
+ if (!isRendered) {
3617
+ return;
3618
+ }
3619
+ setIsAnimatingOut(true);
3620
+ const timeout = setTimeout(() => {
3621
+ setIsRendered(false);
3622
+ setIsAnimatingOut(false);
3623
+ }, 200);
3624
+ return () => clearTimeout(timeout);
3625
+ }, [isPopupOpen, isRendered]);
3626
+ (0, import_react26.useEffect)(() => {
3627
+ if (!isPopupOpen) {
3628
+ return;
3629
+ }
3630
+ if (typeof window === "undefined") {
3631
+ return;
3632
+ }
3633
+ const handleKeyDown = (event) => {
3634
+ if (event.key === "Escape") {
3635
+ event.preventDefault();
3636
+ setModalOpen?.(false);
3637
+ }
3638
+ };
3639
+ window.addEventListener("keydown", handleKeyDown);
3640
+ return () => window.removeEventListener("keydown", handleKeyDown);
3641
+ }, [isPopupOpen, setModalOpen]);
3642
+ (0, import_react26.useEffect)(() => {
3643
+ if (!isPopupOpen) {
3644
+ return;
3645
+ }
3646
+ const focusTimer = setTimeout(() => {
3647
+ containerRef.current?.focus({ preventScroll: true });
3648
+ }, 200);
3649
+ return () => clearTimeout(focusTimer);
3650
+ }, [isPopupOpen]);
3651
+ (0, import_react26.useEffect)(() => {
3652
+ if (!isPopupOpen || !clickOutsideToClose) {
3653
+ return;
3654
+ }
3655
+ if (typeof document === "undefined") {
3656
+ return;
3657
+ }
3658
+ const handlePointerDown = (event) => {
3659
+ const target = event.target;
3660
+ if (!target) {
3661
+ return;
3662
+ }
3663
+ const container = containerRef.current;
3664
+ if (container?.contains(target)) {
3665
+ return;
3666
+ }
3667
+ const toggleButton = document.querySelector("[data-slot='chat-toggle-button']");
3668
+ if (toggleButton && toggleButton.contains(target)) {
3669
+ return;
3670
+ }
3671
+ setModalOpen?.(false);
3672
+ };
3673
+ document.addEventListener("pointerdown", handlePointerDown);
3674
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
3675
+ }, [isPopupOpen, clickOutsideToClose, setModalOpen]);
3676
+ const headerElement = (0, import_react26.useMemo)(() => renderSlot(header, CopilotModalHeader, {}), [header]);
3677
+ const resolvedWidth = dimensionToCss(width, DEFAULT_POPUP_WIDTH);
3678
+ const resolvedHeight = dimensionToCss(height, DEFAULT_POPUP_HEIGHT);
3679
+ const popupStyle = (0, import_react26.useMemo)(
3680
+ () => ({
3681
+ "--copilot-popup-width": resolvedWidth,
3682
+ "--copilot-popup-height": resolvedHeight,
3683
+ "--copilot-popup-max-width": "calc(100vw - 3rem)",
3684
+ "--copilot-popup-max-height": "calc(100dvh - 7.5rem)",
3685
+ paddingTop: "env(safe-area-inset-top)",
3686
+ paddingBottom: "env(safe-area-inset-bottom)",
3687
+ paddingLeft: "env(safe-area-inset-left)",
3688
+ paddingRight: "env(safe-area-inset-right)"
3689
+ }),
3690
+ [resolvedHeight, resolvedWidth]
3691
+ );
3692
+ const popupAnimationClass = isPopupOpen && !isAnimatingOut ? "pointer-events-auto translate-y-0 opacity-100 md:scale-100" : "pointer-events-none translate-y-4 opacity-0 md:translate-y-5 md:scale-[0.95]";
3693
+ const popupContent = isRendered ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3694
+ "div",
3695
+ {
3696
+ className: cn(
3697
+ "fixed inset-0 z-[1200] flex max-w-full flex-col items-stretch",
3698
+ "md:inset-auto md:bottom-24 md:right-6 md:items-end md:gap-4"
3699
+ ),
3700
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3701
+ "div",
3702
+ {
3703
+ ref: containerRef,
3704
+ tabIndex: -1,
3705
+ role: "dialog",
3706
+ "aria-label": labels.modalHeaderTitle,
3707
+ "data-copilot-popup": true,
3708
+ className: cn(
3709
+ "relative flex h-full w-full flex-col overflow-hidden bg-background text-foreground",
3710
+ "origin-bottom focus:outline-none transform-gpu transition-transform transition-opacity duration-200 ease-out",
3711
+ "md:transition-transform md:transition-opacity",
3712
+ "rounded-none border border-border/0 shadow-none ring-0",
3713
+ "md:h-[var(--copilot-popup-height)] md:w-[var(--copilot-popup-width)]",
3714
+ "md:max-h-[var(--copilot-popup-max-height)] md:max-w-[var(--copilot-popup-max-width)]",
3715
+ "md:origin-bottom-right md:rounded-2xl md:border-border md:shadow-xl md:ring-1 md:ring-border/40",
3716
+ popupAnimationClass
3717
+ ),
3718
+ style: popupStyle,
3719
+ children: [
3720
+ headerElement,
3721
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1 overflow-hidden", "data-popup-chat": true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3722
+ CopilotChatView_default,
3723
+ {
3724
+ ...restProps,
3725
+ className: cn("h-full min-h-0", className)
3726
+ }
3727
+ ) })
3728
+ ]
3729
+ }
3730
+ )
3731
+ }
3732
+ ) : null;
3733
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3734
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CopilotChatToggleButton_default, {}),
3735
+ popupContent
3736
+ ] });
3737
+ }
3738
+ CopilotPopupView.displayName = "CopilotPopupView";
3739
+
3740
+ // src/components/chat/CopilotSidebar.tsx
3741
+ var import_react27 = require("react");
3742
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3094
3743
  function CopilotSidebar({ header, defaultOpen, width, ...chatProps }) {
3095
- const SidebarViewOverride = (0, import_react25.useMemo)(() => {
3744
+ const SidebarViewOverride = (0, import_react27.useMemo)(() => {
3096
3745
  const Component = (viewProps) => {
3097
3746
  const { header: viewHeader, width: viewWidth, ...restProps } = viewProps;
3098
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3747
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3099
3748
  CopilotSidebarView,
3100
3749
  {
3101
3750
  ...restProps,
@@ -3106,7 +3755,7 @@ function CopilotSidebar({ header, defaultOpen, width, ...chatProps }) {
3106
3755
  };
3107
3756
  return Object.assign(Component, CopilotChatView_default);
3108
3757
  }, [header, width]);
3109
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3758
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3110
3759
  CopilotChat,
3111
3760
  {
3112
3761
  ...chatProps,
@@ -3117,6 +3766,50 @@ function CopilotSidebar({ header, defaultOpen, width, ...chatProps }) {
3117
3766
  }
3118
3767
  CopilotSidebar.displayName = "CopilotSidebar";
3119
3768
 
3769
+ // src/components/chat/CopilotPopup.tsx
3770
+ var import_react28 = require("react");
3771
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3772
+ function CopilotPopup({
3773
+ header,
3774
+ defaultOpen,
3775
+ width,
3776
+ height,
3777
+ clickOutsideToClose,
3778
+ ...chatProps
3779
+ }) {
3780
+ const PopupViewOverride = (0, import_react28.useMemo)(() => {
3781
+ const Component = (viewProps) => {
3782
+ const {
3783
+ header: viewHeader,
3784
+ width: viewWidth,
3785
+ height: viewHeight,
3786
+ clickOutsideToClose: viewClickOutsideToClose,
3787
+ ...restProps
3788
+ } = viewProps;
3789
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3790
+ CopilotPopupView,
3791
+ {
3792
+ ...restProps,
3793
+ header: header ?? viewHeader,
3794
+ width: width ?? viewWidth,
3795
+ height: height ?? viewHeight,
3796
+ clickOutsideToClose: clickOutsideToClose ?? viewClickOutsideToClose
3797
+ }
3798
+ );
3799
+ };
3800
+ return Object.assign(Component, CopilotChatView_default);
3801
+ }, [clickOutsideToClose, header, height, width]);
3802
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3803
+ CopilotChat,
3804
+ {
3805
+ ...chatProps,
3806
+ chatView: PopupViewOverride,
3807
+ isModalDefaultOpen: defaultOpen
3808
+ }
3809
+ );
3810
+ }
3811
+ CopilotPopup.displayName = "CopilotPopup";
3812
+
3120
3813
  // src/types/defineToolCallRenderer.ts
3121
3814
  var import_zod2 = require("zod");
3122
3815
  function defineToolCallRenderer(def) {
@@ -3130,25 +3823,25 @@ function defineToolCallRenderer(def) {
3130
3823
  }
3131
3824
 
3132
3825
  // src/components/WildcardToolCallRender.tsx
3133
- var import_react26 = require("react");
3134
- var import_jsx_runtime23 = require("react/jsx-runtime");
3826
+ var import_react29 = require("react");
3827
+ var import_jsx_runtime25 = require("react/jsx-runtime");
3135
3828
  var WildcardToolCallRender = defineToolCallRenderer({
3136
3829
  name: "*",
3137
3830
  render: ({ args, result, name, status }) => {
3138
- const [isExpanded, setIsExpanded] = (0, import_react26.useState)(false);
3831
+ const [isExpanded, setIsExpanded] = (0, import_react29.useState)(false);
3139
3832
  const statusString = String(status);
3140
3833
  const isActive = statusString === "inProgress" || statusString === "executing";
3141
3834
  const isComplete = statusString === "complete";
3142
3835
  const statusStyles = isActive ? "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-400" : isComplete ? "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-400" : "bg-zinc-100 text-zinc-800 dark:bg-zinc-700/40 dark:text-zinc-300";
3143
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-2 pb-2", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "rounded-xl border border-zinc-200/60 dark:border-zinc-800/60 bg-white/70 dark:bg-zinc-900/50 shadow-sm backdrop-blur p-4", children: [
3144
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3836
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-2 pb-2", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "rounded-xl border border-zinc-200/60 dark:border-zinc-800/60 bg-white/70 dark:bg-zinc-900/50 shadow-sm backdrop-blur p-4", children: [
3837
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3145
3838
  "div",
3146
3839
  {
3147
3840
  className: "flex items-center justify-between gap-3 cursor-pointer",
3148
3841
  onClick: () => setIsExpanded(!isExpanded),
3149
3842
  children: [
3150
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
3151
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3843
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
3844
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3152
3845
  "svg",
3153
3846
  {
3154
3847
  className: `h-4 w-4 text-zinc-500 dark:text-zinc-400 transition-transform ${isExpanded ? "rotate-90" : ""}`,
@@ -3156,7 +3849,7 @@ var WildcardToolCallRender = defineToolCallRenderer({
3156
3849
  viewBox: "0 0 24 24",
3157
3850
  strokeWidth: 2,
3158
3851
  stroke: "currentColor",
3159
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3852
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3160
3853
  "path",
3161
3854
  {
3162
3855
  strokeLinecap: "round",
@@ -3166,10 +3859,10 @@ var WildcardToolCallRender = defineToolCallRenderer({
3166
3859
  )
3167
3860
  }
3168
3861
  ),
3169
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-blue-500" }),
3170
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "truncate text-sm font-medium text-zinc-900 dark:text-zinc-100", children: name })
3862
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-blue-500" }),
3863
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate text-sm font-medium text-zinc-900 dark:text-zinc-100", children: name })
3171
3864
  ] }),
3172
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3865
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3173
3866
  "span",
3174
3867
  {
3175
3868
  className: `inline-flex items-center rounded-full px-2 py-1 text-xs font-medium ${statusStyles}`,
@@ -3179,14 +3872,14 @@ var WildcardToolCallRender = defineToolCallRenderer({
3179
3872
  ]
3180
3873
  }
3181
3874
  ),
3182
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "mt-3 grid gap-4", children: [
3183
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
3184
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Arguments" }),
3185
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: JSON.stringify(args ?? {}, null, 2) })
3875
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "mt-3 grid gap-4", children: [
3876
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
3877
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Arguments" }),
3878
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: JSON.stringify(args ?? {}, null, 2) })
3186
3879
  ] }),
3187
- result !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
3188
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Result" }),
3189
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
3880
+ result !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
3881
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Result" }),
3882
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
3190
3883
  ] })
3191
3884
  ] })
3192
3885
  ] }) });
@@ -3213,6 +3906,8 @@ var WildcardToolCallRender = defineToolCallRenderer({
3213
3906
  CopilotKitInspector,
3214
3907
  CopilotKitProvider,
3215
3908
  CopilotModalHeader,
3909
+ CopilotPopup,
3910
+ CopilotPopupView,
3216
3911
  CopilotSidebar,
3217
3912
  CopilotSidebarView,
3218
3913
  WildcardToolCallRender,