@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.
Files changed (97) hide show
  1. package/README.md +10 -2
  2. package/lib/bundle.css +1 -1
  3. package/lib/commonjs/package.json.js +1 -1
  4. package/lib/commonjs/src/components/ChatInput.js +1 -1
  5. package/lib/commonjs/src/components/ChatPanel.d.ts.map +1 -1
  6. package/lib/commonjs/src/components/ChatPanel.js +7 -45
  7. package/lib/commonjs/src/components/ChatPanel.js.map +1 -1
  8. package/lib/commonjs/src/components/ChatPopUp.d.ts +31 -4
  9. package/lib/commonjs/src/components/ChatPopUp.d.ts.map +1 -1
  10. package/lib/commonjs/src/components/ChatPopUp.js +57 -10
  11. package/lib/commonjs/src/components/ChatPopUp.js.map +1 -1
  12. package/lib/commonjs/src/components/FeedbackButtons.d.ts +3 -4
  13. package/lib/commonjs/src/components/FeedbackButtons.d.ts.map +1 -1
  14. package/lib/commonjs/src/components/FeedbackButtons.js +2 -1
  15. package/lib/commonjs/src/components/FeedbackButtons.js.map +1 -1
  16. package/lib/commonjs/src/components/InitialMessagePopUp.d.ts +33 -0
  17. package/lib/commonjs/src/components/InitialMessagePopUp.d.ts.map +1 -0
  18. package/lib/commonjs/src/components/InitialMessagePopUp.js +44 -0
  19. package/lib/commonjs/src/components/InitialMessagePopUp.js.map +1 -0
  20. package/lib/commonjs/src/components/Markdown.d.ts +7 -3
  21. package/lib/commonjs/src/components/Markdown.d.ts.map +1 -1
  22. package/lib/commonjs/src/components/Markdown.js +1 -1
  23. package/lib/commonjs/src/components/Markdown.js.map +1 -1
  24. package/lib/commonjs/src/components/index.d.ts +5 -1
  25. package/lib/commonjs/src/components/index.d.ts.map +1 -1
  26. package/lib/commonjs/src/hooks/index.d.ts +4 -0
  27. package/lib/commonjs/src/hooks/index.d.ts.map +1 -1
  28. package/lib/commonjs/src/hooks/useDefaultHandleApiError.d.ts +1 -1
  29. package/lib/commonjs/src/hooks/useDefaultHandleApiError.js +1 -1
  30. package/lib/commonjs/src/hooks/useDefaultHandleApiError.js.map +1 -1
  31. package/lib/commonjs/src/hooks/useFetchInitialMessage.d.ts +13 -0
  32. package/lib/commonjs/src/hooks/useFetchInitialMessage.d.ts.map +1 -0
  33. package/lib/commonjs/src/hooks/useFetchInitialMessage.js +53 -0
  34. package/lib/commonjs/src/hooks/useFetchInitialMessage.js.map +1 -0
  35. package/lib/commonjs/src/hooks/useReportAnalyticsEvent.d.ts +1 -1
  36. package/lib/commonjs/src/hooks/useReportAnalyticsEvent.js +1 -1
  37. package/lib/commonjs/src/hooks/useReportAnalyticsEvent.js.map +1 -1
  38. package/lib/commonjs/src/hooks/useScrollToLastMessage.d.ts +15 -0
  39. package/lib/commonjs/src/hooks/useScrollToLastMessage.d.ts.map +1 -0
  40. package/lib/commonjs/src/hooks/useScrollToLastMessage.js +45 -0
  41. package/lib/commonjs/src/hooks/useScrollToLastMessage.js.map +1 -0
  42. package/lib/commonjs/src/index.js +12 -0
  43. package/lib/commonjs/src/index.js.map +1 -1
  44. package/lib/esm/index.d.ts +132 -4
  45. package/lib/esm/package.json.mjs +1 -1
  46. package/lib/esm/src/components/ChatInput.mjs +1 -1
  47. package/lib/esm/src/components/ChatPanel.d.ts.map +1 -1
  48. package/lib/esm/src/components/ChatPanel.mjs +9 -47
  49. package/lib/esm/src/components/ChatPanel.mjs.map +1 -1
  50. package/lib/esm/src/components/ChatPopUp.d.ts +31 -4
  51. package/lib/esm/src/components/ChatPopUp.d.ts.map +1 -1
  52. package/lib/esm/src/components/ChatPopUp.mjs +57 -10
  53. package/lib/esm/src/components/ChatPopUp.mjs.map +1 -1
  54. package/lib/esm/src/components/FeedbackButtons.d.ts +3 -4
  55. package/lib/esm/src/components/FeedbackButtons.d.ts.map +1 -1
  56. package/lib/esm/src/components/FeedbackButtons.mjs +2 -1
  57. package/lib/esm/src/components/FeedbackButtons.mjs.map +1 -1
  58. package/lib/esm/src/components/InitialMessagePopUp.d.ts +33 -0
  59. package/lib/esm/src/components/InitialMessagePopUp.d.ts.map +1 -0
  60. package/lib/esm/src/components/InitialMessagePopUp.mjs +38 -0
  61. package/lib/esm/src/components/InitialMessagePopUp.mjs.map +1 -0
  62. package/lib/esm/src/components/Markdown.d.ts +7 -3
  63. package/lib/esm/src/components/Markdown.d.ts.map +1 -1
  64. package/lib/esm/src/components/Markdown.mjs +1 -1
  65. package/lib/esm/src/components/Markdown.mjs.map +1 -1
  66. package/lib/esm/src/components/index.d.ts +5 -1
  67. package/lib/esm/src/components/index.d.ts.map +1 -1
  68. package/lib/esm/src/hooks/index.d.ts +4 -0
  69. package/lib/esm/src/hooks/index.d.ts.map +1 -1
  70. package/lib/esm/src/hooks/useDefaultHandleApiError.d.ts +1 -1
  71. package/lib/esm/src/hooks/useDefaultHandleApiError.mjs +1 -1
  72. package/lib/esm/src/hooks/useDefaultHandleApiError.mjs.map +1 -1
  73. package/lib/esm/src/hooks/useFetchInitialMessage.d.ts +13 -0
  74. package/lib/esm/src/hooks/useFetchInitialMessage.d.ts.map +1 -0
  75. package/lib/esm/src/hooks/useFetchInitialMessage.mjs +51 -0
  76. package/lib/esm/src/hooks/useFetchInitialMessage.mjs.map +1 -0
  77. package/lib/esm/src/hooks/useReportAnalyticsEvent.d.ts +1 -1
  78. package/lib/esm/src/hooks/useReportAnalyticsEvent.mjs +1 -1
  79. package/lib/esm/src/hooks/useReportAnalyticsEvent.mjs.map +1 -1
  80. package/lib/esm/src/hooks/useScrollToLastMessage.d.ts +15 -0
  81. package/lib/esm/src/hooks/useScrollToLastMessage.d.ts.map +1 -0
  82. package/lib/esm/src/hooks/useScrollToLastMessage.mjs +43 -0
  83. package/lib/esm/src/hooks/useScrollToLastMessage.mjs.map +1 -0
  84. package/lib/esm/src/index.mjs +6 -0
  85. package/lib/esm/src/index.mjs.map +1 -1
  86. package/package.json +2 -2
  87. package/src/components/ChatPanel.tsx +12 -56
  88. package/src/components/ChatPopUp.tsx +143 -21
  89. package/src/components/FeedbackButtons.tsx +3 -3
  90. package/src/components/InitialMessagePopUp.tsx +76 -0
  91. package/src/components/Markdown.tsx +7 -2
  92. package/src/components/index.ts +8 -2
  93. package/src/hooks/index.ts +4 -0
  94. package/src/hooks/useDefaultHandleApiError.ts +1 -1
  95. package/src/hooks/useFetchInitialMessage.ts +58 -0
  96. package/src/hooks/useReportAnalyticsEvent.ts +1 -1
  97. package/src/hooks/useScrollToLastMessage.ts +47 -0
@@ -0,0 +1,76 @@
1
+ import React, { useMemo } from "react";
2
+ import { CrossIcon } from "../icons/Cross";
3
+ import { useComposedCssClasses } from "../hooks";
4
+ import { withStylelessCssClasses } from "../utils/withStylelessCssClasses";
5
+ import { MessageSource, useChatState } from "@yext/chat-headless-react";
6
+
7
+ /**
8
+ * The CSS class interface for the InitialMessagePopUp component.
9
+ *
10
+ * @public
11
+ */
12
+ export interface InitialMessagePopUpCssClasses {
13
+ container?: string;
14
+ closeButton?: string;
15
+ closeButtonIcon?: string;
16
+ message?: string;
17
+ }
18
+
19
+ /**
20
+ * The props for the {@link InitialMessagePopUp} component.
21
+ *
22
+ * @internal
23
+ */
24
+ interface InitialMessagePopUpProps {
25
+ /** CSS classes for customizing the component styling. */
26
+ customCssClasses?: InitialMessagePopUpCssClasses;
27
+ /** Function to call when user click on the close button */
28
+ onClose: () => void;
29
+ }
30
+
31
+ const builtInCssClasses: InitialMessagePopUpCssClasses =
32
+ withStylelessCssClasses("InitialMessagePopUp", {
33
+ container: "flex gap-x-1 animate-fade-in",
34
+ closeButton: "bg-white w-4 h-4 rounded-full border border-slate-300",
35
+ closeButtonIcon: "",
36
+ message:
37
+ "line-clamp-2 w-60 p-2.5 bg-white rounded-xl shadow-xl text-sm lg:text-base",
38
+ });
39
+
40
+ /**
41
+ * A component that renders a popup bubble displaying the initial message from chat bot.
42
+ *
43
+ * @internal
44
+ *
45
+ * @param props - {@link InitialMessagePopUpProps}
46
+ */
47
+ export function InitialMessagePopUp({
48
+ onClose,
49
+ customCssClasses,
50
+ }: InitialMessagePopUpProps) {
51
+ const messages = useChatState((s) => s.conversation.messages);
52
+ const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
53
+
54
+ const firstBotMessage: string = useMemo(() => {
55
+ return messages.length !== 0 && messages[0].source === MessageSource.BOT
56
+ ? messages[0].text
57
+ : "";
58
+ }, [messages]);
59
+
60
+ if (firstBotMessage.length === 0) {
61
+ return <></>;
62
+ }
63
+
64
+ return (
65
+ <div className={cssClasses.container}>
66
+ <button
67
+ aria-label="Close Initial Message"
68
+ onClick={onClose}
69
+ className={cssClasses.closeButton}
70
+ >
71
+ <CrossIcon className={cssClasses.closeButtonIcon} />
72
+ </button>
73
+ <div className={cssClasses.message}>{firstBotMessage}</div>
74
+ </div>
75
+ );
76
+ }
@@ -19,7 +19,12 @@ const unifiedPlugins: { remark?: PluggableList; rehype: PluggableList } = {
19
19
  ],
20
20
  };
21
21
 
22
- interface MarkdownProps {
22
+ /**
23
+ * The props for the {@link Markdown} component.
24
+ *
25
+ * @public
26
+ */
27
+ export interface MarkdownProps {
23
28
  /** Stringified markdown. */
24
29
  content: string;
25
30
  /** The response ID correlates to the current message. */
@@ -35,7 +40,7 @@ interface MarkdownProps {
35
40
  * @remarks
36
41
  * A link click will send a CHAT_LINK_CLICK analytics event
37
42
  *
38
- * @internal
43
+ * @public
39
44
  */
40
45
  export function Markdown({ content, responseId, className }: MarkdownProps) {
41
46
  const reportAnalyticsEvent = useReportAnalyticsEvent();
@@ -10,10 +10,16 @@ export type {
10
10
  MessageBubbleProps,
11
11
  } from "./MessageBubble";
12
12
 
13
- export type { FeedbackButtonsCssClasses } from "./FeedbackButtons";
14
-
15
13
  export { ChatPanel } from "./ChatPanel";
16
14
  export type { ChatPanelCssClasses, ChatPanelProps } from "./ChatPanel";
17
15
 
18
16
  export { ChatPopUp } from "./ChatPopUp";
19
17
  export type { ChatPopUpCssClasses, ChatPopUpProps } from "./ChatPopUp";
18
+
19
+ export { FeedbackButtons } from "./FeedbackButtons";
20
+ export type { FeedbackButtonsCssClasses, FeedbackButtonsProps } from "./FeedbackButtons";
21
+
22
+ export { Markdown } from "./Markdown";
23
+ export { MarkdownProps } from "./Markdown";
24
+
25
+ export type { InitialMessagePopUpCssClasses } from "./InitialMessagePopUp";
@@ -1 +1,5 @@
1
1
  export { useComposedCssClasses } from "./useComposedCssClasses";
2
+ export { useDefaultHandleApiError } from "./useDefaultHandleApiError";
3
+ export { useFetchInitialMessage } from "./useFetchInitialMessage";
4
+ export { useReportAnalyticsEvent } from "./useReportAnalyticsEvent";
5
+ export { useScrollToLastMessage } from "./useScrollToLastMessage";
@@ -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
- * @internal
8
+ * @public
9
9
  */
10
10
  export function useDefaultHandleApiError() {
11
11
  const chat = useChatActions();
@@ -0,0 +1,58 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useChatState, useChatActions } from "@yext/chat-headless-react";
3
+ import { useDefaultHandleApiError } from "../hooks/useDefaultHandleApiError";
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
+ export function useFetchInitialMessage(
17
+ handleError?: (e: unknown) => void,
18
+ stream = false,
19
+ customCondition = true
20
+ ) {
21
+ const chat = useChatActions();
22
+ const defaultHandleApiError = useDefaultHandleApiError();
23
+ const messages = useChatState((state) => state.conversation.messages);
24
+ const [fetchInitialMessage, setFetchInitialMessage] = useState(
25
+ messages.length === 0
26
+ );
27
+ const [messagesLength, setMessagesLength] = useState(messages.length);
28
+ const canSendMessage = useChatState(
29
+ (state) => state.conversation.canSendMessage
30
+ );
31
+
32
+ //handle message history resets
33
+ useEffect(() => {
34
+ const newMessagesLength = messages.length;
35
+ // Fetch data only when the conversation messages changes from non-zero to zero
36
+ if (messagesLength > 0 && newMessagesLength === 0) {
37
+ setFetchInitialMessage(true);
38
+ }
39
+ setMessagesLength(newMessagesLength);
40
+ }, [messages.length, messagesLength]);
41
+
42
+ useEffect(() => {
43
+ if (!fetchInitialMessage || !canSendMessage || !customCondition) {
44
+ return;
45
+ }
46
+ setFetchInitialMessage(false);
47
+ const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
48
+ res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
49
+ }, [
50
+ chat,
51
+ stream,
52
+ handleError,
53
+ defaultHandleApiError,
54
+ fetchInitialMessage,
55
+ canSendMessage,
56
+ customCondition,
57
+ ]);
58
+ }
@@ -7,7 +7,7 @@ import { useCallback } from "react";
7
7
  * The payload will automatically includes chat-ui-react's
8
8
  * package version for "clientSdk" field.
9
9
  *
10
- * @internal
10
+ * @public
11
11
  */
12
12
  export function useReportAnalyticsEvent(): ChatHeadless["report"] {
13
13
  const chat = useChatActions();
@@ -0,0 +1,47 @@
1
+ import { useChatState } from "@yext/chat-headless-react";
2
+ import React, { useCallback, useEffect, useRef } 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
+ export function useScrollToLastMessage(): [
14
+ React.RefObject<HTMLDivElement>,
15
+ (index: number) => ((message: HTMLDivElement) => void) | undefined
16
+ ] {
17
+ const messagesRef = useRef<Array<HTMLDivElement | null>>([]);
18
+ const messagesContainerRef = useRef<HTMLDivElement>(null);
19
+ const messages = useChatState((state) => state.conversation.messages);
20
+
21
+ // Handle scrolling when messages change
22
+ useEffect(() => {
23
+ let scrollTop = 0;
24
+ messagesRef.current = messagesRef.current.slice(0, messages.length);
25
+
26
+ // Sums up scroll heights of all messages except the last one
27
+ if (messagesRef?.current.length > 1) {
28
+ scrollTop = messagesRef.current
29
+ .slice(0, -1)
30
+ .map((elem, _) => elem?.scrollHeight ?? 0)
31
+ .reduce((total, height) => total + height);
32
+ }
33
+
34
+ // Scroll to the top of the last message
35
+ messagesContainerRef.current?.scroll({
36
+ top: scrollTop,
37
+ behavior: "smooth",
38
+ });
39
+ }, [messages]);
40
+
41
+ const setMessageRef = useCallback((index) => {
42
+ if (!messagesRef?.current) return undefined;
43
+ return (message: HTMLDivElement) => (messagesRef.current[index] = message);
44
+ }, []);
45
+
46
+ return [messagesContainerRef, setMessageRef]
47
+ }