@yext/chat-ui-react 0.8.4 → 0.8.5

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.
@@ -1,11 +1,11 @@
1
1
  import React, { useCallback } from 'react';
2
- import { useChatActions } from '@yext/chat-headless-react';
2
+ import { useChatActions, useChatState } from '@yext/chat-headless-react';
3
3
  import { useDefaultHandleApiError } from '../hooks/useDefaultHandleApiError.mjs';
4
4
  import { withStylelessCssClasses } from '../utils/withStylelessCssClasses.mjs';
5
5
  import { useComposedCssClasses } from '../hooks/useComposedCssClasses.mjs';
6
6
 
7
7
  const defaultClassnames = withStylelessCssClasses("Suggestions", {
8
- container: "flex gap-2 mt-4 w-full overflow-x-auto flex-wrap",
8
+ container: "flex gap-2 mb-4 w-full overflow-x-auto flex-wrap",
9
9
  suggestion: "hover:cursor-pointer px-2 py-1 bg-white hover:bg-slate-300 rounded-full text-sm text-blue-700 border border-blue-700 hover:underline",
10
10
  });
11
11
  /**
@@ -16,13 +16,21 @@ const defaultClassnames = withStylelessCssClasses("Suggestions", {
16
16
  */
17
17
  const MessageSuggestions = ({ suggestions, customCssClasses, }) => {
18
18
  const actions = useChatActions();
19
+ const notes = useChatState((state) => state.conversation.notes);
19
20
  const defaultHandleApiError = useDefaultHandleApiError();
20
21
  const sendMsg = useCallback((msg) => {
22
+ const newNotes = {
23
+ ...(notes || {}),
24
+ suggestedReplies: undefined,
25
+ };
26
+ actions.setMessageNotes(newNotes);
21
27
  const res = actions.getNextMessage(msg);
22
28
  res.catch(defaultHandleApiError);
23
- }, [defaultHandleApiError, actions]);
29
+ }, [actions, notes, defaultHandleApiError]);
24
30
  const classes = useComposedCssClasses(defaultClassnames, customCssClasses);
25
- return (React.createElement("div", { className: classes.container }, suggestions.map((suggestion, index) => (React.createElement("button", { key: index, className: classes.suggestion, onClick: () => sendMsg(suggestion) }, suggestion)))));
31
+ return (React.createElement("div", { className: classes.container }, suggestions.map((suggestion, index) => (React.createElement("button", { key: index, className: classes.suggestion,
32
+ // eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
33
+ onClick: () => sendMsg(suggestion) }, suggestion)))));
26
34
  };
27
35
 
28
36
  export { MessageSuggestions };
@@ -1 +1 @@
1
- {"version":3,"file":"MessageSuggestions.mjs","sources":["../../../../src/components/MessageSuggestions.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { useChatActions } from \"@yext/chat-headless-react\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useComposedCssClasses } from \"../hooks\";\n\n/**\n * The CSS class interface for the MessageSuggestion component.\n *\n * @public\n */\nexport interface MessageSuggestionCssClasses {\n container?: string;\n suggestion?: string;\n}\n\n/**\n * The props for the MessageSuggestions component.\n *\n * @public\n */\nexport interface MessageSuggestionsProps {\n suggestions: string[];\n customCssClasses?: MessageSuggestionCssClasses;\n}\n\nconst defaultClassnames: MessageSuggestionCssClasses = withStylelessCssClasses(\n \"Suggestions\",\n {\n container: \"flex gap-2 mt-4 w-full overflow-x-auto flex-wrap\",\n suggestion:\n \"hover:cursor-pointer px-2 py-1 bg-white hover:bg-slate-300 rounded-full text-sm text-blue-700 border border-blue-700 hover:underline\",\n }\n);\n\n/**\n * A component that displays a list of suggested messages\n * to the user, which they can click to send the message to the bot.\n *\n * @internal\n */\nexport const MessageSuggestions: React.FC<MessageSuggestionsProps> = ({\n suggestions,\n customCssClasses,\n}) => {\n const actions = useChatActions();\n const defaultHandleApiError = useDefaultHandleApiError();\n const sendMsg = useCallback(\n (msg: string) => {\n const res = actions.getNextMessage(msg);\n res.catch(defaultHandleApiError);\n },\n [defaultHandleApiError, actions]\n );\n\n const classes = useComposedCssClasses(defaultClassnames, customCssClasses);\n\n return (\n <div className={classes.container}>\n {suggestions.map((suggestion, index) => (\n <button\n key={index}\n className={classes.suggestion}\n onClick={() => sendMsg(suggestion)}\n >\n {suggestion}\n </button>\n ))}\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;AA0BA,MAAM,iBAAiB,GAAgC,uBAAuB,CAC5E,aAAa,EACb;AACE,IAAA,SAAS,EAAE,kDAAkD;AAC7D,IAAA,UAAU,EACR,sIAAsI;AACzI,CAAA,CACF,CAAC;AAEF;;;;;AAKG;AACU,MAAA,kBAAkB,GAAsC,CAAC,EACpE,WAAW,EACX,gBAAgB,GACjB,KAAI;AACH,IAAA,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;AACjC,IAAA,MAAM,qBAAqB,GAAG,wBAAwB,EAAE,CAAC;AACzD,IAAA,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,GAAW,KAAI;QACd,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AACxC,QAAA,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;AACnC,KAAC,EACD,CAAC,qBAAqB,EAAE,OAAO,CAAC,CACjC,CAAC;IAEF,MAAM,OAAO,GAAG,qBAAqB,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;IAE3E,QACE,6BAAK,SAAS,EAAE,OAAO,CAAC,SAAS,IAC9B,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,MACjC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EACE,GAAG,EAAE,KAAK,EACV,SAAS,EAAE,OAAO,CAAC,UAAU,EAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,EAEjC,EAAA,UAAU,CACJ,CACV,CAAC,CACE,EACN;AACJ;;;;"}
1
+ {"version":3,"file":"MessageSuggestions.mjs","sources":["../../../../src/components/MessageSuggestions.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport {\n MessageNotes,\n useChatActions,\n useChatState,\n} from \"@yext/chat-headless-react\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { useComposedCssClasses } from \"../hooks\";\n\n/**\n * The CSS class interface for the MessageSuggestion component.\n *\n * @public\n */\nexport interface MessageSuggestionCssClasses {\n container?: string;\n suggestion?: string;\n}\n\n/**\n * The props for the MessageSuggestions component.\n *\n * @public\n */\nexport interface MessageSuggestionsProps {\n suggestions: string[];\n customCssClasses?: MessageSuggestionCssClasses;\n}\n\nconst defaultClassnames: MessageSuggestionCssClasses = withStylelessCssClasses(\n \"Suggestions\",\n {\n container: \"flex gap-2 mb-4 w-full overflow-x-auto flex-wrap\",\n suggestion:\n \"hover:cursor-pointer px-2 py-1 bg-white hover:bg-slate-300 rounded-full text-sm text-blue-700 border border-blue-700 hover:underline\",\n }\n);\n\n/**\n * A component that displays a list of suggested messages\n * to the user, which they can click to send the message to the bot.\n *\n * @internal\n */\nexport const MessageSuggestions: React.FC<MessageSuggestionsProps> = ({\n suggestions,\n customCssClasses,\n}) => {\n const actions = useChatActions();\n const notes = useChatState((state) => state.conversation.notes);\n const defaultHandleApiError = useDefaultHandleApiError();\n const sendMsg = useCallback(\n (msg: string) => {\n const newNotes = {\n ...(notes || {}),\n suggestedReplies: undefined,\n } satisfies MessageNotes;\n actions.setMessageNotes(newNotes);\n const res = actions.getNextMessage(msg);\n res.catch(defaultHandleApiError);\n },\n [actions, notes, defaultHandleApiError]\n );\n\n const classes = useComposedCssClasses(defaultClassnames, customCssClasses);\n\n return (\n <div className={classes.container}>\n {suggestions.map((suggestion, index) => (\n <button\n key={index}\n className={classes.suggestion}\n // eslint-disable-next-line react-perf/jsx-no-new-function-as-prop\n onClick={() => sendMsg(suggestion)}\n >\n {suggestion}\n </button>\n ))}\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;AA8BA,MAAM,iBAAiB,GAAgC,uBAAuB,CAC5E,aAAa,EACb;AACE,IAAA,SAAS,EAAE,kDAAkD;AAC7D,IAAA,UAAU,EACR,sIAAsI;AACzI,CAAA,CACF,CAAC;AAEF;;;;;AAKG;AACU,MAAA,kBAAkB,GAAsC,CAAC,EACpE,WAAW,EACX,gBAAgB,GACjB,KAAI;AACH,IAAA,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;AACjC,IAAA,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AAChE,IAAA,MAAM,qBAAqB,GAAG,wBAAwB,EAAE,CAAC;AACzD,IAAA,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,GAAW,KAAI;AACd,QAAA,MAAM,QAAQ,GAAG;AACf,YAAA,IAAI,KAAK,IAAI,EAAE,CAAC;AAChB,YAAA,gBAAgB,EAAE,SAAS;SACL,CAAC;AACzB,QAAA,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AACxC,QAAA,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;KAClC,EACD,CAAC,OAAO,EAAE,KAAK,EAAE,qBAAqB,CAAC,CACxC,CAAC;IAEF,MAAM,OAAO,GAAG,qBAAqB,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;AAE3E,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,OAAO,CAAC,SAAS,EAAA,EAC9B,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,MACjC,KACE,CAAA,aAAA,CAAA,QAAA,EAAA,EAAA,GAAG,EAAE,KAAK,EACV,SAAS,EAAE,OAAO,CAAC,UAAU;;AAE7B,QAAA,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,EAAA,EAEjC,UAAU,CACJ,CACV,CAAC,CACE,EACN;AACJ;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yext/chat-ui-react",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
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",
@@ -74,7 +74,7 @@
74
74
  "babel-jest": "^29.5.0",
75
75
  "eslint": "^8.39.0",
76
76
  "eslint-plugin-storybook": "^0.6.12",
77
- "generate-license-file": "^2.0.0",
77
+ "generate-license-file": "^1.0.0",
78
78
  "jest": "^29.5.0",
79
79
  "jest-environment-jsdom": "^29.5.0",
80
80
  "msw": "^1.2.1",
@@ -85,6 +85,9 @@ export function ChatPanel(props: ChatPanelProps) {
85
85
  props;
86
86
  const messages = useChatState((state) => state.conversation.messages);
87
87
  const loading = useChatState((state) => state.conversation.isLoading);
88
+ const suggestedReplies = useChatState(
89
+ (state) => state.conversation.notes?.suggestedReplies
90
+ );
88
91
  const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
89
92
  const reportAnalyticsEvent = useReportAnalyticsEvent();
90
93
  useFetchInitialMessage(handleError, stream);
@@ -102,9 +105,8 @@ export function ChatPanel(props: ChatPanelProps) {
102
105
  ) {
103
106
  return messageSuggestions;
104
107
  }
105
- // TODO: Chat API will send suggestions in the message notes eventually; add that here. [CLIP-852]
106
- return null;
107
- }, [messages, messageSuggestions]);
108
+ return suggestedReplies;
109
+ }, [messages, suggestedReplies, messageSuggestions]);
108
110
 
109
111
  const messagesRef = useRef<Array<HTMLDivElement | null>>([]);
110
112
  const messagesContainer = useRef<HTMLDivElement>(null);
@@ -150,15 +152,15 @@ export function ChatPanel(props: ChatPanelProps) {
150
152
  </div>
151
153
  ))}
152
154
  {loading && <LoadingDots />}
153
- {suggestions && (
154
- <MessageSuggestions
155
- suggestions={suggestions}
156
- customCssClasses={cssClasses.messageSuggestionClasses}
157
- />
158
- )}
159
155
  </div>
160
156
  </div>
161
157
  <div className={cssClasses.inputContainer}>
158
+ {suggestions && (
159
+ <MessageSuggestions
160
+ suggestions={suggestions}
161
+ customCssClasses={cssClasses.messageSuggestionClasses}
162
+ />
163
+ )}
162
164
  <ChatInput {...props} customCssClasses={cssClasses.inputCssClasses} />
163
165
  </div>
164
166
  </div>
@@ -254,7 +254,7 @@ export function ChatPopUp(props: ChatPopUpProps) {
254
254
  onClick={onClick}
255
255
  className={
256
256
  cssClasses.button +
257
- (showHeartBeatAnimation ? " animate-heartbeat" : "")
257
+ (showHeartBeatAnimation && !!numUnreadMessages ? " animate-heartbeat" : "")
258
258
  }
259
259
  >
260
260
  {openPanelButtonIcon ?? (
@@ -1,5 +1,9 @@
1
1
  import React, { useCallback } from "react";
2
- import { useChatActions } from "@yext/chat-headless-react";
2
+ import {
3
+ MessageNotes,
4
+ useChatActions,
5
+ useChatState,
6
+ } from "@yext/chat-headless-react";
3
7
  import { useDefaultHandleApiError } from "../hooks/useDefaultHandleApiError";
4
8
  import { withStylelessCssClasses } from "../utils/withStylelessCssClasses";
5
9
  import { useComposedCssClasses } from "../hooks";
@@ -27,7 +31,7 @@ export interface MessageSuggestionsProps {
27
31
  const defaultClassnames: MessageSuggestionCssClasses = withStylelessCssClasses(
28
32
  "Suggestions",
29
33
  {
30
- container: "flex gap-2 mt-4 w-full overflow-x-auto flex-wrap",
34
+ container: "flex gap-2 mb-4 w-full overflow-x-auto flex-wrap",
31
35
  suggestion:
32
36
  "hover:cursor-pointer px-2 py-1 bg-white hover:bg-slate-300 rounded-full text-sm text-blue-700 border border-blue-700 hover:underline",
33
37
  }
@@ -44,13 +48,19 @@ export const MessageSuggestions: React.FC<MessageSuggestionsProps> = ({
44
48
  customCssClasses,
45
49
  }) => {
46
50
  const actions = useChatActions();
51
+ const notes = useChatState((state) => state.conversation.notes);
47
52
  const defaultHandleApiError = useDefaultHandleApiError();
48
53
  const sendMsg = useCallback(
49
54
  (msg: string) => {
55
+ const newNotes = {
56
+ ...(notes || {}),
57
+ suggestedReplies: undefined,
58
+ } satisfies MessageNotes;
59
+ actions.setMessageNotes(newNotes);
50
60
  const res = actions.getNextMessage(msg);
51
61
  res.catch(defaultHandleApiError);
52
62
  },
53
- [defaultHandleApiError, actions]
63
+ [actions, notes, defaultHandleApiError]
54
64
  );
55
65
 
56
66
  const classes = useComposedCssClasses(defaultClassnames, customCssClasses);
@@ -61,6 +71,7 @@ export const MessageSuggestions: React.FC<MessageSuggestionsProps> = ({
61
71
  <button
62
72
  key={index}
63
73
  className={classes.suggestion}
74
+ // eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
64
75
  onClick={() => sendMsg(suggestion)}
65
76
  >
66
77
  {suggestion}