@yext/chat-ui-react 0.7.2 → 0.7.3
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/lib/commonjs/package.json.js +1 -1
- package/lib/commonjs/src/components/ChatPanel.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatPanel.js +10 -5
- package/lib/commonjs/src/components/ChatPanel.js.map +1 -1
- package/lib/commonjs/src/components/ChatPopUp.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatPopUp.js +3 -2
- package/lib/commonjs/src/components/ChatPopUp.js.map +1 -1
- package/lib/esm/package.json.mjs +1 -1
- package/lib/esm/src/components/ChatPanel.d.ts.map +1 -1
- package/lib/esm/src/components/ChatPanel.mjs +11 -6
- package/lib/esm/src/components/ChatPanel.mjs.map +1 -1
- package/lib/esm/src/components/ChatPopUp.d.ts.map +1 -1
- package/lib/esm/src/components/ChatPopUp.mjs +3 -2
- package/lib/esm/src/components/ChatPopUp.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/ChatPanel.tsx +13 -10
- package/src/components/ChatPopUp.tsx +17 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,EAEL,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAa,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAO7E;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAeD;;;;GAIG;AACH,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,CAAC,EAC9D,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC1C,kDAAkD;IAClD,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACrB;;OAEG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,qBAsF9C"}
|
|
@@ -33,7 +33,7 @@ const builtInCssClasses = withStylelessCssClasses.withStylelessCssClasses("Panel
|
|
|
33
33
|
* @param props - {@link ChatPanelProps}
|
|
34
34
|
*/
|
|
35
35
|
function ChatPanel(props) {
|
|
36
|
-
const { header, customCssClasses } = props;
|
|
36
|
+
const { header, customCssClasses, stream, handleError } = props;
|
|
37
37
|
const chat = chatHeadlessReact.useChatActions();
|
|
38
38
|
const messages = chatHeadlessReact.useChatState((state) => state.conversation.messages);
|
|
39
39
|
const loading = chatHeadlessReact.useChatState((state) => state.conversation.isLoading);
|
|
@@ -41,20 +41,25 @@ function ChatPanel(props) {
|
|
|
41
41
|
const cssClasses = useComposedCssClasses.useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
42
42
|
const defaultHandleApiError = useDefaultHandleApiError.useDefaultHandleApiError();
|
|
43
43
|
const reportAnalyticsEvent = useReportAnalyticsEvent.useReportAnalyticsEvent();
|
|
44
|
+
const [fetchInitialMessage, setFetchInitialMessage] = React.useState(false);
|
|
44
45
|
React.useEffect(() => {
|
|
45
46
|
reportAnalyticsEvent({
|
|
46
47
|
action: "CHAT_IMPRESSION",
|
|
47
48
|
});
|
|
48
49
|
}, [reportAnalyticsEvent]);
|
|
49
|
-
//
|
|
50
|
+
// Request initial message only if there are no existing messages and no ongoing request.
|
|
50
51
|
React.useEffect(() => {
|
|
51
|
-
|
|
52
|
+
setFetchInitialMessage(messages.length === 0 && canSendMessage);
|
|
53
|
+
}, [messages.length, canSendMessage]);
|
|
54
|
+
React.useEffect(() => {
|
|
55
|
+
if (!fetchInitialMessage) {
|
|
52
56
|
return;
|
|
53
57
|
}
|
|
54
|
-
|
|
58
|
+
// Ensures that the fetch for the initial message occurs only once
|
|
59
|
+
setFetchInitialMessage(false);
|
|
55
60
|
const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
|
|
56
61
|
res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
|
|
57
|
-
}, [chat,
|
|
62
|
+
}, [chat, stream, handleError, defaultHandleApiError, fetchInitialMessage]);
|
|
58
63
|
const messagesRef = React.useRef([]);
|
|
59
64
|
const messagesContainer = React.useRef(null);
|
|
60
65
|
// Handle scrolling when messages change
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPanel.js","sources":["../../../../src/components/ChatPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport {\n MessageBubble,\n MessageBubbleCssClasses,\n MessageBubbleProps,\n} from \"./MessageBubble\";\nimport { ChatInput, ChatInputCssClasses, ChatInputProps } from \"./ChatInput\";\nimport { LoadingDots } from \"./LoadingDots\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelCssClasses {\n container?: string;\n messagesContainer?: string;\n messagesScrollContainer?: string;\n inputContainer?: string;\n inputCssClasses?: ChatInputCssClasses;\n messageBubbleCssClasses?: MessageBubbleCssClasses;\n}\n\nconst builtInCssClasses: ChatPanelCssClasses = withStylelessCssClasses(\n \"Panel\",\n {\n container: \"h-full w-full flex flex-col relative shadow-2xl bg-white\",\n messagesScrollContainer: \"flex flex-col mt-auto overflow-hidden\",\n messagesContainer: \"flex flex-col gap-y-1 px-4 overflow-auto\",\n inputContainer: \"w-full p-4\",\n messageBubbleCssClasses: {\n topContainer: \"first:mt-4\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelProps\n extends Omit<MessageBubbleProps, \"customCssClasses\" | \"message\">,\n Omit<ChatInputProps, \"customCssClasses\"> {\n /** A header to render at the top of the panel. */\n header?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPanelCssClasses;\n}\n\n/**\n * A component that renders a full panel for chat bot interactions. This includes\n * the message bubbles for the conversation, input box with send button, and header\n * (if provided).\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPanel(props: ChatPanelProps) {\n const { header, customCssClasses } = props;\n const chat = useChatActions();\n const messages = useChatState((state) => state.conversation.messages);\n const loading = useChatState((state) => state.conversation.isLoading);\n const canSendMessage = useChatState(\n (state) => state.conversation.canSendMessage\n );\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const defaultHandleApiError = useDefaultHandleApiError();\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n //
|
|
1
|
+
{"version":3,"file":"ChatPanel.js","sources":["../../../../src/components/ChatPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport {\n MessageBubble,\n MessageBubbleCssClasses,\n MessageBubbleProps,\n} from \"./MessageBubble\";\nimport { ChatInput, ChatInputCssClasses, ChatInputProps } from \"./ChatInput\";\nimport { LoadingDots } from \"./LoadingDots\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelCssClasses {\n container?: string;\n messagesContainer?: string;\n messagesScrollContainer?: string;\n inputContainer?: string;\n inputCssClasses?: ChatInputCssClasses;\n messageBubbleCssClasses?: MessageBubbleCssClasses;\n}\n\nconst builtInCssClasses: ChatPanelCssClasses = withStylelessCssClasses(\n \"Panel\",\n {\n container: \"h-full w-full flex flex-col relative shadow-2xl bg-white\",\n messagesScrollContainer: \"flex flex-col mt-auto overflow-hidden\",\n messagesContainer: \"flex flex-col gap-y-1 px-4 overflow-auto\",\n inputContainer: \"w-full p-4\",\n messageBubbleCssClasses: {\n topContainer: \"first:mt-4\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelProps\n extends Omit<MessageBubbleProps, \"customCssClasses\" | \"message\">,\n Omit<ChatInputProps, \"customCssClasses\"> {\n /** A header to render at the top of the panel. */\n header?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPanelCssClasses;\n}\n\n/**\n * A component that renders a full panel for chat bot interactions. This includes\n * the message bubbles for the conversation, input box with send button, and header\n * (if provided).\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPanel(props: ChatPanelProps) {\n const { header, customCssClasses, stream, handleError } = props;\n const chat = useChatActions();\n const messages = useChatState((state) => state.conversation.messages);\n const loading = useChatState((state) => state.conversation.isLoading);\n const canSendMessage = useChatState(\n (state) => state.conversation.canSendMessage\n );\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const defaultHandleApiError = useDefaultHandleApiError();\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n const [fetchInitialMessage, setFetchInitialMessage] = useState(false);\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n // Request initial message only if there are no existing messages and no ongoing request.\n useEffect(() => {\n setFetchInitialMessage(messages.length === 0 && canSendMessage);\n }, [messages.length, canSendMessage]);\n\n useEffect(() => {\n if (!fetchInitialMessage) {\n return;\n }\n // Ensures that the fetch for the initial message occurs only once\n setFetchInitialMessage(false);\n const res = stream ? chat.streamNextMessage() : chat.getNextMessage();\n res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));\n }, [chat, stream, handleError, defaultHandleApiError, fetchInitialMessage]);\n\n const messagesRef = useRef<Array<HTMLDivElement | null>>([]);\n const messagesContainer = useRef<HTMLDivElement>(null);\n\n // Handle scrolling when messages change\n useEffect(() => {\n let scrollTop = 0;\n messagesRef.current = messagesRef.current.slice(0, messages.length);\n\n // Sums up scroll heights of all messages except the last one\n if (messagesRef?.current.length > 1) {\n scrollTop = messagesRef.current\n .slice(0, -1)\n .map((elem, _) => elem?.scrollHeight ?? 0)\n .reduce((total, height) => total + height);\n }\n\n // Scroll to the top of the last message\n messagesContainer.current?.scroll({\n top: scrollTop,\n behavior: \"smooth\",\n });\n }, [messages]);\n\n const setMessagesRef = useCallback((index) => {\n if (!messagesRef?.current) return null;\n return (message) => (messagesRef.current[index] = message);\n }, []);\n\n return (\n <div className=\"yext-chat w-full h-full\">\n <div className={cssClasses.container}>\n {header}\n <div className={cssClasses.messagesScrollContainer}>\n <div ref={messagesContainer} className={cssClasses.messagesContainer}>\n {messages.map((message, index) => (\n <div key={index} ref={setMessagesRef(index)}>\n <MessageBubble\n {...props}\n customCssClasses={cssClasses.messageBubbleCssClasses}\n message={message}\n />\n </div>\n ))}\n {loading && <LoadingDots />}\n </div>\n </div>\n <div className={cssClasses.inputContainer}>\n <ChatInput {...props} customCssClasses={cssClasses.inputCssClasses} />\n </div>\n </div>\n </div>\n );\n}\n"],"names":["withStylelessCssClasses","useChatActions","useChatState","useComposedCssClasses","useDefaultHandleApiError","useReportAnalyticsEvent","useState","useEffect","useRef","useCallback","React","MessageBubble","LoadingDots","ChatInput"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPopUp.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPopUp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAa,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEL,oBAAoB,EACpB,eAAe,EAChB,MAAM,cAAc,CAAC;AAMtB;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,eAAe,CAAC,EAAE,mBAAmB,CAAC;CACvC;AA8BD;;;;GAIG;AACH,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,eAAe,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,EACnE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,kBAAkB,CAAC;IACrD,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAClC;;OAEG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"ChatPopUp.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPopUp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAa,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEL,oBAAoB,EACpB,eAAe,EAChB,MAAM,cAAc,CAAC;AAMtB;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,eAAe,CAAC,EAAE,mBAAmB,CAAC;CACvC;AA8BD;;;;GAIG;AACH,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,eAAe,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,EACnE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,kBAAkB,CAAC;IACrD,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAClC;;OAEG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,qBAsE9C"}
|
|
@@ -50,9 +50,11 @@ function ChatPopUp(props) {
|
|
|
50
50
|
action: "CHAT_IMPRESSION",
|
|
51
51
|
});
|
|
52
52
|
}, [reportAnalyticsEvent]);
|
|
53
|
+
const [renderChat, setRenderChat] = React.useState(false);
|
|
53
54
|
const [showChat, setShowChat] = React.useState(false);
|
|
54
55
|
const onClick = React.useCallback(() => {
|
|
55
56
|
setShowChat(!showChat);
|
|
57
|
+
setRenderChat(true);
|
|
56
58
|
}, [showChat]);
|
|
57
59
|
const onClose = React.useCallback(() => {
|
|
58
60
|
setShowChat(false);
|
|
@@ -63,8 +65,7 @@ function ChatPopUp(props) {
|
|
|
63
65
|
const buttonCssClasses = tailwindMerge.twMerge(cssClasses.button, showChat ? cssClasses.button__hidden : cssClasses.button__display);
|
|
64
66
|
return (React__default.default.createElement("div", { className: "yext-chat w-full h-full" },
|
|
65
67
|
React__default.default.createElement("div", { className: cssClasses.container },
|
|
66
|
-
React__default.default.createElement("div", { className: panelCssClasses, "aria-label": "Chat Popup Panel" },
|
|
67
|
-
React__default.default.createElement(ChatPanel.ChatPanel, { ...props, customCssClasses: cssClasses.panelCssClasses, header: React__default.default.createElement(ChatHeader.ChatHeader, { title: title, showRestartButton: showRestartButton, showCloseButton: true, onClose: onClose, customCssClasses: cssClasses.headerCssClasses }) })),
|
|
68
|
+
React__default.default.createElement("div", { className: panelCssClasses, "aria-label": "Chat Popup Panel" }, renderChat && (React__default.default.createElement(ChatPanel.ChatPanel, { ...props, customCssClasses: cssClasses.panelCssClasses, header: React__default.default.createElement(ChatHeader.ChatHeader, { title: title, showRestartButton: showRestartButton, showCloseButton: true, onClose: onClose, customCssClasses: cssClasses.headerCssClasses }) }))),
|
|
68
69
|
React__default.default.createElement("button", { "aria-label": "Chat Popup Button", onClick: onClick, className: buttonCssClasses }, openPanelButtonIcon ?? (React__default.default.createElement(Chat.ChatIcon, { className: cssClasses.buttonIcon }))))));
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPopUp.js","sources":["../../../../src/components/ChatPopUp.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useState } from \"react\";\nimport { ChatIcon } from \"../icons/Chat\";\nimport { ChatPanel, ChatPanelCssClasses, ChatPanelProps } from \"./ChatPanel\";\nimport {\n ChatHeader,\n ChatHeaderCssClasses,\n ChatHeaderProps,\n} from \"./ChatHeader\";\nimport { twMerge } from \"tailwind-merge\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpCssClasses {\n container?: string;\n panel?: string;\n panel__display?: string;\n panel__hidden?: string;\n button?: string;\n button__display?: string;\n button__hidden?: string;\n buttonIcon?: string;\n headerCssClasses?: ChatHeaderCssClasses;\n panelCssClasses?: ChatPanelCssClasses;\n}\n\nconst fixedPosition = \"fixed bottom-6 right-4 lg:bottom-14 lg:right-10 z-50 \";\nconst builtInCssClasses: ChatPopUpCssClasses = withStylelessCssClasses(\n \"PopUp\",\n {\n container: \"transition-all\",\n panel:\n fixedPosition +\n \"w-80 max-[480px]:right-0 max-[480px]:bottom-0 max-[480px]:w-full max-[480px]:h-full lg:w-96 h-[75vh]\",\n panel__display: \"duration-300 translate-y-0\",\n panel__hidden: \"duration-300 translate-y-[20%] opacity-0 invisible\",\n button:\n fixedPosition +\n \"p-2 w-12 h-12 lg:w-16 lg:h-16 flex justify-center items-center text-white shadow-xl rounded-full bg-gradient-to-br from-blue-600 to-blue-700 hover:-translate-y-2 duration-150\",\n button__display: \"duration-300 transform translate-y-0\",\n button__hidden:\n \"duration-300 transform translate-y-[20%] opacity-0 invisible\",\n buttonIcon: \"text-blue-600 w-[28px] h-[28px] lg:w-[40px] lg:h-[40px]\",\n headerCssClasses: {\n container: \"max-[480px]:rounded-none rounded-t-3xl\",\n },\n panelCssClasses: {\n container: \"max-[480px]:rounded-none rounded-3xl\",\n inputContainer: \"max-[480px]:rounded-none rounded-b-3xl\",\n messagesScrollContainer: \"rounded-b-3xl\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpProps\n extends Omit<ChatHeaderProps, \"showCloseButton\" | \"customCssClasses\">,\n Omit<ChatPanelProps, \"header\" | \"customCssClasses\"> {\n /** Custom icon for the popup button to open the panel. */\n openPanelButtonIcon?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPopUpCssClasses;\n}\n\n/**\n * A component that renders a popup button that displays and hides\n * a panel for chat bot interactions.\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPopUp(props: ChatPopUpProps) {\n const {\n openPanelButtonIcon,\n customCssClasses,\n showRestartButton = true,\n onClose: customOnClose,\n title,\n } = props;\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n const [showChat, setShowChat] = useState(false);\n const onClick = useCallback(() => {\n setShowChat(!showChat);\n }, [showChat]);\n\n const onClose = useCallback(() => {\n setShowChat(false);\n customOnClose?.();\n }, [customOnClose]);\n\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const panelCssClasses = twMerge(\n cssClasses.panel,\n showChat ? cssClasses.panel__display : cssClasses.panel__hidden\n );\n const buttonCssClasses = twMerge(\n cssClasses.button,\n showChat ? cssClasses.button__hidden : cssClasses.button__display\n );\n\n return (\n <div className=\"yext-chat w-full h-full\">\n <div className={cssClasses.container}>\n <div className={panelCssClasses} aria-label=\"Chat Popup Panel\">\n <ChatPanel\n
|
|
1
|
+
{"version":3,"file":"ChatPopUp.js","sources":["../../../../src/components/ChatPopUp.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useState } from \"react\";\nimport { ChatIcon } from \"../icons/Chat\";\nimport { ChatPanel, ChatPanelCssClasses, ChatPanelProps } from \"./ChatPanel\";\nimport {\n ChatHeader,\n ChatHeaderCssClasses,\n ChatHeaderProps,\n} from \"./ChatHeader\";\nimport { twMerge } from \"tailwind-merge\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpCssClasses {\n container?: string;\n panel?: string;\n panel__display?: string;\n panel__hidden?: string;\n button?: string;\n button__display?: string;\n button__hidden?: string;\n buttonIcon?: string;\n headerCssClasses?: ChatHeaderCssClasses;\n panelCssClasses?: ChatPanelCssClasses;\n}\n\nconst fixedPosition = \"fixed bottom-6 right-4 lg:bottom-14 lg:right-10 z-50 \";\nconst builtInCssClasses: ChatPopUpCssClasses = withStylelessCssClasses(\n \"PopUp\",\n {\n container: \"transition-all\",\n panel:\n fixedPosition +\n \"w-80 max-[480px]:right-0 max-[480px]:bottom-0 max-[480px]:w-full max-[480px]:h-full lg:w-96 h-[75vh]\",\n panel__display: \"duration-300 translate-y-0\",\n panel__hidden: \"duration-300 translate-y-[20%] opacity-0 invisible\",\n button:\n fixedPosition +\n \"p-2 w-12 h-12 lg:w-16 lg:h-16 flex justify-center items-center text-white shadow-xl rounded-full bg-gradient-to-br from-blue-600 to-blue-700 hover:-translate-y-2 duration-150\",\n button__display: \"duration-300 transform translate-y-0\",\n button__hidden:\n \"duration-300 transform translate-y-[20%] opacity-0 invisible\",\n buttonIcon: \"text-blue-600 w-[28px] h-[28px] lg:w-[40px] lg:h-[40px]\",\n headerCssClasses: {\n container: \"max-[480px]:rounded-none rounded-t-3xl\",\n },\n panelCssClasses: {\n container: \"max-[480px]:rounded-none rounded-3xl\",\n inputContainer: \"max-[480px]:rounded-none rounded-b-3xl\",\n messagesScrollContainer: \"rounded-b-3xl\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpProps\n extends Omit<ChatHeaderProps, \"showCloseButton\" | \"customCssClasses\">,\n Omit<ChatPanelProps, \"header\" | \"customCssClasses\"> {\n /** Custom icon for the popup button to open the panel. */\n openPanelButtonIcon?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPopUpCssClasses;\n}\n\n/**\n * A component that renders a popup button that displays and hides\n * a panel for chat bot interactions.\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPopUp(props: ChatPopUpProps) {\n const {\n openPanelButtonIcon,\n customCssClasses,\n showRestartButton = true,\n onClose: customOnClose,\n title,\n } = props;\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n const [renderChat, setRenderChat] = useState(false);\n const [showChat, setShowChat] = useState(false);\n const onClick = useCallback(() => {\n setShowChat(!showChat);\n setRenderChat(true);\n }, [showChat]);\n\n const onClose = useCallback(() => {\n setShowChat(false);\n customOnClose?.();\n }, [customOnClose]);\n\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const panelCssClasses = twMerge(\n cssClasses.panel,\n showChat ? cssClasses.panel__display : cssClasses.panel__hidden\n );\n const buttonCssClasses = twMerge(\n cssClasses.button,\n showChat ? cssClasses.button__hidden : cssClasses.button__display\n );\n\n return (\n <div className=\"yext-chat w-full h-full\">\n <div className={cssClasses.container}>\n <div className={panelCssClasses} aria-label=\"Chat Popup Panel\">\n {renderChat && (\n <ChatPanel\n {...props}\n customCssClasses={cssClasses.panelCssClasses}\n header={\n <ChatHeader\n title={title}\n showRestartButton={showRestartButton}\n showCloseButton={true}\n onClose={onClose}\n customCssClasses={cssClasses.headerCssClasses}\n />\n }\n />\n )}\n </div>\n <button\n aria-label=\"Chat Popup Button\"\n onClick={onClick}\n className={buttonCssClasses}\n >\n {openPanelButtonIcon ?? (\n <ChatIcon className={cssClasses.buttonIcon} />\n )}\n </button>\n </div>\n </div>\n );\n}\n"],"names":["withStylelessCssClasses","useReportAnalyticsEvent","useEffect","useState","useCallback","useComposedCssClasses","twMerge","React","ChatPanel","ChatHeader","ChatIcon"],"mappings":"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"}
|
package/lib/esm/package.json.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,EAEL,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAa,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAO7E;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAeD;;;;GAIG;AACH,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,CAAC,EAC9D,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC1C,kDAAkD;IAClD,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACrB;;OAEG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,qBAsF9C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useCallback } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
2
|
import { useChatActions, useChatState } from '@yext/chat-headless-react';
|
|
3
3
|
import { MessageBubble } from './MessageBubble.mjs';
|
|
4
4
|
import { ChatInput } from './ChatInput.mjs';
|
|
@@ -27,7 +27,7 @@ const builtInCssClasses = withStylelessCssClasses("Panel", {
|
|
|
27
27
|
* @param props - {@link ChatPanelProps}
|
|
28
28
|
*/
|
|
29
29
|
function ChatPanel(props) {
|
|
30
|
-
const { header, customCssClasses } = props;
|
|
30
|
+
const { header, customCssClasses, stream, handleError } = props;
|
|
31
31
|
const chat = useChatActions();
|
|
32
32
|
const messages = useChatState((state) => state.conversation.messages);
|
|
33
33
|
const loading = useChatState((state) => state.conversation.isLoading);
|
|
@@ -35,20 +35,25 @@ function ChatPanel(props) {
|
|
|
35
35
|
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
36
36
|
const defaultHandleApiError = useDefaultHandleApiError();
|
|
37
37
|
const reportAnalyticsEvent = useReportAnalyticsEvent();
|
|
38
|
+
const [fetchInitialMessage, setFetchInitialMessage] = useState(false);
|
|
38
39
|
useEffect(() => {
|
|
39
40
|
reportAnalyticsEvent({
|
|
40
41
|
action: "CHAT_IMPRESSION",
|
|
41
42
|
});
|
|
42
43
|
}, [reportAnalyticsEvent]);
|
|
43
|
-
//
|
|
44
|
+
// Request initial message only if there are no existing messages and no ongoing request.
|
|
44
45
|
useEffect(() => {
|
|
45
|
-
|
|
46
|
+
setFetchInitialMessage(messages.length === 0 && canSendMessage);
|
|
47
|
+
}, [messages.length, canSendMessage]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!fetchInitialMessage) {
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
|
-
|
|
52
|
+
// Ensures that the fetch for the initial message occurs only once
|
|
53
|
+
setFetchInitialMessage(false);
|
|
49
54
|
const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
|
|
50
55
|
res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
|
|
51
|
-
}, [chat,
|
|
56
|
+
}, [chat, stream, handleError, defaultHandleApiError, fetchInitialMessage]);
|
|
52
57
|
const messagesRef = useRef([]);
|
|
53
58
|
const messagesContainer = useRef(null);
|
|
54
59
|
// Handle scrolling when messages change
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPanel.mjs","sources":["../../../../src/components/ChatPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport {\n MessageBubble,\n MessageBubbleCssClasses,\n MessageBubbleProps,\n} from \"./MessageBubble\";\nimport { ChatInput, ChatInputCssClasses, ChatInputProps } from \"./ChatInput\";\nimport { LoadingDots } from \"./LoadingDots\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelCssClasses {\n container?: string;\n messagesContainer?: string;\n messagesScrollContainer?: string;\n inputContainer?: string;\n inputCssClasses?: ChatInputCssClasses;\n messageBubbleCssClasses?: MessageBubbleCssClasses;\n}\n\nconst builtInCssClasses: ChatPanelCssClasses = withStylelessCssClasses(\n \"Panel\",\n {\n container: \"h-full w-full flex flex-col relative shadow-2xl bg-white\",\n messagesScrollContainer: \"flex flex-col mt-auto overflow-hidden\",\n messagesContainer: \"flex flex-col gap-y-1 px-4 overflow-auto\",\n inputContainer: \"w-full p-4\",\n messageBubbleCssClasses: {\n topContainer: \"first:mt-4\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelProps\n extends Omit<MessageBubbleProps, \"customCssClasses\" | \"message\">,\n Omit<ChatInputProps, \"customCssClasses\"> {\n /** A header to render at the top of the panel. */\n header?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPanelCssClasses;\n}\n\n/**\n * A component that renders a full panel for chat bot interactions. This includes\n * the message bubbles for the conversation, input box with send button, and header\n * (if provided).\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPanel(props: ChatPanelProps) {\n const { header, customCssClasses } = props;\n const chat = useChatActions();\n const messages = useChatState((state) => state.conversation.messages);\n const loading = useChatState((state) => state.conversation.isLoading);\n const canSendMessage = useChatState(\n (state) => state.conversation.canSendMessage\n );\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const defaultHandleApiError = useDefaultHandleApiError();\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n //
|
|
1
|
+
{"version":3,"file":"ChatPanel.mjs","sources":["../../../../src/components/ChatPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport {\n MessageBubble,\n MessageBubbleCssClasses,\n MessageBubbleProps,\n} from \"./MessageBubble\";\nimport { ChatInput, ChatInputCssClasses, ChatInputProps } from \"./ChatInput\";\nimport { LoadingDots } from \"./LoadingDots\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelCssClasses {\n container?: string;\n messagesContainer?: string;\n messagesScrollContainer?: string;\n inputContainer?: string;\n inputCssClasses?: ChatInputCssClasses;\n messageBubbleCssClasses?: MessageBubbleCssClasses;\n}\n\nconst builtInCssClasses: ChatPanelCssClasses = withStylelessCssClasses(\n \"Panel\",\n {\n container: \"h-full w-full flex flex-col relative shadow-2xl bg-white\",\n messagesScrollContainer: \"flex flex-col mt-auto overflow-hidden\",\n messagesContainer: \"flex flex-col gap-y-1 px-4 overflow-auto\",\n inputContainer: \"w-full p-4\",\n messageBubbleCssClasses: {\n topContainer: \"first:mt-4\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPanel} component.\n *\n * @public\n */\nexport interface ChatPanelProps\n extends Omit<MessageBubbleProps, \"customCssClasses\" | \"message\">,\n Omit<ChatInputProps, \"customCssClasses\"> {\n /** A header to render at the top of the panel. */\n header?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPanelCssClasses;\n}\n\n/**\n * A component that renders a full panel for chat bot interactions. This includes\n * the message bubbles for the conversation, input box with send button, and header\n * (if provided).\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPanel(props: ChatPanelProps) {\n const { header, customCssClasses, stream, handleError } = props;\n const chat = useChatActions();\n const messages = useChatState((state) => state.conversation.messages);\n const loading = useChatState((state) => state.conversation.isLoading);\n const canSendMessage = useChatState(\n (state) => state.conversation.canSendMessage\n );\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const defaultHandleApiError = useDefaultHandleApiError();\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n const [fetchInitialMessage, setFetchInitialMessage] = useState(false);\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n // Request initial message only if there are no existing messages and no ongoing request.\n useEffect(() => {\n setFetchInitialMessage(messages.length === 0 && canSendMessage);\n }, [messages.length, canSendMessage]);\n\n useEffect(() => {\n if (!fetchInitialMessage) {\n return;\n }\n // Ensures that the fetch for the initial message occurs only once\n setFetchInitialMessage(false);\n const res = stream ? chat.streamNextMessage() : chat.getNextMessage();\n res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));\n }, [chat, stream, handleError, defaultHandleApiError, fetchInitialMessage]);\n\n const messagesRef = useRef<Array<HTMLDivElement | null>>([]);\n const messagesContainer = useRef<HTMLDivElement>(null);\n\n // Handle scrolling when messages change\n useEffect(() => {\n let scrollTop = 0;\n messagesRef.current = messagesRef.current.slice(0, messages.length);\n\n // Sums up scroll heights of all messages except the last one\n if (messagesRef?.current.length > 1) {\n scrollTop = messagesRef.current\n .slice(0, -1)\n .map((elem, _) => elem?.scrollHeight ?? 0)\n .reduce((total, height) => total + height);\n }\n\n // Scroll to the top of the last message\n messagesContainer.current?.scroll({\n top: scrollTop,\n behavior: \"smooth\",\n });\n }, [messages]);\n\n const setMessagesRef = useCallback((index) => {\n if (!messagesRef?.current) return null;\n return (message) => (messagesRef.current[index] = message);\n }, []);\n\n return (\n <div className=\"yext-chat w-full h-full\">\n <div className={cssClasses.container}>\n {header}\n <div className={cssClasses.messagesScrollContainer}>\n <div ref={messagesContainer} className={cssClasses.messagesContainer}>\n {messages.map((message, index) => (\n <div key={index} ref={setMessagesRef(index)}>\n <MessageBubble\n {...props}\n customCssClasses={cssClasses.messageBubbleCssClasses}\n message={message}\n />\n </div>\n ))}\n {loading && <LoadingDots />}\n </div>\n </div>\n <div className={cssClasses.inputContainer}>\n <ChatInput {...props} customCssClasses={cssClasses.inputCssClasses} />\n </div>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPopUp.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPopUp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAa,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEL,oBAAoB,EACpB,eAAe,EAChB,MAAM,cAAc,CAAC;AAMtB;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,eAAe,CAAC,EAAE,mBAAmB,CAAC;CACvC;AA8BD;;;;GAIG;AACH,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,eAAe,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,EACnE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,kBAAkB,CAAC;IACrD,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAClC;;OAEG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"ChatPopUp.d.ts","sourceRoot":"","sources":["../../../../src/components/ChatPopUp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAa,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEL,oBAAoB,EACpB,eAAe,EAChB,MAAM,cAAc,CAAC;AAMtB;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,eAAe,CAAC,EAAE,mBAAmB,CAAC;CACvC;AA8BD;;;;GAIG;AACH,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,eAAe,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,EACnE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,kBAAkB,CAAC;IACrD,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAClC;;OAEG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,qBAsE9C"}
|
|
@@ -44,9 +44,11 @@ function ChatPopUp(props) {
|
|
|
44
44
|
action: "CHAT_IMPRESSION",
|
|
45
45
|
});
|
|
46
46
|
}, [reportAnalyticsEvent]);
|
|
47
|
+
const [renderChat, setRenderChat] = useState(false);
|
|
47
48
|
const [showChat, setShowChat] = useState(false);
|
|
48
49
|
const onClick = useCallback(() => {
|
|
49
50
|
setShowChat(!showChat);
|
|
51
|
+
setRenderChat(true);
|
|
50
52
|
}, [showChat]);
|
|
51
53
|
const onClose = useCallback(() => {
|
|
52
54
|
setShowChat(false);
|
|
@@ -57,8 +59,7 @@ function ChatPopUp(props) {
|
|
|
57
59
|
const buttonCssClasses = twMerge(cssClasses.button, showChat ? cssClasses.button__hidden : cssClasses.button__display);
|
|
58
60
|
return (React.createElement("div", { className: "yext-chat w-full h-full" },
|
|
59
61
|
React.createElement("div", { className: cssClasses.container },
|
|
60
|
-
React.createElement("div", { className: panelCssClasses, "aria-label": "Chat Popup Panel" },
|
|
61
|
-
React.createElement(ChatPanel, { ...props, customCssClasses: cssClasses.panelCssClasses, header: React.createElement(ChatHeader, { title: title, showRestartButton: showRestartButton, showCloseButton: true, onClose: onClose, customCssClasses: cssClasses.headerCssClasses }) })),
|
|
62
|
+
React.createElement("div", { className: panelCssClasses, "aria-label": "Chat Popup Panel" }, renderChat && (React.createElement(ChatPanel, { ...props, customCssClasses: cssClasses.panelCssClasses, header: React.createElement(ChatHeader, { title: title, showRestartButton: showRestartButton, showCloseButton: true, onClose: onClose, customCssClasses: cssClasses.headerCssClasses }) }))),
|
|
62
63
|
React.createElement("button", { "aria-label": "Chat Popup Button", onClick: onClick, className: buttonCssClasses }, openPanelButtonIcon ?? (React.createElement(ChatIcon, { className: cssClasses.buttonIcon }))))));
|
|
63
64
|
}
|
|
64
65
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPopUp.mjs","sources":["../../../../src/components/ChatPopUp.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useState } from \"react\";\nimport { ChatIcon } from \"../icons/Chat\";\nimport { ChatPanel, ChatPanelCssClasses, ChatPanelProps } from \"./ChatPanel\";\nimport {\n ChatHeader,\n ChatHeaderCssClasses,\n ChatHeaderProps,\n} from \"./ChatHeader\";\nimport { twMerge } from \"tailwind-merge\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpCssClasses {\n container?: string;\n panel?: string;\n panel__display?: string;\n panel__hidden?: string;\n button?: string;\n button__display?: string;\n button__hidden?: string;\n buttonIcon?: string;\n headerCssClasses?: ChatHeaderCssClasses;\n panelCssClasses?: ChatPanelCssClasses;\n}\n\nconst fixedPosition = \"fixed bottom-6 right-4 lg:bottom-14 lg:right-10 z-50 \";\nconst builtInCssClasses: ChatPopUpCssClasses = withStylelessCssClasses(\n \"PopUp\",\n {\n container: \"transition-all\",\n panel:\n fixedPosition +\n \"w-80 max-[480px]:right-0 max-[480px]:bottom-0 max-[480px]:w-full max-[480px]:h-full lg:w-96 h-[75vh]\",\n panel__display: \"duration-300 translate-y-0\",\n panel__hidden: \"duration-300 translate-y-[20%] opacity-0 invisible\",\n button:\n fixedPosition +\n \"p-2 w-12 h-12 lg:w-16 lg:h-16 flex justify-center items-center text-white shadow-xl rounded-full bg-gradient-to-br from-blue-600 to-blue-700 hover:-translate-y-2 duration-150\",\n button__display: \"duration-300 transform translate-y-0\",\n button__hidden:\n \"duration-300 transform translate-y-[20%] opacity-0 invisible\",\n buttonIcon: \"text-blue-600 w-[28px] h-[28px] lg:w-[40px] lg:h-[40px]\",\n headerCssClasses: {\n container: \"max-[480px]:rounded-none rounded-t-3xl\",\n },\n panelCssClasses: {\n container: \"max-[480px]:rounded-none rounded-3xl\",\n inputContainer: \"max-[480px]:rounded-none rounded-b-3xl\",\n messagesScrollContainer: \"rounded-b-3xl\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpProps\n extends Omit<ChatHeaderProps, \"showCloseButton\" | \"customCssClasses\">,\n Omit<ChatPanelProps, \"header\" | \"customCssClasses\"> {\n /** Custom icon for the popup button to open the panel. */\n openPanelButtonIcon?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPopUpCssClasses;\n}\n\n/**\n * A component that renders a popup button that displays and hides\n * a panel for chat bot interactions.\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPopUp(props: ChatPopUpProps) {\n const {\n openPanelButtonIcon,\n customCssClasses,\n showRestartButton = true,\n onClose: customOnClose,\n title,\n } = props;\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n const [showChat, setShowChat] = useState(false);\n const onClick = useCallback(() => {\n setShowChat(!showChat);\n }, [showChat]);\n\n const onClose = useCallback(() => {\n setShowChat(false);\n customOnClose?.();\n }, [customOnClose]);\n\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const panelCssClasses = twMerge(\n cssClasses.panel,\n showChat ? cssClasses.panel__display : cssClasses.panel__hidden\n );\n const buttonCssClasses = twMerge(\n cssClasses.button,\n showChat ? cssClasses.button__hidden : cssClasses.button__display\n );\n\n return (\n <div className=\"yext-chat w-full h-full\">\n <div className={cssClasses.container}>\n <div className={panelCssClasses} aria-label=\"Chat Popup Panel\">\n <ChatPanel\n
|
|
1
|
+
{"version":3,"file":"ChatPopUp.mjs","sources":["../../../../src/components/ChatPopUp.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useState } from \"react\";\nimport { ChatIcon } from \"../icons/Chat\";\nimport { ChatPanel, ChatPanelCssClasses, ChatPanelProps } from \"./ChatPanel\";\nimport {\n ChatHeader,\n ChatHeaderCssClasses,\n ChatHeaderProps,\n} from \"./ChatHeader\";\nimport { twMerge } from \"tailwind-merge\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n/**\n * The CSS class interface for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpCssClasses {\n container?: string;\n panel?: string;\n panel__display?: string;\n panel__hidden?: string;\n button?: string;\n button__display?: string;\n button__hidden?: string;\n buttonIcon?: string;\n headerCssClasses?: ChatHeaderCssClasses;\n panelCssClasses?: ChatPanelCssClasses;\n}\n\nconst fixedPosition = \"fixed bottom-6 right-4 lg:bottom-14 lg:right-10 z-50 \";\nconst builtInCssClasses: ChatPopUpCssClasses = withStylelessCssClasses(\n \"PopUp\",\n {\n container: \"transition-all\",\n panel:\n fixedPosition +\n \"w-80 max-[480px]:right-0 max-[480px]:bottom-0 max-[480px]:w-full max-[480px]:h-full lg:w-96 h-[75vh]\",\n panel__display: \"duration-300 translate-y-0\",\n panel__hidden: \"duration-300 translate-y-[20%] opacity-0 invisible\",\n button:\n fixedPosition +\n \"p-2 w-12 h-12 lg:w-16 lg:h-16 flex justify-center items-center text-white shadow-xl rounded-full bg-gradient-to-br from-blue-600 to-blue-700 hover:-translate-y-2 duration-150\",\n button__display: \"duration-300 transform translate-y-0\",\n button__hidden:\n \"duration-300 transform translate-y-[20%] opacity-0 invisible\",\n buttonIcon: \"text-blue-600 w-[28px] h-[28px] lg:w-[40px] lg:h-[40px]\",\n headerCssClasses: {\n container: \"max-[480px]:rounded-none rounded-t-3xl\",\n },\n panelCssClasses: {\n container: \"max-[480px]:rounded-none rounded-3xl\",\n inputContainer: \"max-[480px]:rounded-none rounded-b-3xl\",\n messagesScrollContainer: \"rounded-b-3xl\",\n },\n }\n);\n\n/**\n * The props for the {@link ChatPopUp} component.\n *\n * @public\n */\nexport interface ChatPopUpProps\n extends Omit<ChatHeaderProps, \"showCloseButton\" | \"customCssClasses\">,\n Omit<ChatPanelProps, \"header\" | \"customCssClasses\"> {\n /** Custom icon for the popup button to open the panel. */\n openPanelButtonIcon?: JSX.Element;\n /**\n * CSS classes for customizing the component styling.\n */\n customCssClasses?: ChatPopUpCssClasses;\n}\n\n/**\n * A component that renders a popup button that displays and hides\n * a panel for chat bot interactions.\n *\n * @public\n *\n * @param props - {@link ChatPanelProps}\n */\nexport function ChatPopUp(props: ChatPopUpProps) {\n const {\n openPanelButtonIcon,\n customCssClasses,\n showRestartButton = true,\n onClose: customOnClose,\n title,\n } = props;\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n useEffect(() => {\n reportAnalyticsEvent({\n action: \"CHAT_IMPRESSION\",\n });\n }, [reportAnalyticsEvent]);\n\n const [renderChat, setRenderChat] = useState(false);\n const [showChat, setShowChat] = useState(false);\n const onClick = useCallback(() => {\n setShowChat(!showChat);\n setRenderChat(true);\n }, [showChat]);\n\n const onClose = useCallback(() => {\n setShowChat(false);\n customOnClose?.();\n }, [customOnClose]);\n\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const panelCssClasses = twMerge(\n cssClasses.panel,\n showChat ? cssClasses.panel__display : cssClasses.panel__hidden\n );\n const buttonCssClasses = twMerge(\n cssClasses.button,\n showChat ? cssClasses.button__hidden : cssClasses.button__display\n );\n\n return (\n <div className=\"yext-chat w-full h-full\">\n <div className={cssClasses.container}>\n <div className={panelCssClasses} aria-label=\"Chat Popup Panel\">\n {renderChat && (\n <ChatPanel\n {...props}\n customCssClasses={cssClasses.panelCssClasses}\n header={\n <ChatHeader\n title={title}\n showRestartButton={showRestartButton}\n showCloseButton={true}\n onClose={onClose}\n customCssClasses={cssClasses.headerCssClasses}\n />\n }\n />\n )}\n </div>\n <button\n aria-label=\"Chat Popup Button\"\n onClick={onClick}\n className={buttonCssClasses}\n >\n {openPanelButtonIcon ?? (\n <ChatIcon className={cssClasses.buttonIcon} />\n )}\n </button>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef } from "react";
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { useChatState, useChatActions } from "@yext/chat-headless-react";
|
|
3
3
|
import {
|
|
4
4
|
MessageBubble,
|
|
@@ -65,7 +65,7 @@ export interface ChatPanelProps
|
|
|
65
65
|
* @param props - {@link ChatPanelProps}
|
|
66
66
|
*/
|
|
67
67
|
export function ChatPanel(props: ChatPanelProps) {
|
|
68
|
-
const { header, customCssClasses } = props;
|
|
68
|
+
const { header, customCssClasses, stream, handleError } = props;
|
|
69
69
|
const chat = useChatActions();
|
|
70
70
|
const messages = useChatState((state) => state.conversation.messages);
|
|
71
71
|
const loading = useChatState((state) => state.conversation.isLoading);
|
|
@@ -75,6 +75,7 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
75
75
|
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
76
76
|
const defaultHandleApiError = useDefaultHandleApiError();
|
|
77
77
|
const reportAnalyticsEvent = useReportAnalyticsEvent();
|
|
78
|
+
const [fetchInitialMessage, setFetchInitialMessage] = useState(false);
|
|
78
79
|
|
|
79
80
|
useEffect(() => {
|
|
80
81
|
reportAnalyticsEvent({
|
|
@@ -82,15 +83,20 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
82
83
|
});
|
|
83
84
|
}, [reportAnalyticsEvent]);
|
|
84
85
|
|
|
85
|
-
//
|
|
86
|
+
// Request initial message only if there are no existing messages and no ongoing request.
|
|
86
87
|
useEffect(() => {
|
|
87
|
-
|
|
88
|
+
setFetchInitialMessage(messages.length === 0 && canSendMessage);
|
|
89
|
+
}, [messages.length, canSendMessage]);
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (!fetchInitialMessage) {
|
|
88
93
|
return;
|
|
89
94
|
}
|
|
90
|
-
|
|
95
|
+
// Ensures that the fetch for the initial message occurs only once
|
|
96
|
+
setFetchInitialMessage(false);
|
|
91
97
|
const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
|
|
92
98
|
res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
|
|
93
|
-
}, [chat,
|
|
99
|
+
}, [chat, stream, handleError, defaultHandleApiError, fetchInitialMessage]);
|
|
94
100
|
|
|
95
101
|
const messagesRef = useRef<Array<HTMLDivElement | null>>([]);
|
|
96
102
|
const messagesContainer = useRef<HTMLDivElement>(null);
|
|
@@ -125,10 +131,7 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
125
131
|
<div className={cssClasses.container}>
|
|
126
132
|
{header}
|
|
127
133
|
<div className={cssClasses.messagesScrollContainer}>
|
|
128
|
-
<div
|
|
129
|
-
ref={messagesContainer}
|
|
130
|
-
className={cssClasses.messagesContainer}
|
|
131
|
-
>
|
|
134
|
+
<div ref={messagesContainer} className={cssClasses.messagesContainer}>
|
|
132
135
|
{messages.map((message, index) => (
|
|
133
136
|
<div key={index} ref={setMessagesRef(index)}>
|
|
134
137
|
<MessageBubble
|
|
@@ -97,9 +97,11 @@ export function ChatPopUp(props: ChatPopUpProps) {
|
|
|
97
97
|
});
|
|
98
98
|
}, [reportAnalyticsEvent]);
|
|
99
99
|
|
|
100
|
+
const [renderChat, setRenderChat] = useState(false);
|
|
100
101
|
const [showChat, setShowChat] = useState(false);
|
|
101
102
|
const onClick = useCallback(() => {
|
|
102
103
|
setShowChat(!showChat);
|
|
104
|
+
setRenderChat(true);
|
|
103
105
|
}, [showChat]);
|
|
104
106
|
|
|
105
107
|
const onClose = useCallback(() => {
|
|
@@ -121,19 +123,21 @@ export function ChatPopUp(props: ChatPopUpProps) {
|
|
|
121
123
|
<div className="yext-chat w-full h-full">
|
|
122
124
|
<div className={cssClasses.container}>
|
|
123
125
|
<div className={panelCssClasses} aria-label="Chat Popup Panel">
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
{renderChat && (
|
|
127
|
+
<ChatPanel
|
|
128
|
+
{...props}
|
|
129
|
+
customCssClasses={cssClasses.panelCssClasses}
|
|
130
|
+
header={
|
|
131
|
+
<ChatHeader
|
|
132
|
+
title={title}
|
|
133
|
+
showRestartButton={showRestartButton}
|
|
134
|
+
showCloseButton={true}
|
|
135
|
+
onClose={onClose}
|
|
136
|
+
customCssClasses={cssClasses.headerCssClasses}
|
|
137
|
+
/>
|
|
138
|
+
}
|
|
139
|
+
/>
|
|
140
|
+
)}
|
|
137
141
|
</div>
|
|
138
142
|
<button
|
|
139
143
|
aria-label="Chat Popup Button"
|