@yext/chat-ui-react 0.8.4 → 0.8.6

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 (55) hide show
  1. package/LICENSE +3 -0
  2. package/THIRD-PARTY-NOTICES +137 -141
  3. package/lib/bundle.css +1 -1
  4. package/lib/commonjs/package.json.js +1 -1
  5. package/lib/commonjs/src/components/ChatInput.d.ts +3 -1
  6. package/lib/commonjs/src/components/ChatInput.d.ts.map +1 -1
  7. package/lib/commonjs/src/components/ChatInput.js +5 -3
  8. package/lib/commonjs/src/components/ChatInput.js.map +1 -1
  9. package/lib/commonjs/src/components/ChatPanel.d.ts +3 -0
  10. package/lib/commonjs/src/components/ChatPanel.d.ts.map +1 -1
  11. package/lib/commonjs/src/components/ChatPanel.js +14 -7
  12. package/lib/commonjs/src/components/ChatPanel.js.map +1 -1
  13. package/lib/commonjs/src/components/ChatPopUp.d.ts.map +1 -1
  14. package/lib/commonjs/src/components/ChatPopUp.js +5 -3
  15. package/lib/commonjs/src/components/ChatPopUp.js.map +1 -1
  16. package/lib/commonjs/src/components/Markdown.d.ts +17 -3
  17. package/lib/commonjs/src/components/Markdown.d.ts.map +1 -1
  18. package/lib/commonjs/src/components/Markdown.js +10 -5
  19. package/lib/commonjs/src/components/Markdown.js.map +1 -1
  20. package/lib/commonjs/src/components/MessageBubble.d.ts.map +1 -1
  21. package/lib/commonjs/src/components/MessageBubble.js +4 -1
  22. package/lib/commonjs/src/components/MessageBubble.js.map +1 -1
  23. package/lib/commonjs/src/components/MessageSuggestions.d.ts.map +1 -1
  24. package/lib/commonjs/src/components/MessageSuggestions.js +11 -3
  25. package/lib/commonjs/src/components/MessageSuggestions.js.map +1 -1
  26. package/lib/esm/index.d.ts +6 -1
  27. package/lib/esm/package.json.mjs +1 -1
  28. package/lib/esm/src/components/ChatInput.d.ts +3 -1
  29. package/lib/esm/src/components/ChatInput.d.ts.map +1 -1
  30. package/lib/esm/src/components/ChatInput.mjs +5 -3
  31. package/lib/esm/src/components/ChatInput.mjs.map +1 -1
  32. package/lib/esm/src/components/ChatPanel.d.ts +3 -0
  33. package/lib/esm/src/components/ChatPanel.d.ts.map +1 -1
  34. package/lib/esm/src/components/ChatPanel.mjs +14 -7
  35. package/lib/esm/src/components/ChatPanel.mjs.map +1 -1
  36. package/lib/esm/src/components/ChatPopUp.d.ts.map +1 -1
  37. package/lib/esm/src/components/ChatPopUp.mjs +5 -3
  38. package/lib/esm/src/components/ChatPopUp.mjs.map +1 -1
  39. package/lib/esm/src/components/Markdown.d.ts +17 -3
  40. package/lib/esm/src/components/Markdown.d.ts.map +1 -1
  41. package/lib/esm/src/components/Markdown.mjs +10 -5
  42. package/lib/esm/src/components/Markdown.mjs.map +1 -1
  43. package/lib/esm/src/components/MessageBubble.d.ts.map +1 -1
  44. package/lib/esm/src/components/MessageBubble.mjs +5 -2
  45. package/lib/esm/src/components/MessageBubble.mjs.map +1 -1
  46. package/lib/esm/src/components/MessageSuggestions.d.ts.map +1 -1
  47. package/lib/esm/src/components/MessageSuggestions.mjs +12 -4
  48. package/lib/esm/src/components/MessageSuggestions.mjs.map +1 -1
  49. package/package.json +2 -2
  50. package/src/components/ChatInput.tsx +7 -2
  51. package/src/components/ChatPanel.tsx +39 -11
  52. package/src/components/ChatPopUp.tsx +5 -1
  53. package/src/components/Markdown.tsx +33 -7
  54. package/src/components/MessageBubble.tsx +10 -3
  55. package/src/components/MessageSuggestions.tsx +14 -3
@@ -4,6 +4,7 @@ import rehypeRaw from 'rehype-raw';
4
4
  import rehypeSanitize from 'rehype-sanitize';
5
5
  import React, { useMemo } from 'react';
6
6
  import { useReportAnalyticsEvent } from '../hooks/useReportAnalyticsEvent.mjs';
7
+ import { useComposedCssClasses } from '../hooks/useComposedCssClasses.mjs';
7
8
 
8
9
  // The Remark and Rehype plugins to use in conjunction with ReactMarkdown.
9
10
  const unifiedPlugins = {
@@ -15,6 +16,9 @@ const unifiedPlugins = {
15
16
  rehypeSanitize, //to sanitize HTML content
16
17
  ],
17
18
  };
19
+ const builtInCssClasses = {
20
+ link: "cursor-pointer",
21
+ };
18
22
  /**
19
23
  * Renders Github-Flavored Markdown from the Knowledge Graph. This Markdown can include
20
24
  * arbitrary HTML. Any HTML will be sanitized according to Rehype's default Schema.
@@ -24,12 +28,13 @@ const unifiedPlugins = {
24
28
  *
25
29
  * @internal
26
30
  */
27
- function Markdown({ content, responseId, className }) {
31
+ function Markdown({ content, responseId, customCssClasses, linkClickEvent = "CHAT_LINK_CLICK", }) {
28
32
  const reportAnalyticsEvent = useReportAnalyticsEvent();
33
+ const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
29
34
  const components = useMemo(() => {
30
35
  const createClickHandlerFn = (href) => () => {
31
36
  reportAnalyticsEvent({
32
- action: "CHAT_LINK_CLICK",
37
+ action: linkClickEvent,
33
38
  destinationUrl: href,
34
39
  chat: {
35
40
  responseId,
@@ -38,11 +43,11 @@ function Markdown({ content, responseId, className }) {
38
43
  };
39
44
  return {
40
45
  a: ({ node: _, children, ...props }) => {
41
- return (React.createElement("a", { ...props, onClick: createClickHandlerFn(props.href), target: "_blank", rel: "noopener noreferrer", className: "cursor-pointer" }, children));
46
+ return (React.createElement("a", { ...props, onClick: createClickHandlerFn(props.href), target: "_blank", rel: "noopener noreferrer", className: cssClasses.link }, children));
42
47
  },
43
48
  };
44
- }, [reportAnalyticsEvent, responseId]);
45
- return (React.createElement(ReactMarkdown, { className: className, children: content, remarkPlugins: unifiedPlugins.remark, rehypePlugins: unifiedPlugins.rehype, components: components }));
49
+ }, [reportAnalyticsEvent, linkClickEvent, responseId, cssClasses]);
50
+ return (React.createElement(ReactMarkdown, { className: cssClasses.container, children: content, remarkPlugins: unifiedPlugins.remark, rehypePlugins: unifiedPlugins.rehype, components: components }));
46
51
  }
47
52
 
48
53
  export { Markdown };
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.mjs","sources":["../../../../src/components/Markdown.tsx"],"sourcesContent":["import ReactMarkdown, {\n PluggableList,\n ReactMarkdownOptions,\n} from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport rehypeRaw from \"rehype-raw\";\nimport rehypeSanitize from \"rehype-sanitize\";\nimport React, { useMemo } from \"react\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\n\n// The Remark and Rehype plugins to use in conjunction with ReactMarkdown.\nconst unifiedPlugins: { remark?: PluggableList; rehype: PluggableList } = {\n remark: [\n remarkGfm, //renders Github-Flavored Markdown\n ],\n rehype: [\n rehypeRaw, //to support HTML embedded in markdown\n rehypeSanitize, //to sanitize HTML content\n ],\n};\n\ninterface MarkdownProps {\n /** Stringified markdown. */\n content: string;\n /** The response ID correlates to the current message. */\n responseId?: string;\n /** Classnames for the container. */\n className?: string;\n}\n\n/**\n * Renders Github-Flavored Markdown from the Knowledge Graph. This Markdown can include\n * arbitrary HTML. Any HTML will be sanitized according to Rehype's default Schema.\n *\n * @remarks\n * A link click will send a CHAT_LINK_CLICK analytics event\n *\n * @internal\n */\nexport function Markdown({ content, responseId, className }: MarkdownProps) {\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n\n const components: ReactMarkdownOptions[\"components\"] = useMemo(() => {\n const createClickHandlerFn = (href?: string) => () => {\n reportAnalyticsEvent({\n action: \"CHAT_LINK_CLICK\",\n destinationUrl: href,\n chat: {\n responseId,\n },\n });\n };\n return {\n a: ({ node: _, children, ...props }) => {\n return (\n <a\n {...props}\n onClick={createClickHandlerFn(props.href)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"cursor-pointer\"\n >\n {children}\n </a>\n );\n },\n };\n }, [reportAnalyticsEvent, responseId]);\n\n return (\n <ReactMarkdown\n className={className}\n children={content}\n remarkPlugins={unifiedPlugins.remark}\n rehypePlugins={unifiedPlugins.rehype}\n components={components}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;;AAUA;AACA,MAAM,cAAc,GAAsD;AACxE,IAAA,MAAM,EAAE;AACN,QAAA,SAAS;AACV,KAAA;AACD,IAAA,MAAM,EAAE;QACN,SAAS;AACT,QAAA,cAAc;AACf,KAAA;CACF,CAAC;AAWF;;;;;;;;AAQG;AACG,SAAU,QAAQ,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAiB,EAAA;AACxE,IAAA,MAAM,oBAAoB,GAAG,uBAAuB,EAAE,CAAC;AAEvD,IAAA,MAAM,UAAU,GAAuC,OAAO,CAAC,MAAK;QAClE,MAAM,oBAAoB,GAAG,CAAC,IAAa,KAAK,MAAK;AACnD,YAAA,oBAAoB,CAAC;AACnB,gBAAA,MAAM,EAAE,iBAAiB;AACzB,gBAAA,cAAc,EAAE,IAAI;AACpB,gBAAA,IAAI,EAAE;oBACJ,UAAU;AACX,iBAAA;AACF,aAAA,CAAC,CAAC;AACL,SAAC,CAAC;QACF,OAAO;AACL,YAAA,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,KAAI;AACrC,gBAAA,QACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAA,GACM,KAAK,EACT,OAAO,EAAE,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,EACzC,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,qBAAqB,EACzB,SAAS,EAAC,gBAAgB,EAEzB,EAAA,QAAQ,CACP,EACJ;aACH;SACF,CAAC;AACJ,KAAC,EAAE,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAC,CAAC;AAEvC,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,aAAa,EAAA,EACZ,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,OAAO,EACjB,aAAa,EAAE,cAAc,CAAC,MAAM,EACpC,aAAa,EAAE,cAAc,CAAC,MAAM,EACpC,UAAU,EAAE,UAAU,EAAA,CACtB,EACF;AACJ;;;;"}
1
+ {"version":3,"file":"Markdown.mjs","sources":["../../../../src/components/Markdown.tsx"],"sourcesContent":["import ReactMarkdown, {\n PluggableList,\n ReactMarkdownOptions,\n} from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport rehypeRaw from \"rehype-raw\";\nimport rehypeSanitize from \"rehype-sanitize\";\nimport React, { useMemo } from \"react\";\nimport { useReportAnalyticsEvent } from \"../hooks/useReportAnalyticsEvent\";\nimport { useComposedCssClasses } from \"../hooks/useComposedCssClasses\";\n\n// The Remark and Rehype plugins to use in conjunction with ReactMarkdown.\nconst unifiedPlugins: { remark?: PluggableList; rehype: PluggableList } = {\n remark: [\n remarkGfm, //renders Github-Flavored Markdown\n ],\n rehype: [\n rehypeRaw, //to support HTML embedded in markdown\n rehypeSanitize, //to sanitize HTML content\n ],\n};\n\n/**\n * The CSS class interface for the Markdown component.\n *\n * @internal\n */\nexport interface MarkdownCssClasses {\n container?: string;\n link?: string;\n}\n\nconst builtInCssClasses: MarkdownCssClasses = {\n link: \"cursor-pointer\",\n};\n\ninterface MarkdownProps {\n /** Stringified markdown. */\n content: string;\n /** The response ID correlates to the current message. */\n responseId?: string;\n /** CSS classes for customizing the component styling. */\n customCssClasses?: MarkdownCssClasses;\n /**\n * Action to report for analytics event when a link is clicked.\n * Defaults to 'CHAT_LINK_CLICK'.\n */\n linkClickEvent?: \"WEBSITE\" | \"CHAT_LINK_CLICK\";\n}\n\n/**\n * Renders Github-Flavored Markdown from the Knowledge Graph. This Markdown can include\n * arbitrary HTML. Any HTML will be sanitized according to Rehype's default Schema.\n *\n * @remarks\n * A link click will send a CHAT_LINK_CLICK analytics event\n *\n * @internal\n */\nexport function Markdown({\n content,\n responseId,\n customCssClasses,\n linkClickEvent = \"CHAT_LINK_CLICK\",\n}: MarkdownProps) {\n const reportAnalyticsEvent = useReportAnalyticsEvent();\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n\n const components: ReactMarkdownOptions[\"components\"] = useMemo(() => {\n const createClickHandlerFn = (href?: string) => () => {\n reportAnalyticsEvent({\n action: linkClickEvent,\n destinationUrl: href,\n chat: {\n responseId,\n },\n });\n };\n return {\n a: ({ node: _, children, ...props }) => {\n return (\n <a\n {...props}\n onClick={createClickHandlerFn(props.href)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cssClasses.link}\n >\n {children}\n </a>\n );\n },\n };\n }, [reportAnalyticsEvent, linkClickEvent, responseId, cssClasses]);\n\n return (\n <ReactMarkdown\n className={cssClasses.container}\n children={content}\n remarkPlugins={unifiedPlugins.remark}\n rehypePlugins={unifiedPlugins.rehype}\n components={components}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAWA;AACA,MAAM,cAAc,GAAsD;AACxE,IAAA,MAAM,EAAE;AACN,QAAA,SAAS;AACV,KAAA;AACD,IAAA,MAAM,EAAE;QACN,SAAS;AACT,QAAA,cAAc;AACf,KAAA;CACF,CAAC;AAYF,MAAM,iBAAiB,GAAuB;AAC5C,IAAA,IAAI,EAAE,gBAAgB;CACvB,CAAC;AAgBF;;;;;;;;AAQG;AACa,SAAA,QAAQ,CAAC,EACvB,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,cAAc,GAAG,iBAAiB,GACpB,EAAA;AACd,IAAA,MAAM,oBAAoB,GAAG,uBAAuB,EAAE,CAAC;IACvD,MAAM,UAAU,GAAG,qBAAqB,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;AAE9E,IAAA,MAAM,UAAU,GAAuC,OAAO,CAAC,MAAK;QAClE,MAAM,oBAAoB,GAAG,CAAC,IAAa,KAAK,MAAK;AACnD,YAAA,oBAAoB,CAAC;AACnB,gBAAA,MAAM,EAAE,cAAc;AACtB,gBAAA,cAAc,EAAE,IAAI;AACpB,gBAAA,IAAI,EAAE;oBACJ,UAAU;AACX,iBAAA;AACF,aAAA,CAAC,CAAC;AACL,SAAC,CAAC;QACF,OAAO;AACL,YAAA,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,KAAI;AACrC,gBAAA,QACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAA,GACM,KAAK,EACT,OAAO,EAAE,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,EACzC,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,qBAAqB,EACzB,SAAS,EAAE,UAAU,CAAC,IAAI,EAAA,EAEzB,QAAQ,CACP,EACJ;aACH;SACF,CAAC;KACH,EAAE,CAAC,oBAAoB,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;AAEnE,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,aAAa,EAAA,EACZ,SAAS,EAAE,UAAU,CAAC,SAAS,EAC/B,QAAQ,EAAE,OAAO,EACjB,aAAa,EAAE,cAAc,CAAC,MAAM,EACpC,aAAa,EAAE,cAAc,CAAC,MAAM,EACpC,UAAU,EAAE,UAAU,EAAA,CACtB,EACF;AACJ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/MessageBubble.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAiB,MAAM,2BAA2B,CAAC;AAKnE,OAAO,EAAmB,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB,CAAC,EAAE,yBAAyB,CAAC;CACvD;AAuBD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;CAC5C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,mBAA0B,EAC1B,aAAoB,EACpB,gBAAgB,EAChB,eAAwC,GACzC,EAAE,kBAAkB,qBAoDpB"}
1
+ {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/MessageBubble.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,OAAO,EAAiB,MAAM,2BAA2B,CAAC;AAKnE,OAAO,EAAmB,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB,CAAC,EAAE,yBAAyB,CAAC;CACvD;AAuBD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;CAC5C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,mBAA0B,EAC1B,aAAoB,EACpB,gBAAgB,EAChB,eAAwC,GACzC,EAAE,kBAAkB,qBA2DpB"}
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { MessageSource } from '@yext/chat-headless-react';
3
3
  import { useComposedCssClasses } from '../hooks/useComposedCssClasses.mjs';
4
4
  import { twMerge } from 'tailwind-merge';
@@ -43,11 +43,14 @@ function MessageBubble({ message, showFeedbackButtons = true, showTimestamp = tr
43
43
  const timestampCssClasses = twMerge(cssClasses.timestamp, message.source === MessageSource.USER
44
44
  ? cssClasses.timestamp__user
45
45
  : cssClasses.timestamp__bot);
46
+ const markdownCssClasses = useMemo(() => ({
47
+ container: textCssClasses,
48
+ }), [textCssClasses]);
46
49
  return (React.createElement("div", { className: cssClasses.topContainer },
47
50
  React.createElement("div", { className: subContainerCssClasses },
48
51
  React.createElement("div", { className: bubbleCssClasses },
49
52
  showFeedbackButtons && message.source === MessageSource.BOT && (React.createElement(FeedbackButtons, { customCssClasses: cssClasses.feedbackButtonsCssClasses, responseId: message.responseId })),
50
- React.createElement(Markdown, { content: message.text, responseId: message.responseId, className: textCssClasses })),
53
+ React.createElement(Markdown, { content: message.text, responseId: message.responseId, customCssClasses: markdownCssClasses })),
51
54
  showTimestamp && (React.createElement("div", { className: timestampCssClasses }, message.timestamp ? formatTimestamp(message.timestamp) : " ")))));
52
55
  }
53
56
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"MessageBubble.mjs","sources":["../../../../src/components/MessageBubble.tsx"],"sourcesContent":["import React from \"react\";\nimport { Message, MessageSource } from \"@yext/chat-headless-react\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { twMerge } from \"tailwind-merge\";\nimport { Markdown } from \"./Markdown\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { FeedbackButtons, FeedbackButtonsCssClasses } from \"./FeedbackButtons\";\n\n/**\n * The CSS class interface for the {@link MessageBubble} component.\n *\n * @public\n */\nexport interface MessageBubbleCssClasses {\n topContainer?: string;\n subContainer?: string;\n subContainer__bot?: string;\n subContainer__user?: string;\n bubble?: string;\n bubble__bot?: string;\n bubble__user?: string;\n text?: string;\n text__bot?: string;\n text__user?: string;\n timestamp?: string;\n timestamp__bot?: string;\n timestamp__user?: string;\n feedbackButtonsCssClasses?: FeedbackButtonsCssClasses;\n}\n\nconst builtInCssClasses: MessageBubbleCssClasses =\n withStylelessCssClasses<MessageBubbleCssClasses>(\"MessageBubble\", {\n topContainer: \"w-full animate-fade-in @container\",\n subContainer:\n \"flex flex-col @lg:flex-row @lg:items-center @lg:gap-x-2 @lg:m-1\",\n subContainer__bot: \"\",\n subContainer__user: \"@lg:flex-row-reverse\",\n bubble: \"relative group peer w-fit max-w-[80%] rounded-2xl p-4\",\n bubble__bot: \"bg-gradient-to-tr from-slate-50 to-slate-100\",\n bubble__user:\n \"ml-auto @lg:ml-0 bg-gradient-to-tr from-blue-600 to-blue-700 text-white\",\n text: \"text-[13px] @[480px]:text-base prose overflow-x-auto\",\n text__bot: \"text-slate-900\",\n text__user: \"text-white break-words\",\n timestamp:\n \"w-fit my-0.5 ml-4 @lg:ml-0 text-slate-400 text-[10px] @[480px]:text-[13px] opacity-0 peer-hover:opacity-100 duration-200 whitespace-pre-wrap\",\n timestamp__bot: \"\",\n timestamp__user: \"ml-auto\",\n feedbackButtonsCssClasses: {},\n });\n\n/**\n * The props for the {@link MessageBubble} component.\n *\n * @public\n */\nexport interface MessageBubbleProps {\n /** The message to display. */\n message: Message;\n /**\n * Whether to show the feedback buttons on the message bubble.\n * Defaults to true.\n */\n showFeedbackButtons?: boolean;\n /**\n * Whether to show the timestamp of the message with the message bubble.\n * Defaults to true.\n */\n showTimestamp?: boolean;\n /**\n * A function which is called to format the message's timestamp given in\n * ISO format (e.g. \"2023-05-18T19:33:34.553Z\").\n * Defaults to \"HH:MM A\" (e.g. \"7:33 PM\").\n */\n formatTimestamp?: (timestamp: string) => string;\n /** CSS classes for customizing the component styling. */\n customCssClasses?: MessageBubbleCssClasses;\n}\n\n/**\n * A component that displays the provided message.\n *\n * @public\n *\n * @param props - {@link MessageBubbleProps}\n */\nexport function MessageBubble({\n message,\n showFeedbackButtons = true,\n showTimestamp = true,\n customCssClasses,\n formatTimestamp = defaultFormatTimestamp,\n}: MessageBubbleProps) {\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const bubbleCssClasses = twMerge(\n cssClasses.bubble,\n message.source === MessageSource.USER\n ? cssClasses.bubble__user\n : cssClasses.bubble__bot\n );\n const textCssClasses = twMerge(\n cssClasses.text,\n message.source === MessageSource.USER\n ? cssClasses.text__user\n : cssClasses.text__bot\n );\n const subContainerCssClasses = twMerge(\n cssClasses.subContainer,\n message.source === MessageSource.USER\n ? cssClasses.subContainer__user\n : cssClasses.subContainer__bot\n );\n const timestampCssClasses = twMerge(\n cssClasses.timestamp,\n message.source === MessageSource.USER\n ? cssClasses.timestamp__user\n : cssClasses.timestamp__bot\n );\n\n return (\n <div className={cssClasses.topContainer}>\n <div className={subContainerCssClasses}>\n <div className={bubbleCssClasses}>\n {showFeedbackButtons && message.source === MessageSource.BOT && (\n <FeedbackButtons\n customCssClasses={cssClasses.feedbackButtonsCssClasses}\n responseId={message.responseId}\n />\n )}\n <Markdown\n content={message.text}\n responseId={message.responseId}\n className={textCssClasses}\n />\n </div>\n {/* fallback on empty space here to perserve the height for timestamp div */}\n {showTimestamp && (\n <div className={timestampCssClasses}>\n {message.timestamp ? formatTimestamp(message.timestamp) : \" \"}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Formats message's timestamp from \"2023-05-18T19:33:34.553Z\" to \"7:33 PM\"\n *\n * @param timestamp - the timestamp to convert from\n * @returns formatted timestamp\n */\nfunction defaultFormatTimestamp(timestamp: string): string {\n return new Date(timestamp).toLocaleString(undefined, {\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MessageBubble.mjs","sources":["../../../../src/components/MessageBubble.tsx"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport { Message, MessageSource } from \"@yext/chat-headless-react\";\nimport { useComposedCssClasses } from \"../hooks\";\nimport { twMerge } from \"tailwind-merge\";\nimport { Markdown, MarkdownCssClasses } from \"./Markdown\";\nimport { withStylelessCssClasses } from \"../utils/withStylelessCssClasses\";\nimport { FeedbackButtons, FeedbackButtonsCssClasses } from \"./FeedbackButtons\";\n\n/**\n * The CSS class interface for the {@link MessageBubble} component.\n *\n * @public\n */\nexport interface MessageBubbleCssClasses {\n topContainer?: string;\n subContainer?: string;\n subContainer__bot?: string;\n subContainer__user?: string;\n bubble?: string;\n bubble__bot?: string;\n bubble__user?: string;\n text?: string;\n text__bot?: string;\n text__user?: string;\n timestamp?: string;\n timestamp__bot?: string;\n timestamp__user?: string;\n feedbackButtonsCssClasses?: FeedbackButtonsCssClasses;\n}\n\nconst builtInCssClasses: MessageBubbleCssClasses =\n withStylelessCssClasses<MessageBubbleCssClasses>(\"MessageBubble\", {\n topContainer: \"w-full animate-fade-in @container\",\n subContainer:\n \"flex flex-col @lg:flex-row @lg:items-center @lg:gap-x-2 @lg:m-1\",\n subContainer__bot: \"\",\n subContainer__user: \"@lg:flex-row-reverse\",\n bubble: \"relative group peer w-fit max-w-[80%] rounded-2xl p-4\",\n bubble__bot: \"bg-gradient-to-tr from-slate-50 to-slate-100\",\n bubble__user:\n \"ml-auto @lg:ml-0 bg-gradient-to-tr from-blue-600 to-blue-700 text-white\",\n text: \"text-[13px] @[480px]:text-base prose overflow-x-auto\",\n text__bot: \"text-slate-900\",\n text__user: \"text-white break-words\",\n timestamp:\n \"w-fit my-0.5 ml-4 @lg:ml-0 text-slate-400 text-[10px] @[480px]:text-[13px] opacity-0 peer-hover:opacity-100 duration-200 whitespace-pre-wrap\",\n timestamp__bot: \"\",\n timestamp__user: \"ml-auto\",\n feedbackButtonsCssClasses: {},\n });\n\n/**\n * The props for the {@link MessageBubble} component.\n *\n * @public\n */\nexport interface MessageBubbleProps {\n /** The message to display. */\n message: Message;\n /**\n * Whether to show the feedback buttons on the message bubble.\n * Defaults to true.\n */\n showFeedbackButtons?: boolean;\n /**\n * Whether to show the timestamp of the message with the message bubble.\n * Defaults to true.\n */\n showTimestamp?: boolean;\n /**\n * A function which is called to format the message's timestamp given in\n * ISO format (e.g. \"2023-05-18T19:33:34.553Z\").\n * Defaults to \"HH:MM A\" (e.g. \"7:33 PM\").\n */\n formatTimestamp?: (timestamp: string) => string;\n /** CSS classes for customizing the component styling. */\n customCssClasses?: MessageBubbleCssClasses;\n}\n\n/**\n * A component that displays the provided message.\n *\n * @public\n *\n * @param props - {@link MessageBubbleProps}\n */\nexport function MessageBubble({\n message,\n showFeedbackButtons = true,\n showTimestamp = true,\n customCssClasses,\n formatTimestamp = defaultFormatTimestamp,\n}: MessageBubbleProps) {\n const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);\n const bubbleCssClasses = twMerge(\n cssClasses.bubble,\n message.source === MessageSource.USER\n ? cssClasses.bubble__user\n : cssClasses.bubble__bot\n );\n const textCssClasses = twMerge(\n cssClasses.text,\n message.source === MessageSource.USER\n ? cssClasses.text__user\n : cssClasses.text__bot\n );\n const subContainerCssClasses = twMerge(\n cssClasses.subContainer,\n message.source === MessageSource.USER\n ? cssClasses.subContainer__user\n : cssClasses.subContainer__bot\n );\n const timestampCssClasses = twMerge(\n cssClasses.timestamp,\n message.source === MessageSource.USER\n ? cssClasses.timestamp__user\n : cssClasses.timestamp__bot\n );\n\n const markdownCssClasses: MarkdownCssClasses = useMemo(\n () => ({\n container: textCssClasses,\n }),\n [textCssClasses]\n );\n\n return (\n <div className={cssClasses.topContainer}>\n <div className={subContainerCssClasses}>\n <div className={bubbleCssClasses}>\n {showFeedbackButtons && message.source === MessageSource.BOT && (\n <FeedbackButtons\n customCssClasses={cssClasses.feedbackButtonsCssClasses}\n responseId={message.responseId}\n />\n )}\n <Markdown\n content={message.text}\n responseId={message.responseId}\n customCssClasses={markdownCssClasses}\n />\n </div>\n {/* fallback on empty space here to perserve the height for timestamp div */}\n {showTimestamp && (\n <div className={timestampCssClasses}>\n {message.timestamp ? formatTimestamp(message.timestamp) : \" \"}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Formats message's timestamp from \"2023-05-18T19:33:34.553Z\" to \"7:33 PM\"\n *\n * @param timestamp - the timestamp to convert from\n * @returns formatted timestamp\n */\nfunction defaultFormatTimestamp(timestamp: string): string {\n return new Date(timestamp).toLocaleString(undefined, {\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MessageSuggestions.d.ts","sourceRoot":"","sources":["../../../../src/components/MessageSuggestions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAM3C;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,2BAA2B,CAAC;CAChD;AAWD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA6BhE,CAAC"}
1
+ {"version":3,"file":"MessageSuggestions.d.ts","sourceRoot":"","sources":["../../../../src/components/MessageSuggestions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAU3C;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,2BAA2B,CAAC;CAChD;AAWD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAoChE,CAAC"}
@@ -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.6",
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",
@@ -56,6 +56,8 @@ export interface ChatInputProps {
56
56
  sendButtonIcon?: JSX.Element;
57
57
  /** CSS classes for customizing the component styling. */
58
58
  customCssClasses?: ChatInputCssClasses;
59
+ /** A callback which is called when user sends a message. */
60
+ onSend?: (message: string) => void;
59
61
  }
60
62
 
61
63
  /**
@@ -76,6 +78,7 @@ export function ChatInput({
76
78
  handleError,
77
79
  sendButtonIcon = <ArrowIcon />,
78
80
  customCssClasses,
81
+ onSend,
79
82
  }: ChatInputProps) {
80
83
  const chat = useChatActions();
81
84
  const [input, setInput] = useState("");
@@ -91,8 +94,10 @@ export function ChatInput({
91
94
  ? chat.streamNextMessage(input)
92
95
  : chat.getNextMessage(input);
93
96
  setInput("");
94
- res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
95
- }, [chat, input, handleError, defaultHandleApiError, stream]);
97
+ res.then(() => {
98
+ onSend?.(input)
99
+ }).catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
100
+ }, [chat, input, handleError, defaultHandleApiError, stream, onSend]);
96
101
 
97
102
  const handleKeyDown = useCallback(
98
103
  (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
@@ -21,6 +21,7 @@ import {
21
21
  MessageSuggestionCssClasses,
22
22
  MessageSuggestions,
23
23
  } from "./MessageSuggestions";
24
+ import { Markdown, MarkdownCssClasses } from "./Markdown";
24
25
 
25
26
  /**
26
27
  * The CSS class interface for the {@link ChatPanel} component.
@@ -35,6 +36,7 @@ export interface ChatPanelCssClasses {
35
36
  inputCssClasses?: ChatInputCssClasses;
36
37
  messageBubbleCssClasses?: MessageBubbleCssClasses;
37
38
  messageSuggestionClasses?: MessageSuggestionCssClasses;
39
+ footer?: string;
38
40
  }
39
41
 
40
42
  const builtInCssClasses: ChatPanelCssClasses = withStylelessCssClasses(
@@ -47,6 +49,7 @@ const builtInCssClasses: ChatPanelCssClasses = withStylelessCssClasses(
47
49
  messageBubbleCssClasses: {
48
50
  topContainer: "first:mt-4",
49
51
  },
52
+ footer: "text-center text-slate-400 rounded-b-3xl px-4 pb-4 text-[12px]",
50
53
  }
51
54
  );
52
55
 
@@ -60,6 +63,8 @@ export interface ChatPanelProps
60
63
  Omit<ChatInputProps, "customCssClasses"> {
61
64
  /** A header to render at the top of the panel. */
62
65
  header?: ReactNode;
66
+ /** A footer markdown string to render at the bottom of the panel. */
67
+ footer?: string;
63
68
  /**
64
69
  * CSS classes for customizing the component styling.
65
70
  */
@@ -81,10 +86,19 @@ export interface ChatPanelProps
81
86
  * @param props - {@link ChatPanelProps}
82
87
  */
83
88
  export function ChatPanel(props: ChatPanelProps) {
84
- const { header, customCssClasses, stream, handleError, messageSuggestions } =
85
- props;
89
+ const {
90
+ header,
91
+ footer,
92
+ customCssClasses,
93
+ stream,
94
+ handleError,
95
+ messageSuggestions,
96
+ } = props;
86
97
  const messages = useChatState((state) => state.conversation.messages);
87
98
  const loading = useChatState((state) => state.conversation.isLoading);
99
+ const suggestedReplies = useChatState(
100
+ (state) => state.conversation.notes?.suggestedReplies
101
+ );
88
102
  const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
89
103
  const reportAnalyticsEvent = useReportAnalyticsEvent();
90
104
  useFetchInitialMessage(handleError, stream);
@@ -102,9 +116,8 @@ export function ChatPanel(props: ChatPanelProps) {
102
116
  ) {
103
117
  return messageSuggestions;
104
118
  }
105
- // TODO: Chat API will send suggestions in the message notes eventually; add that here. [CLIP-852]
106
- return null;
107
- }, [messages, messageSuggestions]);
119
+ return suggestedReplies;
120
+ }, [messages, suggestedReplies, messageSuggestions]);
108
121
 
109
122
  const messagesRef = useRef<Array<HTMLDivElement | null>>([]);
110
123
  const messagesContainer = useRef<HTMLDivElement>(null);
@@ -134,6 +147,14 @@ export function ChatPanel(props: ChatPanelProps) {
134
147
  return (message) => (messagesRef.current[index] = message);
135
148
  }, []);
136
149
 
150
+ const footerCssClasses: MarkdownCssClasses = useMemo(
151
+ () => ({
152
+ container: cssClasses.footer,
153
+ link: "cursor-pointer hover:underline text-blue-600",
154
+ }),
155
+ [cssClasses]
156
+ );
157
+
137
158
  return (
138
159
  <div className="yext-chat w-full h-full">
139
160
  <div className={cssClasses.container}>
@@ -150,17 +171,24 @@ export function ChatPanel(props: ChatPanelProps) {
150
171
  </div>
151
172
  ))}
152
173
  {loading && <LoadingDots />}
153
- {suggestions && (
154
- <MessageSuggestions
155
- suggestions={suggestions}
156
- customCssClasses={cssClasses.messageSuggestionClasses}
157
- />
158
- )}
159
174
  </div>
160
175
  </div>
161
176
  <div className={cssClasses.inputContainer}>
177
+ {suggestions && (
178
+ <MessageSuggestions
179
+ suggestions={suggestions}
180
+ customCssClasses={cssClasses.messageSuggestionClasses}
181
+ />
182
+ )}
162
183
  <ChatInput {...props} customCssClasses={cssClasses.inputCssClasses} />
163
184
  </div>
185
+ {footer && (
186
+ <Markdown
187
+ content={footer}
188
+ linkClickEvent="WEBSITE"
189
+ customCssClasses={footerCssClasses}
190
+ />
191
+ )}
164
192
  </div>
165
193
  </div>
166
194
  );
@@ -133,6 +133,7 @@ export function ChatPopUp(props: ChatPopUpProps) {
133
133
  showUnreadNotification = false,
134
134
  ctaLabel,
135
135
  title,
136
+ footer,
136
137
  } = props;
137
138
 
138
139
  const reportAnalyticsEvent = useReportAnalyticsEvent();
@@ -224,6 +225,7 @@ export function ChatPopUp(props: ChatPopUpProps) {
224
225
  customCssClasses={cssClasses.headerCssClasses}
225
226
  />
226
227
  }
228
+ footer={footer}
227
229
  />
228
230
  )}
229
231
  </div>
@@ -254,7 +256,9 @@ export function ChatPopUp(props: ChatPopUpProps) {
254
256
  onClick={onClick}
255
257
  className={
256
258
  cssClasses.button +
257
- (showHeartBeatAnimation ? " animate-heartbeat" : "")
259
+ (showHeartBeatAnimation && !!numUnreadMessages
260
+ ? " animate-heartbeat"
261
+ : "")
258
262
  }
259
263
  >
260
264
  {openPanelButtonIcon ?? (
@@ -7,6 +7,7 @@ import rehypeRaw from "rehype-raw";
7
7
  import rehypeSanitize from "rehype-sanitize";
8
8
  import React, { useMemo } from "react";
9
9
  import { useReportAnalyticsEvent } from "../hooks/useReportAnalyticsEvent";
10
+ import { useComposedCssClasses } from "../hooks/useComposedCssClasses";
10
11
 
11
12
  // The Remark and Rehype plugins to use in conjunction with ReactMarkdown.
12
13
  const unifiedPlugins: { remark?: PluggableList; rehype: PluggableList } = {
@@ -19,13 +20,32 @@ const unifiedPlugins: { remark?: PluggableList; rehype: PluggableList } = {
19
20
  ],
20
21
  };
21
22
 
23
+ /**
24
+ * The CSS class interface for the Markdown component.
25
+ *
26
+ * @internal
27
+ */
28
+ export interface MarkdownCssClasses {
29
+ container?: string;
30
+ link?: string;
31
+ }
32
+
33
+ const builtInCssClasses: MarkdownCssClasses = {
34
+ link: "cursor-pointer",
35
+ };
36
+
22
37
  interface MarkdownProps {
23
38
  /** Stringified markdown. */
24
39
  content: string;
25
40
  /** The response ID correlates to the current message. */
26
41
  responseId?: string;
27
- /** Classnames for the container. */
28
- className?: string;
42
+ /** CSS classes for customizing the component styling. */
43
+ customCssClasses?: MarkdownCssClasses;
44
+ /**
45
+ * Action to report for analytics event when a link is clicked.
46
+ * Defaults to 'CHAT_LINK_CLICK'.
47
+ */
48
+ linkClickEvent?: "WEBSITE" | "CHAT_LINK_CLICK";
29
49
  }
30
50
 
31
51
  /**
@@ -37,13 +57,19 @@ interface MarkdownProps {
37
57
  *
38
58
  * @internal
39
59
  */
40
- export function Markdown({ content, responseId, className }: MarkdownProps) {
60
+ export function Markdown({
61
+ content,
62
+ responseId,
63
+ customCssClasses,
64
+ linkClickEvent = "CHAT_LINK_CLICK",
65
+ }: MarkdownProps) {
41
66
  const reportAnalyticsEvent = useReportAnalyticsEvent();
67
+ const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
42
68
 
43
69
  const components: ReactMarkdownOptions["components"] = useMemo(() => {
44
70
  const createClickHandlerFn = (href?: string) => () => {
45
71
  reportAnalyticsEvent({
46
- action: "CHAT_LINK_CLICK",
72
+ action: linkClickEvent,
47
73
  destinationUrl: href,
48
74
  chat: {
49
75
  responseId,
@@ -58,18 +84,18 @@ export function Markdown({ content, responseId, className }: MarkdownProps) {
58
84
  onClick={createClickHandlerFn(props.href)}
59
85
  target="_blank"
60
86
  rel="noopener noreferrer"
61
- className="cursor-pointer"
87
+ className={cssClasses.link}
62
88
  >
63
89
  {children}
64
90
  </a>
65
91
  );
66
92
  },
67
93
  };
68
- }, [reportAnalyticsEvent, responseId]);
94
+ }, [reportAnalyticsEvent, linkClickEvent, responseId, cssClasses]);
69
95
 
70
96
  return (
71
97
  <ReactMarkdown
72
- className={className}
98
+ className={cssClasses.container}
73
99
  children={content}
74
100
  remarkPlugins={unifiedPlugins.remark}
75
101
  rehypePlugins={unifiedPlugins.rehype}
@@ -1,8 +1,8 @@
1
- import React from "react";
1
+ import React, { useMemo } from "react";
2
2
  import { Message, MessageSource } from "@yext/chat-headless-react";
3
3
  import { useComposedCssClasses } from "../hooks";
4
4
  import { twMerge } from "tailwind-merge";
5
- import { Markdown } from "./Markdown";
5
+ import { Markdown, MarkdownCssClasses } from "./Markdown";
6
6
  import { withStylelessCssClasses } from "../utils/withStylelessCssClasses";
7
7
  import { FeedbackButtons, FeedbackButtonsCssClasses } from "./FeedbackButtons";
8
8
 
@@ -117,6 +117,13 @@ export function MessageBubble({
117
117
  : cssClasses.timestamp__bot
118
118
  );
119
119
 
120
+ const markdownCssClasses: MarkdownCssClasses = useMemo(
121
+ () => ({
122
+ container: textCssClasses,
123
+ }),
124
+ [textCssClasses]
125
+ );
126
+
120
127
  return (
121
128
  <div className={cssClasses.topContainer}>
122
129
  <div className={subContainerCssClasses}>
@@ -130,7 +137,7 @@ export function MessageBubble({
130
137
  <Markdown
131
138
  content={message.text}
132
139
  responseId={message.responseId}
133
- className={textCssClasses}
140
+ customCssClasses={markdownCssClasses}
134
141
  />
135
142
  </div>
136
143
  {/* fallback on empty space here to perserve the height for timestamp div */}
@@ -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}