@yext/chat-ui-react 0.7.3 → 0.8.1-alpha
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/README.md +10 -2
- package/lib/bundle.css +1 -1
- package/lib/commonjs/package.json.js +1 -1
- package/lib/commonjs/src/components/ChatInput.js +1 -1
- package/lib/commonjs/src/components/ChatPanel.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatPanel.js +7 -45
- package/lib/commonjs/src/components/ChatPanel.js.map +1 -1
- package/lib/commonjs/src/components/ChatPopUp.d.ts +31 -4
- package/lib/commonjs/src/components/ChatPopUp.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatPopUp.js +57 -10
- package/lib/commonjs/src/components/ChatPopUp.js.map +1 -1
- package/lib/commonjs/src/components/FeedbackButtons.d.ts +3 -4
- package/lib/commonjs/src/components/FeedbackButtons.d.ts.map +1 -1
- package/lib/commonjs/src/components/FeedbackButtons.js +2 -1
- package/lib/commonjs/src/components/FeedbackButtons.js.map +1 -1
- package/lib/commonjs/src/components/InitialMessagePopUp.d.ts +33 -0
- package/lib/commonjs/src/components/InitialMessagePopUp.d.ts.map +1 -0
- package/lib/commonjs/src/components/InitialMessagePopUp.js +44 -0
- package/lib/commonjs/src/components/InitialMessagePopUp.js.map +1 -0
- package/lib/commonjs/src/components/Markdown.d.ts +7 -3
- package/lib/commonjs/src/components/Markdown.d.ts.map +1 -1
- package/lib/commonjs/src/components/Markdown.js +1 -1
- package/lib/commonjs/src/components/Markdown.js.map +1 -1
- package/lib/commonjs/src/components/index.d.ts +5 -1
- package/lib/commonjs/src/components/index.d.ts.map +1 -1
- package/lib/commonjs/src/hooks/index.d.ts +4 -0
- package/lib/commonjs/src/hooks/index.d.ts.map +1 -1
- package/lib/commonjs/src/hooks/useDefaultHandleApiError.d.ts +1 -1
- package/lib/commonjs/src/hooks/useDefaultHandleApiError.js +1 -1
- package/lib/commonjs/src/hooks/useDefaultHandleApiError.js.map +1 -1
- package/lib/commonjs/src/hooks/useFetchInitialMessage.d.ts +13 -0
- package/lib/commonjs/src/hooks/useFetchInitialMessage.d.ts.map +1 -0
- package/lib/commonjs/src/hooks/useFetchInitialMessage.js +53 -0
- package/lib/commonjs/src/hooks/useFetchInitialMessage.js.map +1 -0
- package/lib/commonjs/src/hooks/useReportAnalyticsEvent.d.ts +1 -1
- package/lib/commonjs/src/hooks/useReportAnalyticsEvent.js +1 -1
- package/lib/commonjs/src/hooks/useReportAnalyticsEvent.js.map +1 -1
- package/lib/commonjs/src/hooks/useScrollToLastMessage.d.ts +15 -0
- package/lib/commonjs/src/hooks/useScrollToLastMessage.d.ts.map +1 -0
- package/lib/commonjs/src/hooks/useScrollToLastMessage.js +45 -0
- package/lib/commonjs/src/hooks/useScrollToLastMessage.js.map +1 -0
- package/lib/commonjs/src/index.js +12 -0
- package/lib/commonjs/src/index.js.map +1 -1
- package/lib/esm/index.d.ts +132 -4
- package/lib/esm/package.json.mjs +1 -1
- package/lib/esm/src/components/ChatInput.mjs +1 -1
- package/lib/esm/src/components/ChatPanel.d.ts.map +1 -1
- package/lib/esm/src/components/ChatPanel.mjs +9 -47
- package/lib/esm/src/components/ChatPanel.mjs.map +1 -1
- package/lib/esm/src/components/ChatPopUp.d.ts +31 -4
- package/lib/esm/src/components/ChatPopUp.d.ts.map +1 -1
- package/lib/esm/src/components/ChatPopUp.mjs +57 -10
- package/lib/esm/src/components/ChatPopUp.mjs.map +1 -1
- package/lib/esm/src/components/FeedbackButtons.d.ts +3 -4
- package/lib/esm/src/components/FeedbackButtons.d.ts.map +1 -1
- package/lib/esm/src/components/FeedbackButtons.mjs +2 -1
- package/lib/esm/src/components/FeedbackButtons.mjs.map +1 -1
- package/lib/esm/src/components/InitialMessagePopUp.d.ts +33 -0
- package/lib/esm/src/components/InitialMessagePopUp.d.ts.map +1 -0
- package/lib/esm/src/components/InitialMessagePopUp.mjs +38 -0
- package/lib/esm/src/components/InitialMessagePopUp.mjs.map +1 -0
- package/lib/esm/src/components/Markdown.d.ts +7 -3
- package/lib/esm/src/components/Markdown.d.ts.map +1 -1
- package/lib/esm/src/components/Markdown.mjs +1 -1
- package/lib/esm/src/components/Markdown.mjs.map +1 -1
- package/lib/esm/src/components/index.d.ts +5 -1
- package/lib/esm/src/components/index.d.ts.map +1 -1
- package/lib/esm/src/hooks/index.d.ts +4 -0
- package/lib/esm/src/hooks/index.d.ts.map +1 -1
- package/lib/esm/src/hooks/useDefaultHandleApiError.d.ts +1 -1
- package/lib/esm/src/hooks/useDefaultHandleApiError.mjs +1 -1
- package/lib/esm/src/hooks/useDefaultHandleApiError.mjs.map +1 -1
- package/lib/esm/src/hooks/useFetchInitialMessage.d.ts +13 -0
- package/lib/esm/src/hooks/useFetchInitialMessage.d.ts.map +1 -0
- package/lib/esm/src/hooks/useFetchInitialMessage.mjs +51 -0
- package/lib/esm/src/hooks/useFetchInitialMessage.mjs.map +1 -0
- package/lib/esm/src/hooks/useReportAnalyticsEvent.d.ts +1 -1
- package/lib/esm/src/hooks/useReportAnalyticsEvent.mjs +1 -1
- package/lib/esm/src/hooks/useReportAnalyticsEvent.mjs.map +1 -1
- package/lib/esm/src/hooks/useScrollToLastMessage.d.ts +15 -0
- package/lib/esm/src/hooks/useScrollToLastMessage.d.ts.map +1 -0
- package/lib/esm/src/hooks/useScrollToLastMessage.mjs +43 -0
- package/lib/esm/src/hooks/useScrollToLastMessage.mjs.map +1 -0
- package/lib/esm/src/index.mjs +6 -0
- package/lib/esm/src/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/ChatPanel.tsx +12 -56
- package/src/components/ChatPopUp.tsx +143 -21
- package/src/components/FeedbackButtons.tsx +3 -3
- package/src/components/InitialMessagePopUp.tsx +76 -0
- package/src/components/Markdown.tsx +7 -2
- package/src/components/index.ts +8 -2
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useDefaultHandleApiError.ts +1 -1
- package/src/hooks/useFetchInitialMessage.ts +58 -0
- package/src/hooks/useReportAnalyticsEvent.ts +1 -1
- package/src/hooks/useScrollToLastMessage.ts +47 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Returns a default handler function for API errors. It will log the error and
|
|
3
3
|
* add a default error message to state.
|
|
4
4
|
*
|
|
5
|
-
* @
|
|
5
|
+
* @public
|
|
6
6
|
*/
|
|
7
7
|
export declare function useDefaultHandleApiError(): (e: unknown) => void;
|
|
8
8
|
//# sourceMappingURL=useDefaultHandleApiError.d.ts.map
|
|
@@ -5,7 +5,7 @@ import { useCallback } from 'react';
|
|
|
5
5
|
* Returns a default handler function for API errors. It will log the error and
|
|
6
6
|
* add a default error message to state.
|
|
7
7
|
*
|
|
8
|
-
* @
|
|
8
|
+
* @public
|
|
9
9
|
*/
|
|
10
10
|
function useDefaultHandleApiError() {
|
|
11
11
|
const chat = useChatActions();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDefaultHandleApiError.mjs","sources":["../../../../src/hooks/useDefaultHandleApiError.ts"],"sourcesContent":["import { MessageSource, useChatActions } from \"@yext/chat-headless-react\";\nimport { useCallback } from \"react\";\n\n/**\n * Returns a default handler function for API errors. It will log the error and\n * add a default error message to state.\n *\n * @
|
|
1
|
+
{"version":3,"file":"useDefaultHandleApiError.mjs","sources":["../../../../src/hooks/useDefaultHandleApiError.ts"],"sourcesContent":["import { MessageSource, useChatActions } from \"@yext/chat-headless-react\";\nimport { useCallback } from \"react\";\n\n/**\n * Returns a default handler function for API errors. It will log the error and\n * add a default error message to state.\n *\n * @public\n */\nexport function useDefaultHandleApiError() {\n const chat = useChatActions();\n\n return useCallback(\n (e: unknown) => {\n console.error(e);\n chat.addMessage({\n text: \"Sorry, I'm unable to respond at the moment. Please try again later!\",\n source: MessageSource.BOT,\n timestamp: new Date().toISOString(),\n });\n },\n [chat]\n );\n}\n"],"names":[],"mappings":";;;AAGA;;;;;AAKG;SACa,wBAAwB,GAAA;AACtC,IAAA,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;AAE9B,IAAA,OAAO,WAAW,CAChB,CAAC,CAAU,KAAI;AACb,QAAA,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC,UAAU,CAAC;AACd,YAAA,IAAI,EAAE,qEAAqE;YAC3E,MAAM,EAAE,aAAa,CAAC,GAAG;AACzB,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACpC,SAAA,CAAC,CAAC;AACL,KAAC,EACD,CAAC,IAAI,CAAC,CACP,CAAC;AACJ;;;;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sends a request to Chat API to fetch the initial message when the
|
|
3
|
+
* conversation first start or when the message history is reset.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
6
|
+
*
|
|
7
|
+
* @param handleError - A function which is called when an error occurs while fetching for initial message.
|
|
8
|
+
* By default, the error is logged to the console and an error message is added to state.
|
|
9
|
+
* @param stream - Enable streaming behavior by making a request to Chat Streaming API. Defaults to false.
|
|
10
|
+
* @param customCondition - additional condition for when to fetch initial message
|
|
11
|
+
*/
|
|
12
|
+
export declare function useFetchInitialMessage(handleError?: (e: unknown) => void, stream?: boolean, customCondition?: boolean): void;
|
|
13
|
+
//# sourceMappingURL=useFetchInitialMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFetchInitialMessage.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useFetchInitialMessage.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EAClC,MAAM,UAAQ,EACd,eAAe,UAAO,QAuCvB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useChatActions, useChatState } from '@yext/chat-headless-react';
|
|
3
|
+
import { useDefaultHandleApiError } from './useDefaultHandleApiError.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sends a request to Chat API to fetch the initial message when the
|
|
7
|
+
* conversation first start or when the message history is reset.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*
|
|
11
|
+
* @param handleError - A function which is called when an error occurs while fetching for initial message.
|
|
12
|
+
* By default, the error is logged to the console and an error message is added to state.
|
|
13
|
+
* @param stream - Enable streaming behavior by making a request to Chat Streaming API. Defaults to false.
|
|
14
|
+
* @param customCondition - additional condition for when to fetch initial message
|
|
15
|
+
*/
|
|
16
|
+
function useFetchInitialMessage(handleError, stream = false, customCondition = true) {
|
|
17
|
+
const chat = useChatActions();
|
|
18
|
+
const defaultHandleApiError = useDefaultHandleApiError();
|
|
19
|
+
const messages = useChatState((state) => state.conversation.messages);
|
|
20
|
+
const [fetchInitialMessage, setFetchInitialMessage] = useState(messages.length === 0);
|
|
21
|
+
const [messagesLength, setMessagesLength] = useState(messages.length);
|
|
22
|
+
const canSendMessage = useChatState((state) => state.conversation.canSendMessage);
|
|
23
|
+
//handle message history resets
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const newMessagesLength = messages.length;
|
|
26
|
+
// Fetch data only when the conversation messages changes from non-zero to zero
|
|
27
|
+
if (messagesLength > 0 && newMessagesLength === 0) {
|
|
28
|
+
setFetchInitialMessage(true);
|
|
29
|
+
}
|
|
30
|
+
setMessagesLength(newMessagesLength);
|
|
31
|
+
}, [messages.length, messagesLength]);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (!fetchInitialMessage || !canSendMessage || !customCondition) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
setFetchInitialMessage(false);
|
|
37
|
+
const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
|
|
38
|
+
res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
|
|
39
|
+
}, [
|
|
40
|
+
chat,
|
|
41
|
+
stream,
|
|
42
|
+
handleError,
|
|
43
|
+
defaultHandleApiError,
|
|
44
|
+
fetchInitialMessage,
|
|
45
|
+
canSendMessage,
|
|
46
|
+
customCondition,
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { useFetchInitialMessage };
|
|
51
|
+
//# sourceMappingURL=useFetchInitialMessage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFetchInitialMessage.mjs","sources":["../../../../src/hooks/useFetchInitialMessage.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\n\n/**\n * Sends a request to Chat API to fetch the initial message when the\n * conversation first start or when the message history is reset.\n *\n * @public\n *\n * @param handleError - A function which is called when an error occurs while fetching for initial message.\n * By default, the error is logged to the console and an error message is added to state.\n * @param stream - Enable streaming behavior by making a request to Chat Streaming API. Defaults to false.\n * @param customCondition - additional condition for when to fetch initial message\n */\nexport function useFetchInitialMessage(\n handleError?: (e: unknown) => void,\n stream = false,\n customCondition = true\n) {\n const chat = useChatActions();\n const defaultHandleApiError = useDefaultHandleApiError();\n const messages = useChatState((state) => state.conversation.messages);\n const [fetchInitialMessage, setFetchInitialMessage] = useState(\n messages.length === 0\n );\n const [messagesLength, setMessagesLength] = useState(messages.length);\n const canSendMessage = useChatState(\n (state) => state.conversation.canSendMessage\n );\n\n //handle message history resets\n useEffect(() => {\n const newMessagesLength = messages.length;\n // Fetch data only when the conversation messages changes from non-zero to zero\n if (messagesLength > 0 && newMessagesLength === 0) {\n setFetchInitialMessage(true);\n }\n setMessagesLength(newMessagesLength);\n }, [messages.length, messagesLength]);\n\n useEffect(() => {\n if (!fetchInitialMessage || !canSendMessage || !customCondition) {\n return;\n }\n setFetchInitialMessage(false);\n const res = stream ? chat.streamNextMessage() : chat.getNextMessage();\n res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));\n }, [\n chat,\n stream,\n handleError,\n defaultHandleApiError,\n fetchInitialMessage,\n canSendMessage,\n customCondition,\n ]);\n}\n"],"names":[],"mappings":";;;;AAIA;;;;;;;;;;AAUG;AACG,SAAU,sBAAsB,CACpC,WAAkC,EAClC,MAAM,GAAG,KAAK,EACd,eAAe,GAAG,IAAI,EAAA;AAEtB,IAAA,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;AAC9B,IAAA,MAAM,qBAAqB,GAAG,wBAAwB,EAAE,CAAC;AACzD,IAAA,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AACtE,IAAA,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAC5D,QAAQ,CAAC,MAAM,KAAK,CAAC,CACtB,CAAC;AACF,IAAA,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACtE,IAAA,MAAM,cAAc,GAAG,YAAY,CACjC,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,CAAC,cAAc,CAC7C,CAAC;;IAGF,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC;;AAE1C,QAAA,IAAI,cAAc,GAAG,CAAC,IAAI,iBAAiB,KAAK,CAAC,EAAE;YACjD,sBAAsB,CAAC,IAAI,CAAC,CAAC;AAC9B,SAAA;QACD,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;KACtC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAEtC,SAAS,CAAC,MAAK;QACb,IAAI,CAAC,mBAAmB,IAAI,CAAC,cAAc,IAAI,CAAC,eAAe,EAAE;YAC/D,OAAO;AACR,SAAA;QACD,sBAAsB,CAAC,KAAK,CAAC,CAAC;AAC9B,QAAA,MAAM,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACtE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,KAAC,EAAE;QACD,IAAI;QACJ,MAAM;QACN,WAAW;QACX,qBAAqB;QACrB,mBAAmB;QACnB,cAAc;QACd,eAAe;AAChB,KAAA,CAAC,CAAC;AACL;;;;"}
|
|
@@ -4,7 +4,7 @@ import { ChatHeadless } from "@yext/chat-headless-react";
|
|
|
4
4
|
* The payload will automatically includes chat-ui-react's
|
|
5
5
|
* package version for "clientSdk" field.
|
|
6
6
|
*
|
|
7
|
-
* @
|
|
7
|
+
* @public
|
|
8
8
|
*/
|
|
9
9
|
export declare function useReportAnalyticsEvent(): ChatHeadless["report"];
|
|
10
10
|
//# sourceMappingURL=useReportAnalyticsEvent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReportAnalyticsEvent.mjs","sources":["../../../../src/hooks/useReportAnalyticsEvent.ts"],"sourcesContent":["import { ChatHeadless, useChatActions } from \"@yext/chat-headless-react\";\nimport { version } from \"../../package.json\";\nimport { useCallback } from \"react\";\n\n/**\n * Returns a function to send requests to Yext Analytics API.\n * The payload will automatically includes chat-ui-react's\n * package version for \"clientSdk\" field.\n *\n * @
|
|
1
|
+
{"version":3,"file":"useReportAnalyticsEvent.mjs","sources":["../../../../src/hooks/useReportAnalyticsEvent.ts"],"sourcesContent":["import { ChatHeadless, useChatActions } from \"@yext/chat-headless-react\";\nimport { version } from \"../../package.json\";\nimport { useCallback } from \"react\";\n\n/**\n * Returns a function to send requests to Yext Analytics API.\n * The payload will automatically includes chat-ui-react's\n * package version for \"clientSdk\" field.\n *\n * @public\n */\nexport function useReportAnalyticsEvent(): ChatHeadless[\"report\"] {\n const chat = useChatActions();\n chat.addClientSdk({\n CHAT_UI_REACT: version,\n });\n return useCallback((payload) => chat.report(payload), [chat]);\n}\n"],"names":[],"mappings":";;;;AAIA;;;;;;AAMG;SACa,uBAAuB,GAAA;AACrC,IAAA,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,IAAI,CAAC,YAAY,CAAC;AAChB,QAAA,aAAa,EAAE,OAAO;AACvB,KAAA,CAAC,CAAC;AACH,IAAA,OAAO,WAAW,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAChE;;;;"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Scroll the messsages container to the top of the last message whenever there's
|
|
4
|
+
* an update to the messages state.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*
|
|
8
|
+
* @returns a ref to set on the messages container element and
|
|
9
|
+
* a function to set ref on individual message element
|
|
10
|
+
*/
|
|
11
|
+
export declare function useScrollToLastMessage(): [
|
|
12
|
+
React.RefObject<HTMLDivElement>,
|
|
13
|
+
(index: number) => ((message: HTMLDivElement) => void) | undefined
|
|
14
|
+
];
|
|
15
|
+
//# sourceMappingURL=useScrollToLastMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollToLastMessage.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useScrollToLastMessage.ts"],"names":[],"mappings":"AACA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,IAAI;IACxC,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC;IAC/B,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS;CACnE,CA+BA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useChatState } from '@yext/chat-headless-react';
|
|
2
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Scroll the messsages container to the top of the last message whenever there's
|
|
6
|
+
* an update to the messages state.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*
|
|
10
|
+
* @returns a ref to set on the messages container element and
|
|
11
|
+
* a function to set ref on individual message element
|
|
12
|
+
*/
|
|
13
|
+
function useScrollToLastMessage() {
|
|
14
|
+
const messagesRef = useRef([]);
|
|
15
|
+
const messagesContainerRef = useRef(null);
|
|
16
|
+
const messages = useChatState((state) => state.conversation.messages);
|
|
17
|
+
// Handle scrolling when messages change
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let scrollTop = 0;
|
|
20
|
+
messagesRef.current = messagesRef.current.slice(0, messages.length);
|
|
21
|
+
// Sums up scroll heights of all messages except the last one
|
|
22
|
+
if (messagesRef?.current.length > 1) {
|
|
23
|
+
scrollTop = messagesRef.current
|
|
24
|
+
.slice(0, -1)
|
|
25
|
+
.map((elem, _) => elem?.scrollHeight ?? 0)
|
|
26
|
+
.reduce((total, height) => total + height);
|
|
27
|
+
}
|
|
28
|
+
// Scroll to the top of the last message
|
|
29
|
+
messagesContainerRef.current?.scroll({
|
|
30
|
+
top: scrollTop,
|
|
31
|
+
behavior: "smooth",
|
|
32
|
+
});
|
|
33
|
+
}, [messages]);
|
|
34
|
+
const setMessageRef = useCallback((index) => {
|
|
35
|
+
if (!messagesRef?.current)
|
|
36
|
+
return undefined;
|
|
37
|
+
return (message) => (messagesRef.current[index] = message);
|
|
38
|
+
}, []);
|
|
39
|
+
return [messagesContainerRef, setMessageRef];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { useScrollToLastMessage };
|
|
43
|
+
//# sourceMappingURL=useScrollToLastMessage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollToLastMessage.mjs","sources":["../../../../src/hooks/useScrollToLastMessage.ts"],"sourcesContent":["import { useChatState } from \"@yext/chat-headless-react\";\nimport React, { useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Scroll the messsages container to the top of the last message whenever there's\n * an update to the messages state.\n * \n * @public\n * \n * @returns a ref to set on the messages container element and\n * a function to set ref on individual message element\n */\nexport function useScrollToLastMessage(): [\n React.RefObject<HTMLDivElement>,\n (index: number) => ((message: HTMLDivElement) => void) | undefined\n] {\n const messagesRef = useRef<Array<HTMLDivElement | null>>([]);\n const messagesContainerRef = useRef<HTMLDivElement>(null);\n const messages = useChatState((state) => state.conversation.messages);\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 messagesContainerRef.current?.scroll({\n top: scrollTop,\n behavior: \"smooth\",\n });\n }, [messages]);\n\n const setMessageRef = useCallback((index) => {\n if (!messagesRef?.current) return undefined;\n return (message: HTMLDivElement) => (messagesRef.current[index] = message);\n }, []);\n\n return [messagesContainerRef, setMessageRef]\n}"],"names":[],"mappings":";;;AAGA;;;;;;;;AAQG;SACa,sBAAsB,GAAA;AAIpC,IAAA,MAAM,WAAW,GAAG,MAAM,CAA+B,EAAE,CAAC,CAAC;AAC7D,IAAA,MAAM,oBAAoB,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;AAC1D,IAAA,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;;IAGtE,SAAS,CAAC,MAAK;QACb,IAAI,SAAS,GAAG,CAAC,CAAC;AAClB,QAAA,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;;AAGpE,QAAA,IAAI,WAAW,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;YACnC,SAAS,GAAG,WAAW,CAAC,OAAO;AAC5B,iBAAA,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACZ,iBAAA,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,YAAY,IAAI,CAAC,CAAC;AACzC,iBAAA,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,CAAC,CAAC;AAC9C,SAAA;;AAGD,QAAA,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;AACnC,YAAA,GAAG,EAAE,SAAS;AACd,YAAA,QAAQ,EAAE,QAAQ;AACnB,SAAA,CAAC,CAAC;AACL,KAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AAEf,IAAA,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,KAAK,KAAI;QAC1C,IAAI,CAAC,WAAW,EAAE,OAAO;AAAE,YAAA,OAAO,SAAS,CAAC;AAC5C,QAAA,OAAO,CAAC,OAAuB,MAAM,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC;KAC5E,EAAE,EAAE,CAAC,CAAC;AAEP,IAAA,OAAO,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAA;AAC9C;;;;"}
|
package/lib/esm/src/index.mjs
CHANGED
|
@@ -3,5 +3,11 @@ export { ChatHeader } from './components/ChatHeader.mjs';
|
|
|
3
3
|
export { MessageBubble } from './components/MessageBubble.mjs';
|
|
4
4
|
export { ChatPanel } from './components/ChatPanel.mjs';
|
|
5
5
|
export { ChatPopUp } from './components/ChatPopUp.mjs';
|
|
6
|
+
export { FeedbackButtons } from './components/FeedbackButtons.mjs';
|
|
7
|
+
export { Markdown } from './components/Markdown.mjs';
|
|
6
8
|
export { useComposedCssClasses } from './hooks/useComposedCssClasses.mjs';
|
|
9
|
+
export { useDefaultHandleApiError } from './hooks/useDefaultHandleApiError.mjs';
|
|
10
|
+
export { useFetchInitialMessage } from './hooks/useFetchInitialMessage.mjs';
|
|
11
|
+
export { useReportAnalyticsEvent } from './hooks/useReportAnalyticsEvent.mjs';
|
|
12
|
+
export { useScrollToLastMessage } from './hooks/useScrollToLastMessage.mjs';
|
|
7
13
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yext/chat-ui-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1-alpha",
|
|
4
4
|
"description": "A library of React Components for powering Yext Chat integrations.",
|
|
5
5
|
"author": "clippy@yext.com",
|
|
6
6
|
"main": "./lib/commonjs/src/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"lint": "prettier --write . && eslint --fix --max-warnings=0 .",
|
|
34
34
|
"test": "jest --config=jest.config.json",
|
|
35
35
|
"storybook": "storybook dev -p 6006",
|
|
36
|
-
"dev": "
|
|
36
|
+
"dev": "rollup --watch --config rollup.config.mjs",
|
|
37
37
|
"generate-docs": "api-extractor run --local --verbose && api-documenter markdown --input-folder temp --output-folder docs && rm -rf temp",
|
|
38
38
|
"generate-notices": "generate-license-file --input package.json --output ./THIRD-PARTY-NOTICES --overwrite",
|
|
39
39
|
"postcss": "postcss",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import { useChatState
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useChatState } from "@yext/chat-headless-react";
|
|
3
3
|
import {
|
|
4
4
|
MessageBubble,
|
|
5
5
|
MessageBubbleCssClasses,
|
|
@@ -7,10 +7,13 @@ import {
|
|
|
7
7
|
} from "./MessageBubble";
|
|
8
8
|
import { ChatInput, ChatInputCssClasses, ChatInputProps } from "./ChatInput";
|
|
9
9
|
import { LoadingDots } from "./LoadingDots";
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
useComposedCssClasses,
|
|
12
|
+
useReportAnalyticsEvent,
|
|
13
|
+
useFetchInitialMessage,
|
|
14
|
+
useScrollToLastMessage,
|
|
15
|
+
} from "../hooks";
|
|
12
16
|
import { withStylelessCssClasses } from "../utils/withStylelessCssClasses";
|
|
13
|
-
import { useReportAnalyticsEvent } from "../hooks/useReportAnalyticsEvent";
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* The CSS class interface for the {@link ChatPanel} component.
|
|
@@ -66,16 +69,12 @@ export interface ChatPanelProps
|
|
|
66
69
|
*/
|
|
67
70
|
export function ChatPanel(props: ChatPanelProps) {
|
|
68
71
|
const { header, customCssClasses, stream, handleError } = props;
|
|
69
|
-
const chat = useChatActions();
|
|
70
72
|
const messages = useChatState((state) => state.conversation.messages);
|
|
71
73
|
const loading = useChatState((state) => state.conversation.isLoading);
|
|
72
|
-
const canSendMessage = useChatState(
|
|
73
|
-
(state) => state.conversation.canSendMessage
|
|
74
|
-
);
|
|
75
74
|
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
76
|
-
const defaultHandleApiError = useDefaultHandleApiError();
|
|
77
75
|
const reportAnalyticsEvent = useReportAnalyticsEvent();
|
|
78
|
-
|
|
76
|
+
useFetchInitialMessage(handleError, stream);
|
|
77
|
+
const [messagesContainerRef, setMessageRef] = useScrollToLastMessage();
|
|
79
78
|
|
|
80
79
|
useEffect(() => {
|
|
81
80
|
reportAnalyticsEvent({
|
|
@@ -83,57 +82,14 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
83
82
|
});
|
|
84
83
|
}, [reportAnalyticsEvent]);
|
|
85
84
|
|
|
86
|
-
// Request initial message only if there are no existing messages and no ongoing request.
|
|
87
|
-
useEffect(() => {
|
|
88
|
-
setFetchInitialMessage(messages.length === 0 && canSendMessage);
|
|
89
|
-
}, [messages.length, canSendMessage]);
|
|
90
|
-
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
if (!fetchInitialMessage) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
// Ensures that the fetch for the initial message occurs only once
|
|
96
|
-
setFetchInitialMessage(false);
|
|
97
|
-
const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
|
|
98
|
-
res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
|
|
99
|
-
}, [chat, stream, handleError, defaultHandleApiError, fetchInitialMessage]);
|
|
100
|
-
|
|
101
|
-
const messagesRef = useRef<Array<HTMLDivElement | null>>([]);
|
|
102
|
-
const messagesContainer = useRef<HTMLDivElement>(null);
|
|
103
|
-
|
|
104
|
-
// Handle scrolling when messages change
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
let scrollTop = 0;
|
|
107
|
-
messagesRef.current = messagesRef.current.slice(0, messages.length);
|
|
108
|
-
|
|
109
|
-
// Sums up scroll heights of all messages except the last one
|
|
110
|
-
if (messagesRef?.current.length > 1) {
|
|
111
|
-
scrollTop = messagesRef.current
|
|
112
|
-
.slice(0, -1)
|
|
113
|
-
.map((elem, _) => elem?.scrollHeight ?? 0)
|
|
114
|
-
.reduce((total, height) => total + height);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Scroll to the top of the last message
|
|
118
|
-
messagesContainer.current?.scroll({
|
|
119
|
-
top: scrollTop,
|
|
120
|
-
behavior: "smooth",
|
|
121
|
-
});
|
|
122
|
-
}, [messages]);
|
|
123
|
-
|
|
124
|
-
const setMessagesRef = useCallback((index) => {
|
|
125
|
-
if (!messagesRef?.current) return null;
|
|
126
|
-
return (message) => (messagesRef.current[index] = message);
|
|
127
|
-
}, []);
|
|
128
|
-
|
|
129
85
|
return (
|
|
130
86
|
<div className="yext-chat w-full h-full">
|
|
131
87
|
<div className={cssClasses.container}>
|
|
132
88
|
{header}
|
|
133
89
|
<div className={cssClasses.messagesScrollContainer}>
|
|
134
|
-
<div ref={
|
|
90
|
+
<div ref={messagesContainerRef} className={cssClasses.messagesContainer}>
|
|
135
91
|
{messages.map((message, index) => (
|
|
136
|
-
<div key={index} ref={
|
|
92
|
+
<div key={index} ref={setMessageRef(index)}>
|
|
137
93
|
<MessageBubble
|
|
138
94
|
{...props}
|
|
139
95
|
customCssClasses={cssClasses.messageBubbleCssClasses}
|
|
@@ -10,6 +10,12 @@ import { twMerge } from "tailwind-merge";
|
|
|
10
10
|
import { useComposedCssClasses } from "../hooks";
|
|
11
11
|
import { withStylelessCssClasses } from "../utils/withStylelessCssClasses";
|
|
12
12
|
import { useReportAnalyticsEvent } from "../hooks/useReportAnalyticsEvent";
|
|
13
|
+
import {
|
|
14
|
+
InitialMessagePopUp,
|
|
15
|
+
InitialMessagePopUpCssClasses,
|
|
16
|
+
} from "./InitialMessagePopUp";
|
|
17
|
+
import { useChatState } from "@yext/chat-headless-react";
|
|
18
|
+
import { useFetchInitialMessage } from "../hooks/useFetchInitialMessage";
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* The CSS class interface for the {@link ChatPopUp} component.
|
|
@@ -22,11 +28,16 @@ export interface ChatPopUpCssClasses {
|
|
|
22
28
|
panel__display?: string;
|
|
23
29
|
panel__hidden?: string;
|
|
24
30
|
button?: string;
|
|
25
|
-
button__display?: string;
|
|
26
|
-
button__hidden?: string;
|
|
27
31
|
buttonIcon?: string;
|
|
32
|
+
ctaLabelContainer?: string;
|
|
33
|
+
ctaLabel?: string;
|
|
34
|
+
notification?: string;
|
|
35
|
+
closedPopupContainer?: string;
|
|
36
|
+
closedPopupContainer__display?: string;
|
|
37
|
+
closedPopupContainer__hidden?: string;
|
|
28
38
|
headerCssClasses?: ChatHeaderCssClasses;
|
|
29
39
|
panelCssClasses?: ChatPanelCssClasses;
|
|
40
|
+
initialMessagePopUpCssClasses?: InitialMessagePopUpCssClasses;
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
const fixedPosition = "fixed bottom-6 right-4 lg:bottom-14 lg:right-10 z-50 ";
|
|
@@ -39,13 +50,20 @@ const builtInCssClasses: ChatPopUpCssClasses = withStylelessCssClasses(
|
|
|
39
50
|
"w-80 max-[480px]:right-0 max-[480px]:bottom-0 max-[480px]:w-full max-[480px]:h-full lg:w-96 h-[75vh]",
|
|
40
51
|
panel__display: "duration-300 translate-y-0",
|
|
41
52
|
panel__hidden: "duration-300 translate-y-[20%] opacity-0 invisible",
|
|
42
|
-
|
|
53
|
+
closedPopupContainer:
|
|
43
54
|
fixedPosition +
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
"flex gap-x-2.5 items-center hover:-translate-y-2 duration-150",
|
|
56
|
+
closedPopupContainer__display: "duration-300 transform translate-y-0",
|
|
57
|
+
closedPopupContainer__hidden:
|
|
47
58
|
"duration-300 transform translate-y-[20%] opacity-0 invisible",
|
|
59
|
+
button:
|
|
60
|
+
"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",
|
|
48
61
|
buttonIcon: "text-blue-600 w-[28px] h-[28px] lg:w-[40px] lg:h-[40px]",
|
|
62
|
+
ctaLabelContainer: "max-w-60 -mr-8 line-clamp-1",
|
|
63
|
+
ctaLabel:
|
|
64
|
+
"p-3 pr-8 flex items-center whitespace-nowrap animate-expand-left font-bold rounded-l-full bg-white text-blue-700 h-10 lg:h-14 text-sm lg:text-base",
|
|
65
|
+
notification:
|
|
66
|
+
"fixed animate-fade-in bg-red-700 -right-1 top-0 rounded-full w-5 lg:w-6 h-5 lg:h-6 items-center flex justify-center text-sm lg:text-base text-white",
|
|
49
67
|
headerCssClasses: {
|
|
50
68
|
container: "max-[480px]:rounded-none rounded-t-3xl",
|
|
51
69
|
},
|
|
@@ -67,10 +85,31 @@ export interface ChatPopUpProps
|
|
|
67
85
|
Omit<ChatPanelProps, "header" | "customCssClasses"> {
|
|
68
86
|
/** Custom icon for the popup button to open the panel. */
|
|
69
87
|
openPanelButtonIcon?: JSX.Element;
|
|
88
|
+
/** CSS classes for customizing the component styling. */
|
|
89
|
+
customCssClasses?: ChatPopUpCssClasses;
|
|
90
|
+
/** Whether to show the panel on load. Defaults to false. */
|
|
91
|
+
openOnLoad?: boolean;
|
|
70
92
|
/**
|
|
71
|
-
*
|
|
93
|
+
* Whether to show the initial message popup when the panel is hidden on load.
|
|
94
|
+
* Defaults to false.
|
|
72
95
|
*/
|
|
73
|
-
|
|
96
|
+
showInitialMessagePopUp?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Whether to show a heartbeat animation on the popup button when the panel is hidden.
|
|
99
|
+
* Defaults to false.
|
|
100
|
+
*/
|
|
101
|
+
showHeartBeatAnimation?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Whether to show notification showing number of unread messages.
|
|
104
|
+
* Defaults to false.
|
|
105
|
+
*/
|
|
106
|
+
showUnreadNotification?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* The "Call to Action" label to be displayed next to the popup button.
|
|
109
|
+
* By default, the CTA is not shown.
|
|
110
|
+
* This prop will override the "showInitialMessagePopUp" prop, if specified.
|
|
111
|
+
*/
|
|
112
|
+
ctaLabel?: string;
|
|
74
113
|
}
|
|
75
114
|
|
|
76
115
|
/**
|
|
@@ -87,36 +126,85 @@ export function ChatPopUp(props: ChatPopUpProps) {
|
|
|
87
126
|
customCssClasses,
|
|
88
127
|
showRestartButton = true,
|
|
89
128
|
onClose: customOnClose,
|
|
129
|
+
handleError,
|
|
130
|
+
openOnLoad = false,
|
|
131
|
+
showInitialMessagePopUp = false,
|
|
132
|
+
showHeartBeatAnimation = false,
|
|
133
|
+
showUnreadNotification = false,
|
|
134
|
+
ctaLabel,
|
|
90
135
|
title,
|
|
91
136
|
} = props;
|
|
92
|
-
const reportAnalyticsEvent = useReportAnalyticsEvent();
|
|
93
137
|
|
|
138
|
+
const reportAnalyticsEvent = useReportAnalyticsEvent();
|
|
94
139
|
useEffect(() => {
|
|
95
140
|
reportAnalyticsEvent({
|
|
96
141
|
action: "CHAT_IMPRESSION",
|
|
97
142
|
});
|
|
98
143
|
}, [reportAnalyticsEvent]);
|
|
99
144
|
|
|
100
|
-
const
|
|
145
|
+
const messages = useChatState((s) => s.conversation.messages);
|
|
146
|
+
const [numReadMessages, setNumReadMessagesLength] = useState<number>(0);
|
|
147
|
+
const [numUnreadMessages, setNumUnreadMessagesLength] = useState<number>(0);
|
|
148
|
+
|
|
149
|
+
useFetchInitialMessage(
|
|
150
|
+
showInitialMessagePopUp ? console.error : handleError,
|
|
151
|
+
false,
|
|
152
|
+
showUnreadNotification || showInitialMessagePopUp
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const [showInitialMessage, setshowInitialMessage] = useState(
|
|
156
|
+
//only show initial message popup (if specified) when CTA label is not provided
|
|
157
|
+
!ctaLabel && showInitialMessagePopUp
|
|
158
|
+
);
|
|
159
|
+
const onCloseInitialMessage = useCallback(() => {
|
|
160
|
+
setshowInitialMessage(false);
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
163
|
+
// control CSS behavior on open/close state of the panel
|
|
101
164
|
const [showChat, setShowChat] = useState(false);
|
|
165
|
+
|
|
166
|
+
// control the actual DOM rendering of the panel. Start rendering on first open state
|
|
167
|
+
// to avoid message requests immediately on load while the popup is still "hidden"
|
|
168
|
+
const [renderChat, setRenderChat] = useState(false);
|
|
169
|
+
|
|
170
|
+
// update in useEffect, instead of having openOnLoad as initial state for show/renderChat,
|
|
171
|
+
// in order to maintain the fade-in CSS animation when opening the panel on load
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (openOnLoad) {
|
|
174
|
+
setShowChat(true);
|
|
175
|
+
setRenderChat(true);
|
|
176
|
+
setshowInitialMessage(false);
|
|
177
|
+
}
|
|
178
|
+
}, [openOnLoad]);
|
|
179
|
+
|
|
102
180
|
const onClick = useCallback(() => {
|
|
103
181
|
setShowChat(!showChat);
|
|
104
182
|
setRenderChat(true);
|
|
183
|
+
setshowInitialMessage(false);
|
|
105
184
|
}, [showChat]);
|
|
106
185
|
|
|
107
186
|
const onClose = useCallback(() => {
|
|
108
187
|
setShowChat(false);
|
|
109
188
|
customOnClose?.();
|
|
110
|
-
|
|
189
|
+
// consider all the messages are read while the panel was open
|
|
190
|
+
setNumReadMessagesLength(messages.length);
|
|
191
|
+
}, [customOnClose, messages]);
|
|
192
|
+
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
//update number of unread messages if there are new messages added while the panel is closed
|
|
195
|
+
setNumUnreadMessagesLength(messages.length - numReadMessages);
|
|
196
|
+
}, [messages, numReadMessages]);
|
|
111
197
|
|
|
112
198
|
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
113
199
|
const panelCssClasses = twMerge(
|
|
114
200
|
cssClasses.panel,
|
|
115
201
|
showChat ? cssClasses.panel__display : cssClasses.panel__hidden
|
|
116
202
|
);
|
|
117
|
-
const
|
|
118
|
-
cssClasses.
|
|
119
|
-
showChat
|
|
203
|
+
const closedPopupContainerCssClasses = twMerge(
|
|
204
|
+
cssClasses.closedPopupContainer,
|
|
205
|
+
showChat
|
|
206
|
+
? cssClasses.closedPopupContainer__hidden
|
|
207
|
+
: cssClasses.closedPopupContainer__display
|
|
120
208
|
);
|
|
121
209
|
|
|
122
210
|
return (
|
|
@@ -139,15 +227,49 @@ export function ChatPopUp(props: ChatPopUpProps) {
|
|
|
139
227
|
/>
|
|
140
228
|
)}
|
|
141
229
|
</div>
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
className={buttonCssClasses}
|
|
230
|
+
<div
|
|
231
|
+
className={closedPopupContainerCssClasses}
|
|
232
|
+
aria-label="Chat Closed Popup Container"
|
|
146
233
|
>
|
|
147
|
-
{
|
|
148
|
-
<
|
|
234
|
+
{showInitialMessage && (
|
|
235
|
+
<InitialMessagePopUp
|
|
236
|
+
onClose={onCloseInitialMessage}
|
|
237
|
+
customCssClasses={cssClasses.initialMessagePopUpCssClasses}
|
|
238
|
+
/>
|
|
239
|
+
)}
|
|
240
|
+
{ctaLabel && (
|
|
241
|
+
// the div container is needed to islate the expand CSS animation
|
|
242
|
+
<div className={cssClasses.ctaLabelContainer}>
|
|
243
|
+
<button
|
|
244
|
+
onClick={onClick}
|
|
245
|
+
aria-label="CTA Label"
|
|
246
|
+
className={cssClasses.ctaLabel}
|
|
247
|
+
>
|
|
248
|
+
{ctaLabel}
|
|
249
|
+
</button>
|
|
250
|
+
</div>
|
|
149
251
|
)}
|
|
150
|
-
|
|
252
|
+
<button
|
|
253
|
+
aria-label="Chat Popup Button"
|
|
254
|
+
onClick={onClick}
|
|
255
|
+
className={
|
|
256
|
+
cssClasses.button +
|
|
257
|
+
(showHeartBeatAnimation ? " animate-heartbeat" : "")
|
|
258
|
+
}
|
|
259
|
+
>
|
|
260
|
+
{openPanelButtonIcon ?? (
|
|
261
|
+
<ChatIcon className={cssClasses.buttonIcon} />
|
|
262
|
+
)}
|
|
263
|
+
{showUnreadNotification && !!numUnreadMessages && (
|
|
264
|
+
<div
|
|
265
|
+
aria-label="Unread Messages Notification"
|
|
266
|
+
className={cssClasses.notification}
|
|
267
|
+
>
|
|
268
|
+
{numUnreadMessages}
|
|
269
|
+
</div>
|
|
270
|
+
)}
|
|
271
|
+
</button>
|
|
272
|
+
</div>
|
|
151
273
|
</div>
|
|
152
274
|
</div>
|
|
153
275
|
);
|
|
@@ -39,9 +39,9 @@ const builtInCssClasses: FeedbackButtonsCssClasses =
|
|
|
39
39
|
/**
|
|
40
40
|
* The props for the FeedbackButtons component.
|
|
41
41
|
*
|
|
42
|
-
* @
|
|
42
|
+
* @public
|
|
43
43
|
*/
|
|
44
|
-
interface FeedbackButtonsProps {
|
|
44
|
+
export interface FeedbackButtonsProps {
|
|
45
45
|
/** The response ID correlates to the current message to give feedback on. */
|
|
46
46
|
responseId?: string;
|
|
47
47
|
/** CSS classes for customizing the component styling. */
|
|
@@ -52,7 +52,7 @@ interface FeedbackButtonsProps {
|
|
|
52
52
|
* Displays feedback buttons (e.g. thumbs up and thumbs down) that will
|
|
53
53
|
* report analytic events on click.
|
|
54
54
|
*
|
|
55
|
-
* @
|
|
55
|
+
* @public
|
|
56
56
|
*/
|
|
57
57
|
export function FeedbackButtons({
|
|
58
58
|
customCssClasses,
|