rdesign/frontend/node_modules/@copilotkitnext/react/dist/components/chat/CopilotChatView.mjs

291 lines
12 KiB
JavaScript

import { CopilotChatDefaultLabels, useCopilotChatConfiguration } from "../../providers/CopilotChatConfigurationProvider.mjs";
import { cn } from "../../lib/utils.mjs";
import { Button } from "../ui/button.mjs";
import { renderSlot } from "../../lib/slots.mjs";
import CopilotChatInput_default from "./CopilotChatInput.mjs";
import CopilotChatSuggestionView from "./CopilotChatSuggestionView.mjs";
import CopilotChatMessageView from "./CopilotChatMessageView.mjs";
import { useKeyboardHeight } from "../../hooks/use-keyboard-height.mjs";
import React, { useEffect, useRef, useState } from "react";
import { twMerge } from "tailwind-merge";
import { ChevronDown } from "lucide-react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { StickToBottom, useStickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
//#region src/components/chat/CopilotChatView.tsx
const FEATHER_HEIGHT = 96;
function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, disclaimer, children, className, ...props }) {
const inputContainerRef = useRef(null);
const [inputContainerHeight, setInputContainerHeight] = useState(0);
const [isResizing, setIsResizing] = useState(false);
const resizeTimeoutRef = useRef(null);
const { isKeyboardOpen, keyboardHeight, availableHeight } = useKeyboardHeight();
useEffect(() => {
const element = inputContainerRef.current;
if (!element) return;
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const newHeight = entry.contentRect.height;
setInputContainerHeight((prevHeight) => {
if (newHeight !== prevHeight) {
setIsResizing(true);
if (resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current);
resizeTimeoutRef.current = setTimeout(() => {
setIsResizing(false);
}, 250);
return newHeight;
}
return prevHeight;
});
}
});
resizeObserver.observe(element);
setInputContainerHeight(element.offsetHeight);
return () => {
resizeObserver.disconnect();
if (resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current);
};
}, []);
const BoundMessageView = renderSlot(messageView, CopilotChatMessageView, {
messages,
isRunning
});
const BoundInput = renderSlot(input, CopilotChatInput_default, {
onSubmitMessage,
onStop,
mode: inputMode,
value: inputValue,
onChange: onInputChange,
isRunning,
onStartTranscribe,
onCancelTranscribe,
onFinishTranscribe,
onFinishTranscribeWithAudio,
positioning: "absolute",
keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
containerRef: inputContainerRef,
showDisclaimer: true,
...disclaimer !== void 0 ? { disclaimer } : {}
});
const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
const BoundSuggestionView = hasSuggestions ? renderSlot(suggestionView, CopilotChatSuggestionView, {
suggestions,
loadingIndexes: suggestionLoadingIndexes,
onSelectSuggestion,
className: "cpk:mb-3 cpk:lg:ml-4 cpk:lg:mr-4 cpk:ml-0 cpk:mr-0"
}) : null;
const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
autoScroll,
inputContainerHeight,
isResizing,
children: /* @__PURE__ */ jsx("div", {
style: { paddingBottom: `${inputContainerHeight + FEATHER_HEIGHT + (hasSuggestions ? 4 : 32)}px` },
children: /* @__PURE__ */ jsxs("div", {
className: "cpk:max-w-3xl cpk:mx-auto",
children: [BoundMessageView, hasSuggestions ? /* @__PURE__ */ jsx("div", {
className: "cpk:pl-0 cpk:pr-4 cpk:sm:px-0 cpk:mt-4",
children: BoundSuggestionView
}) : null]
})
})
});
if (messages.length === 0 && !(welcomeScreen === false)) {
const BoundInputForWelcome = renderSlot(input, CopilotChatInput_default, {
onSubmitMessage,
onStop,
mode: inputMode,
value: inputValue,
onChange: onInputChange,
isRunning,
onStartTranscribe,
onCancelTranscribe,
onFinishTranscribe,
onFinishTranscribeWithAudio,
positioning: "static",
showDisclaimer: true,
...disclaimer !== void 0 ? { disclaimer } : {}
});
const BoundWelcomeScreen = renderSlot(welcomeScreen === true ? void 0 : welcomeScreen, CopilotChatView.WelcomeScreen, {
input: BoundInputForWelcome,
suggestionView: BoundSuggestionView ?? /* @__PURE__ */ jsx(Fragment, {})
});
return /* @__PURE__ */ jsx("div", {
"data-copilotkit": true,
"data-testid": "copilot-chat",
"data-copilot-running": isRunning ? "true" : "false",
className: twMerge("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
...props,
children: BoundWelcomeScreen
});
}
if (children) return /* @__PURE__ */ jsx("div", {
"data-copilotkit": true,
style: { display: "contents" },
children: children({
messageView: BoundMessageView,
input: BoundInput,
scrollView: BoundScrollView,
suggestionView: BoundSuggestionView ?? /* @__PURE__ */ jsx(Fragment, {})
})
});
return /* @__PURE__ */ jsxs("div", {
"data-copilotkit": true,
"data-testid": "copilot-chat",
"data-copilot-running": isRunning ? "true" : "false",
className: twMerge("copilotKitChat cpk:relative cpk:h-full", className),
...props,
children: [BoundScrollView, BoundInput]
});
}
(function(_CopilotChatView) {
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(StickToBottom.Content, {
className: "cpk:overflow-y-scroll cpk:overflow-x-hidden",
style: {
flex: "1 1 0%",
minHeight: 0
},
children: /* @__PURE__ */ jsx("div", {
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
children
})
}),
BoundFeather,
!isAtBottom && !isResizing && /* @__PURE__ */ jsx("div", {
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
})
] });
};
_CopilotChatView.ScrollView = ({ children, autoScroll = true, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
const [hasMounted, setHasMounted] = useState(false);
const { scrollRef, contentRef, scrollToBottom } = useStickToBottom();
const [showScrollButton, setShowScrollButton] = useState(false);
useEffect(() => {
setHasMounted(true);
}, []);
useEffect(() => {
if (autoScroll) return;
const scrollElement = scrollRef.current;
if (!scrollElement) return;
const checkScroll = () => {
setShowScrollButton(!(scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight < 10));
};
checkScroll();
scrollElement.addEventListener("scroll", checkScroll);
const resizeObserver = new ResizeObserver(checkScroll);
resizeObserver.observe(scrollElement);
return () => {
scrollElement.removeEventListener("scroll", checkScroll);
resizeObserver.disconnect();
};
}, [scrollRef, autoScroll]);
if (!hasMounted) return /* @__PURE__ */ jsx("div", {
className: "cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-scroll cpk:overflow-x-hidden",
children: /* @__PURE__ */ jsx("div", {
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
children
})
});
if (!autoScroll) {
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
return /* @__PURE__ */ jsxs("div", {
ref: scrollRef,
className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-scroll cpk:overflow-x-hidden cpk:relative", className),
...props,
children: [
/* @__PURE__ */ jsx("div", {
ref: contentRef,
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
children
}),
BoundFeather,
showScrollButton && !isResizing && /* @__PURE__ */ jsx("div", {
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
})
]
});
}
return /* @__PURE__ */ jsx(StickToBottom, {
className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:relative", className),
resize: "smooth",
initial: "smooth",
...props,
children: /* @__PURE__ */ jsx(ScrollContent, {
scrollToBottomButton,
feather,
inputContainerHeight,
isResizing,
children
})
});
};
_CopilotChatView.ScrollToBottomButton = ({ className, ...props }) => /* @__PURE__ */ jsx(Button, {
"data-testid": "copilot-scroll-to-bottom",
variant: "outline",
size: "sm",
className: twMerge("cpk:rounded-full cpk:w-10 cpk:h-10 cpk:p-0 cpk:pointer-events-auto", "cpk:bg-white cpk:dark:bg-gray-900", "cpk:shadow-lg cpk:border cpk:border-gray-200 cpk:dark:border-gray-700", "cpk:hover:bg-gray-50 cpk:dark:hover:bg-gray-800", "cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer", className),
...props,
children: /* @__PURE__ */ jsx(ChevronDown, { className: "cpk:w-4 cpk:h-4 cpk:text-gray-600 cpk:dark:text-white" })
});
_CopilotChatView.Feather = ({ className, style, ...props }) => /* @__PURE__ */ jsx("div", {
className: cn("cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-4 cpk:h-24 cpk:pointer-events-none cpk:z-10 cpk:bg-gradient-to-t", "cpk:from-white cpk:via-white cpk:to-transparent", "cpk:dark:from-[rgb(33,33,33)] cpk:dark:via-[rgb(33,33,33)]", className),
style,
...props
});
_CopilotChatView.WelcomeMessage = ({ className, ...props }) => {
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
return /* @__PURE__ */ jsx("h1", {
className: cn("cpk:text-xl cpk:sm:text-2xl cpk:font-medium cpk:text-foreground cpk:text-center", className),
...props,
children: labels.welcomeMessageText
});
};
_CopilotChatView.WelcomeScreen = ({ welcomeMessage, input, suggestionView, className, children, ...props }) => {
const BoundWelcomeMessage = renderSlot(welcomeMessage, CopilotChatView.WelcomeMessage, {});
if (children) return /* @__PURE__ */ jsx("div", {
"data-copilotkit": true,
style: { display: "contents" },
children: children({
welcomeMessage: BoundWelcomeMessage,
input,
suggestionView,
className,
...props
})
});
return /* @__PURE__ */ jsx("div", {
"data-testid": "copilot-welcome-screen",
className: cn("cpk:flex-1 cpk:flex cpk:flex-col cpk:items-center cpk:justify-center cpk:px-4", className),
...props,
children: /* @__PURE__ */ jsxs("div", {
className: "cpk:w-full cpk:max-w-3xl cpk:flex cpk:flex-col cpk:items-center",
children: [
/* @__PURE__ */ jsx("div", {
className: "cpk:mb-6",
children: BoundWelcomeMessage
}),
/* @__PURE__ */ jsx("div", {
className: "cpk:w-full",
children: input
}),
/* @__PURE__ */ jsx("div", {
className: "cpk:mt-4 cpk:flex cpk:justify-center",
children: suggestionView
})
]
})
});
};
})(CopilotChatView || (CopilotChatView = {}));
var CopilotChatView_default = CopilotChatView;
//#endregion
export { CopilotChatView, CopilotChatView_default as default };
//# sourceMappingURL=CopilotChatView.mjs.map