162 lines
7.3 KiB
JavaScript
162 lines
7.3 KiB
JavaScript
import { CopilotChatConfigurationProvider, CopilotChatDefaultLabels, useCopilotChatConfiguration } from "../../providers/CopilotChatConfigurationProvider.mjs";
|
|
import { cn } from "../../lib/utils.mjs";
|
|
import { renderSlot } from "../../lib/slots.mjs";
|
|
import CopilotChatView_default from "./CopilotChatView.mjs";
|
|
import CopilotChatToggleButton from "./CopilotChatToggleButton.mjs";
|
|
import { CopilotModalHeader } from "./CopilotModalHeader.mjs";
|
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
|
//#region src/components/chat/CopilotPopupView.tsx
|
|
const DEFAULT_POPUP_WIDTH = 420;
|
|
const DEFAULT_POPUP_HEIGHT = 560;
|
|
const dimensionToCss = (value, fallback) => {
|
|
if (typeof value === "number" && Number.isFinite(value)) return `${value}px`;
|
|
if (typeof value === "string" && value.trim().length > 0) return value;
|
|
return `${fallback}px`;
|
|
};
|
|
function CopilotPopupView({ header, toggleButton, width, height, clickOutsideToClose, defaultOpen = true, className, ...restProps }) {
|
|
return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
|
|
isModalDefaultOpen: defaultOpen,
|
|
children: /* @__PURE__ */ jsx(CopilotPopupViewInternal, {
|
|
header,
|
|
toggleButton,
|
|
width,
|
|
height,
|
|
clickOutsideToClose,
|
|
className,
|
|
...restProps
|
|
})
|
|
});
|
|
}
|
|
function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOutsideToClose, className, ...restProps }) {
|
|
const configuration = useCopilotChatConfiguration();
|
|
const isPopupOpen = configuration?.isModalOpen ?? false;
|
|
const setModalOpen = configuration?.setModalOpen;
|
|
const labels = configuration?.labels ?? CopilotChatDefaultLabels;
|
|
const containerRef = useRef(null);
|
|
const [isRendered, setIsRendered] = useState(isPopupOpen);
|
|
const [isAnimatingOut, setIsAnimatingOut] = useState(false);
|
|
useEffect(() => {
|
|
if (isPopupOpen) {
|
|
setIsRendered(true);
|
|
setIsAnimatingOut(false);
|
|
return;
|
|
}
|
|
if (!isRendered) return;
|
|
setIsAnimatingOut(true);
|
|
const timeout = setTimeout(() => {
|
|
setIsRendered(false);
|
|
setIsAnimatingOut(false);
|
|
}, 200);
|
|
return () => clearTimeout(timeout);
|
|
}, [isPopupOpen, isRendered]);
|
|
useEffect(() => {
|
|
if (!isPopupOpen) return;
|
|
if (typeof window === "undefined") return;
|
|
const handleKeyDown = (event) => {
|
|
if (event.key === "Escape") {
|
|
event.preventDefault();
|
|
setModalOpen?.(false);
|
|
}
|
|
};
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
}, [isPopupOpen, setModalOpen]);
|
|
useEffect(() => {
|
|
if (!isPopupOpen) return;
|
|
const focusTimer = setTimeout(() => {
|
|
const container = containerRef.current;
|
|
if (container && !container.contains(document.activeElement)) container.focus({ preventScroll: true });
|
|
}, 200);
|
|
return () => clearTimeout(focusTimer);
|
|
}, [isPopupOpen]);
|
|
useEffect(() => {
|
|
if (!isPopupOpen || !clickOutsideToClose) return;
|
|
if (typeof document === "undefined") return;
|
|
const handlePointerDown = (event) => {
|
|
const target = event.target;
|
|
if (!target) return;
|
|
if (containerRef.current?.contains(target)) return;
|
|
const toggleButton = document.querySelector("[data-slot='chat-toggle-button']");
|
|
if (toggleButton && toggleButton.contains(target)) return;
|
|
setModalOpen?.(false);
|
|
};
|
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
}, [
|
|
isPopupOpen,
|
|
clickOutsideToClose,
|
|
setModalOpen
|
|
]);
|
|
const headerElement = useMemo(() => renderSlot(header, CopilotModalHeader, {}), [header]);
|
|
const toggleButtonElement = useMemo(() => renderSlot(toggleButton, CopilotChatToggleButton, {}), [toggleButton]);
|
|
const resolvedWidth = dimensionToCss(width, DEFAULT_POPUP_WIDTH);
|
|
const resolvedHeight = dimensionToCss(height, DEFAULT_POPUP_HEIGHT);
|
|
const popupStyle = useMemo(() => ({
|
|
"--copilot-popup-width": resolvedWidth,
|
|
"--copilot-popup-height": resolvedHeight,
|
|
"--copilot-popup-max-width": "calc(100vw - 3rem)",
|
|
"--copilot-popup-max-height": "calc(100dvh - 7.5rem)",
|
|
paddingTop: "env(safe-area-inset-top)",
|
|
paddingBottom: "env(safe-area-inset-bottom)",
|
|
paddingLeft: "env(safe-area-inset-left)",
|
|
paddingRight: "env(safe-area-inset-right)"
|
|
}), [resolvedHeight, resolvedWidth]);
|
|
const popupAnimationClass = isPopupOpen && !isAnimatingOut ? "cpk:pointer-events-auto cpk:translate-y-0 cpk:opacity-100 cpk:md:scale-100" : "cpk:pointer-events-none cpk:translate-y-4 cpk:opacity-0 cpk:md:translate-y-5 cpk:md:scale-[0.95]";
|
|
return /* @__PURE__ */ jsxs(Fragment, { children: [toggleButtonElement, isRendered ? /* @__PURE__ */ jsx("div", {
|
|
"data-copilotkit": true,
|
|
className: cn("cpk:fixed cpk:inset-0 cpk:z-[1200] cpk:flex cpk:max-w-full cpk:flex-col cpk:items-stretch", "cpk:md:inset-auto cpk:md:bottom-24 cpk:md:right-6 cpk:md:items-end cpk:md:gap-4"),
|
|
children: /* @__PURE__ */ jsxs("div", {
|
|
ref: containerRef,
|
|
tabIndex: -1,
|
|
role: "dialog",
|
|
"aria-label": labels.modalHeaderTitle,
|
|
"data-testid": "copilot-popup",
|
|
"data-copilot-popup": true,
|
|
className: cn("copilotKitPopup copilotKitWindow", "cpk:relative cpk:flex cpk:h-full cpk:w-full cpk:flex-col cpk:overflow-hidden cpk:bg-background cpk:text-foreground", "cpk:origin-bottom cpk:focus:outline-none cpk:transform-gpu cpk:transition-transform cpk:transition-opacity cpk:duration-200 cpk:ease-out", "cpk:md:transition-transform cpk:md:transition-opacity", "cpk:rounded-none cpk:border cpk:border-border/0 cpk:shadow-none cpk:ring-0", "cpk:md:h-[var(--copilot-popup-height)] cpk:md:w-[var(--copilot-popup-width)]", "cpk:md:max-h-[var(--copilot-popup-max-height)] cpk:md:max-w-[var(--copilot-popup-max-width)]", "cpk:md:origin-bottom-right cpk:md:rounded-2xl cpk:md:border-border cpk:md:shadow-xl cpk:md:ring-1 cpk:md:ring-border/40", popupAnimationClass),
|
|
style: popupStyle,
|
|
children: [headerElement, /* @__PURE__ */ jsx("div", {
|
|
className: "cpk:flex-1 cpk:overflow-hidden",
|
|
"data-popup-chat": true,
|
|
children: /* @__PURE__ */ jsx(CopilotChatView_default, {
|
|
...restProps,
|
|
className: cn("cpk:h-full cpk:min-h-0", className)
|
|
})
|
|
})]
|
|
})
|
|
}) : null] });
|
|
}
|
|
CopilotPopupView.displayName = "CopilotPopupView";
|
|
(function(_CopilotPopupView) {
|
|
_CopilotPopupView.WelcomeScreen = ({ welcomeMessage, input, suggestionView, className, children, ...props }) => {
|
|
const BoundWelcomeMessage = renderSlot(welcomeMessage, CopilotChatView_default.WelcomeMessage, {});
|
|
if (children) return /* @__PURE__ */ jsx("div", {
|
|
"data-copilotkit": true,
|
|
style: { display: "contents" },
|
|
children: children({
|
|
welcomeMessage: BoundWelcomeMessage,
|
|
input,
|
|
suggestionView,
|
|
className,
|
|
...props
|
|
})
|
|
});
|
|
return /* @__PURE__ */ jsxs("div", {
|
|
className: cn("cpk:h-full cpk:flex cpk:flex-col", className),
|
|
...props,
|
|
children: [/* @__PURE__ */ jsx("div", {
|
|
className: "cpk:flex-1 cpk:flex cpk:flex-col cpk:items-center cpk:justify-center cpk:px-4",
|
|
children: BoundWelcomeMessage
|
|
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
className: "cpk:mb-4 cpk:flex cpk:justify-center cpk:px-4",
|
|
children: suggestionView
|
|
}), input] })]
|
|
});
|
|
};
|
|
})(CopilotPopupView || (CopilotPopupView = {}));
|
|
var CopilotPopupView_default = CopilotPopupView;
|
|
|
|
//#endregion
|
|
export { CopilotPopupView, CopilotPopupView_default as default };
|
|
//# sourceMappingURL=CopilotPopupView.mjs.map
|