@envive-ai/react-toolkit-v3 0.3.27 → 0.3.28

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 (183) hide show
  1. package/dist/AnimatedText/AnimatedText.d.cts +3 -3
  2. package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.cts +2 -2
  3. package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.ts +2 -2
  4. package/dist/Carousel/Carousel.cjs +1 -1
  5. package/dist/Carousel/Carousel.d.cts +2 -2
  6. package/dist/Carousel/Carousel.d.ts +2 -2
  7. package/dist/Carousel/Carousel.js +1 -1
  8. package/dist/Carousel/components/Container.cjs +2 -2
  9. package/dist/Carousel/components/Container.js +2 -2
  10. package/dist/ChatFooter/ChatFooter.cjs +2 -1
  11. package/dist/ChatFooter/ChatFooter.d.cts +2 -2
  12. package/dist/ChatFooter/ChatFooter.d.ts +2 -2
  13. package/dist/ChatFooter/ChatFooter.js +2 -1
  14. package/dist/ChatFooter/components/Layout.cjs +2 -2
  15. package/dist/ChatFooter/components/Layout.js +2 -2
  16. package/dist/ChatFooter/components/index.d.cts +6 -5
  17. package/dist/ChatFooter/components/index.d.ts +4 -3
  18. package/dist/ChatFooter/types/types.d.cts +3 -2
  19. package/dist/ChatFooter/types/types.d.ts +3 -2
  20. package/dist/ChatHeader/ChatHeader.d.cts +2 -2
  21. package/dist/ChatHeader/ChatHeader.d.ts +2 -2
  22. package/dist/ChatHeader/components/Handle.cjs +2 -2
  23. package/dist/ChatHeader/components/Handle.js +2 -2
  24. package/dist/ChatHeader/components/Toggle.cjs +3 -3
  25. package/dist/ChatHeader/components/Toggle.js +3 -3
  26. package/dist/ChatPreview/ChatPreview.cjs +1 -1
  27. package/dist/ChatPreview/ChatPreview.d.cts +2 -2
  28. package/dist/ChatPreview/ChatPreview.d.ts +2 -2
  29. package/dist/ChatPreview/ChatPreview.js +1 -1
  30. package/dist/ChatPreviewComparison/ChatPreviewComparison.cjs +1 -1
  31. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
  32. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
  33. package/dist/ChatPreviewComparison/ChatPreviewComparison.js +1 -1
  34. package/dist/ChatPreviewComparison/components/Headline.cjs +2 -2
  35. package/dist/ChatPreviewComparison/components/Headline.js +2 -2
  36. package/dist/ChatPreviewComparison/components/Layout.cjs +4 -4
  37. package/dist/ChatPreviewComparison/components/Layout.js +4 -4
  38. package/dist/ChatPreviewComparison/components/Message.cjs +2 -2
  39. package/dist/ChatPreviewComparison/components/Message.js +2 -2
  40. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
  41. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
  42. package/dist/Container/Container.d.cts +219 -219
  43. package/dist/Container/Container.d.ts +57 -57
  44. package/dist/DesignTokens/DesignTokensComponent.d.cts +2 -2
  45. package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
  46. package/dist/Disclaimer/components/Container.cjs +2 -2
  47. package/dist/Disclaimer/components/Container.js +2 -2
  48. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
  49. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
  50. package/dist/DocumentRetrievalCard/components/Layout.cjs +2 -2
  51. package/dist/DocumentRetrievalCard/components/Layout.js +2 -2
  52. package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.cjs +1 -1
  53. package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.js +1 -1
  54. package/dist/DocumentRetrievalCard/components/ViewArticleButton.cjs +1 -1
  55. package/dist/DocumentRetrievalCard/components/ViewArticleButton.js +1 -1
  56. package/dist/FloatingButton/FloatingButton.d.cts +2 -2
  57. package/dist/FloatingButton/FloatingButton.d.ts +2 -2
  58. package/dist/FloatingChat/FloatingChat.d.cts +2 -2
  59. package/dist/FloatingChat/FloatingChat.d.ts +2 -2
  60. package/dist/FloatingChat/components/ChatMessages.cjs +1 -1
  61. package/dist/FloatingChat/components/ChatMessages.js +1 -1
  62. package/dist/FloatingChat/components/Layout.cjs +3 -3
  63. package/dist/FloatingChat/components/Layout.js +3 -3
  64. package/dist/FloatingChat/components/ResultsGridView.cjs +1 -1
  65. package/dist/FloatingChat/components/ResultsGridView.js +1 -1
  66. package/dist/FloatingChat/components/SalesAgentBadgeContent.cjs +1 -1
  67. package/dist/FloatingChat/components/SalesAgentBadgeContent.js +1 -1
  68. package/dist/FullPageSalesAgent/FullPageSalesAgent.cjs +43 -8
  69. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.cts +2 -2
  70. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.ts +2 -2
  71. package/dist/FullPageSalesAgent/FullPageSalesAgent.js +43 -8
  72. package/dist/FullPageSalesAgent/components/WelcomeOverlay.cjs +10 -3
  73. package/dist/FullPageSalesAgent/components/WelcomeOverlay.js +10 -3
  74. package/dist/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.cjs +1 -0
  75. package/dist/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.js +1 -0
  76. package/dist/Image/Image.d.cts +2 -2
  77. package/dist/Image/Image.d.ts +2 -2
  78. package/dist/ImageGallery/ImageGallery.d.cts +2 -2
  79. package/dist/ImageGallery/ImageGallery.d.ts +2 -2
  80. package/dist/ImageGallery/components/Layout.cjs +1 -1
  81. package/dist/ImageGallery/components/Layout.js +1 -1
  82. package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +2 -2
  83. package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +2 -2
  84. package/dist/Message/components/LinkButton.cjs +2 -2
  85. package/dist/Message/components/LinkButton.js +2 -2
  86. package/dist/OrderLookupCard/OrderLookupCard.cjs +1 -1
  87. package/dist/OrderLookupCard/OrderLookupCard.js +1 -1
  88. package/dist/ProductCard/ProductCard.cjs +2 -2
  89. package/dist/ProductCard/ProductCard.d.cts +2 -2
  90. package/dist/ProductCard/ProductCard.d.ts +2 -2
  91. package/dist/ProductCard/ProductCard.js +2 -2
  92. package/dist/PromptButton/PromptButton.d.cts +2 -2
  93. package/dist/PromptButton/PromptButton.d.ts +2 -2
  94. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
  95. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
  96. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.cjs +1 -1
  97. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.js +1 -1
  98. package/dist/PromptCarousel/PromptCarousel.cjs +3 -3
  99. package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
  100. package/dist/PromptCarousel/PromptCarousel.js +3 -3
  101. package/dist/ReviewCard/ReviewCard.d.cts +2 -2
  102. package/dist/ReviewCard/ReviewCard.d.ts +2 -2
  103. package/dist/ReviewCard/components/Container.cjs +2 -2
  104. package/dist/ReviewCard/components/Container.js +2 -2
  105. package/dist/ReviewCard/components/ReadMoreButton.cjs +1 -1
  106. package/dist/ReviewCard/components/ReadMoreButton.js +1 -1
  107. package/dist/ReviewCard/components/index.d.cts +6 -6
  108. package/dist/ReviewCard/components/index.d.ts +6 -6
  109. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
  110. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
  111. package/dist/SalesAgentProductCard/components/Container.cjs +2 -2
  112. package/dist/SalesAgentProductCard/components/Container.js +2 -2
  113. package/dist/SalesAgentProductCard/components/index.d.cts +6 -6
  114. package/dist/SalesAgentProductCard/components/index.d.ts +8 -8
  115. package/dist/SocialProof/SocialProof.cjs +1 -1
  116. package/dist/SocialProof/SocialProof.d.cts +2 -2
  117. package/dist/SocialProof/SocialProof.d.ts +2 -2
  118. package/dist/SocialProof/SocialProof.js +1 -1
  119. package/dist/SocialProof/components/Headline.cjs +3 -3
  120. package/dist/SocialProof/components/Headline.js +3 -3
  121. package/dist/SocialProof/components/LayoutFourHorizontal.cjs +1 -1
  122. package/dist/SocialProof/components/LayoutFourHorizontal.js +1 -1
  123. package/dist/SocialProof/components/Subheadline.cjs +1 -1
  124. package/dist/SocialProof/components/Subheadline.js +1 -1
  125. package/dist/SparkleAnimation/SparkleAnimation.d.cts +2 -2
  126. package/dist/SparkleAnimation/SparkleAnimation.d.ts +2 -2
  127. package/dist/Stack/Stack.d.cts +2 -2
  128. package/dist/Stack/Stack.d.ts +2 -2
  129. package/dist/TextField/TextField.cjs +7 -3
  130. package/dist/TextField/TextField.d.cts +1 -0
  131. package/dist/TextField/TextField.d.ts +1 -0
  132. package/dist/TextField/TextField.js +7 -3
  133. package/dist/TextField/components/Input.cjs +31 -2
  134. package/dist/TextField/components/Input.js +31 -2
  135. package/dist/TextField/components/Layout.cjs +7 -2
  136. package/dist/TextField/components/Layout.js +7 -2
  137. package/dist/TextField/hooks/useAutoResize.cjs +17 -0
  138. package/dist/TextField/hooks/useAutoResize.js +16 -0
  139. package/dist/TextField/hooks/usePlaceholderAnimation.cjs +58 -0
  140. package/dist/TextField/hooks/usePlaceholderAnimation.js +57 -0
  141. package/dist/TextField/types/index.d.cts +7 -1
  142. package/dist/TextField/types/index.d.ts +7 -1
  143. package/dist/TitledPromptCarousel/TitledPromptCarousel.cjs +1 -1
  144. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.cts +2 -2
  145. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.ts +2 -2
  146. package/dist/TitledPromptCarousel/TitledPromptCarousel.js +1 -1
  147. package/dist/Tokens/index.cjs +1 -1
  148. package/dist/Tokens/index.js +1 -1
  149. package/dist/TypingAnimation/TypingAnimation.cjs +1 -1
  150. package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
  151. package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
  152. package/dist/TypingAnimation/TypingAnimation.js +1 -1
  153. package/dist/TypingAnimation/hooks/useGetTypographyVariant.cjs +1 -1
  154. package/dist/TypingAnimation/hooks/useGetTypographyVariant.js +1 -1
  155. package/dist/Typography/Typography.d.cts +4 -4
  156. package/dist/Typography/Typography.d.ts +4 -4
  157. package/dist/WelcomeMessage/components/Container.cjs +2 -2
  158. package/dist/WelcomeMessage/components/Container.js +2 -2
  159. package/dist/WidgetTextField/WidgetTextField.cjs +4 -4
  160. package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
  161. package/dist/WidgetTextField/WidgetTextField.js +1 -1
  162. package/dist/WidgetTextField/components/Container.cjs +2 -2
  163. package/dist/WidgetTextField/components/Container.js +2 -2
  164. package/dist/WidgetTextField/components/Icon.cjs +1 -1
  165. package/dist/WidgetTextField/components/Icon.js +1 -1
  166. package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
  167. package/dist/WidgetWrapper/WidgetWrapper.d.ts +2 -2
  168. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
  169. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts +2 -2
  170. package/package.json +1 -1
  171. package/src/components/ChatFooter/ChatFooter.tsx +1 -0
  172. package/src/components/ChatFooter/components/TextField.tsx +4 -1
  173. package/src/components/ChatFooter/types/types.ts +3 -2
  174. package/src/components/FullPageSalesAgent/FullPageSalesAgent.tsx +75 -7
  175. package/src/components/FullPageSalesAgent/components/WelcomeOverlay.tsx +22 -0
  176. package/src/components/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.ts +1 -0
  177. package/src/components/TextField/TextField.tsx +7 -1
  178. package/src/components/TextField/components/Input.tsx +43 -9
  179. package/src/components/TextField/components/Layout.tsx +7 -1
  180. package/src/components/TextField/hooks/useAutoResize.ts +14 -0
  181. package/src/components/TextField/hooks/usePlaceholderAnimation.ts +67 -0
  182. package/src/components/TextField/hooks/useTextFieldSubmit.ts +1 -1
  183. package/src/components/TextField/types/index.ts +7 -1
@@ -1,5 +1,5 @@
1
1
  import { WidgetWrapperProps } from "./types/types.cjs";
2
- import * as react_jsx_runtime4 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/WidgetWrapper/WidgetWrapper.d.ts
5
5
 
@@ -16,6 +16,6 @@ declare const WidgetWrapper: ({
16
16
  className,
17
17
  style,
18
18
  ...containerProps
19
- }: WidgetWrapperProps) => react_jsx_runtime4.JSX.Element;
19
+ }: WidgetWrapperProps) => react_jsx_runtime0.JSX.Element;
20
20
  //#endregion
21
21
  export { WidgetWrapper };
@@ -1,5 +1,5 @@
1
1
  import { WidgetWrapperProps } from "./types/types.js";
2
- import * as react_jsx_runtime4 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime16 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/WidgetWrapper/WidgetWrapper.d.ts
5
5
 
@@ -16,6 +16,6 @@ declare const WidgetWrapper: ({
16
16
  className,
17
17
  style,
18
18
  ...containerProps
19
- }: WidgetWrapperProps) => react_jsx_runtime4.JSX.Element;
19
+ }: WidgetWrapperProps) => react_jsx_runtime16.JSX.Element;
20
20
  //#endregion
21
21
  export { WidgetWrapper };
@@ -1,5 +1,5 @@
1
1
  import { WidgetWrapperWithTitleProps } from "./types/types.cjs";
2
- import * as react_jsx_runtime34 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime1 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts
5
5
  declare const WidgetWrapperWithTitle: ({
@@ -14,6 +14,6 @@ declare const WidgetWrapperWithTitle: ({
14
14
  hexCardColor,
15
15
  hideLogo,
16
16
  fullIsLoading
17
- }: WidgetWrapperWithTitleProps) => react_jsx_runtime34.JSX.Element;
17
+ }: WidgetWrapperWithTitleProps) => react_jsx_runtime1.JSX.Element;
18
18
  //#endregion
19
19
  export { WidgetWrapperWithTitle };
@@ -1,5 +1,5 @@
1
1
  import { WidgetWrapperWithTitleProps } from "./types/types.js";
2
- import * as react_jsx_runtime1 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime6 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts
5
5
  declare const WidgetWrapperWithTitle: ({
@@ -14,6 +14,6 @@ declare const WidgetWrapperWithTitle: ({
14
14
  hexCardColor,
15
15
  hideLogo,
16
16
  fullIsLoading
17
- }: WidgetWrapperWithTitleProps) => react_jsx_runtime1.JSX.Element;
17
+ }: WidgetWrapperWithTitleProps) => react_jsx_runtime6.JSX.Element;
18
18
  //#endregion
19
19
  export { WidgetWrapperWithTitle };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envive-ai/react-toolkit-v3",
3
- "version": "0.3.27",
3
+ "version": "0.3.28",
4
4
  "description": "React component library for Envive services.",
5
5
  "keywords": [
6
6
  "react",
@@ -62,6 +62,7 @@ export const ChatFooter = ({
62
62
  className={classNames(textFieldClasses, className)}
63
63
  inputClassName={inputClassName}
64
64
  disabled={disabled || disabledInput}
65
+ multiline
65
66
  enableVoiceInput={voiceInputEnabled}
66
67
  onTranscriptionStarted={onTranscriptionStarted}
67
68
  onTranscriptionCompleted={onTranscriptionCompleted}
@@ -3,7 +3,7 @@ import { Theme } from '../../../../tokens/theme/theme';
3
3
 
4
4
  type TextFieldProps = {
5
5
  theme?: Theme;
6
- placeholder: string;
6
+ placeholder: string | string[];
7
7
  value?: string;
8
8
  onChange?: (value: string) => void;
9
9
  onSubmit?: (value: string) => void;
@@ -15,6 +15,7 @@ type TextFieldProps = {
15
15
  style?: React.CSSProperties;
16
16
  isLoading?: boolean;
17
17
  disabled?: boolean;
18
+ multiline?: boolean;
18
19
  enableVoiceInput?: boolean;
19
20
  onTranscriptionStarted?: () => void;
20
21
  onTranscriptionCompleted?: (transcript: string) => void;
@@ -34,6 +35,7 @@ export const FooterTextField = ({
34
35
  style,
35
36
  isLoading,
36
37
  disabled,
38
+ multiline,
37
39
  enableVoiceInput,
38
40
  onTranscriptionStarted,
39
41
  onTranscriptionCompleted,
@@ -53,6 +55,7 @@ export const FooterTextField = ({
53
55
  style={style}
54
56
  isLoading={isLoading}
55
57
  disabled={disabled}
58
+ multiline={multiline}
56
59
  enableVoiceInput={enableVoiceInput}
57
60
  onTranscriptionStarted={onTranscriptionStarted}
58
61
  onTranscriptionCompleted={onTranscriptionCompleted}
@@ -53,9 +53,10 @@ export type ChatFooterProps = {
53
53
  */
54
54
  onFocus?: () => void;
55
55
  /**
56
- * The placeholder text that goes in the textbox before interaction
56
+ * The placeholder text that goes in the textbox before interaction.
57
+ * Pass an array of strings to cycle through them with a typing animation.
57
58
  */
58
- textFieldPlaceholderText: string;
59
+ textFieldPlaceholderText: string | string[];
59
60
  /**
60
61
  * Whether we want the Envive watermark to show up or not
61
62
  */
@@ -65,6 +65,31 @@ export const FullPageSalesAgent = ({
65
65
  const { trackWidgetInteraction } = useWidgetInteraction();
66
66
  const { onDrag, onHover, onMouseDown, onMouseUp, onTouchStart, onTouchEnd } =
67
67
  usePromptCarouselAnalytics(WidgetInteractionComponent.FULL_PAGE_SALES_AGENT, text => text);
68
+ const getOverlaySuggestionId = useCallback(
69
+ (text: string) => {
70
+ const rawValues = hardcopyContent?.rawValues;
71
+ if (rawValues) {
72
+ for (const raw of Object.values(rawValues)) {
73
+ const list = Array.isArray(raw) ? raw : [raw];
74
+ const found = list.find(s => s.value === text);
75
+ if (found) return found.id;
76
+ }
77
+ }
78
+ return text;
79
+ },
80
+ [hardcopyContent?.rawValues],
81
+ );
82
+ const {
83
+ onDrag: onOverlayDrag,
84
+ onHover: onOverlayHover,
85
+ onMouseDown: onOverlayMouseDown,
86
+ onMouseUp: onOverlayMouseUp,
87
+ onTouchStart: onOverlayTouchStart,
88
+ onTouchEnd: onOverlayTouchEnd,
89
+ } = usePromptCarouselAnalytics(
90
+ WidgetInteractionComponent.FULL_PAGE_SALES_AGENT,
91
+ getOverlaySuggestionId,
92
+ );
68
93
  const setListeningToSpeech = useSetAtom(listeningToSpeechAtom);
69
94
 
70
95
  const {
@@ -116,12 +141,17 @@ export const FullPageSalesAgent = ({
116
141
  chatFooterTextFieldPlaceholderText,
117
142
  disclaimerText,
118
143
  welcomeOverlayTitle,
144
+ welcomeOverlayAnimatedPlaceholder,
119
145
  welcomeOverlayPromptSuggestions,
120
146
  welcomeOverlayProductCarouselTitle,
121
147
  welcomeOverlayProductIds,
122
148
  } = hardcopyContent?.values ?? {};
123
149
 
124
- const overlayEnabled = typeof welcomeOverlayTitle === 'string' && !!welcomeOverlayTitle;
150
+ const overlayTitle =
151
+ Array.isArray(welcomeOverlayTitle) && welcomeOverlayTitle.length > 0
152
+ ? welcomeOverlayTitle[0]
153
+ : welcomeOverlayTitle;
154
+ const overlayEnabled = typeof overlayTitle === 'string' && !!welcomeOverlayTitle;
125
155
 
126
156
  const [showOverlay, setShowOverlay] = useState(overlayEnabled);
127
157
  const { footerStyles, footerClasses } = useGetFooterStyles({ showOverlay });
@@ -230,12 +260,28 @@ export const FullPageSalesAgent = ({
230
260
  );
231
261
 
232
262
  const handleOverlayDismiss = useCallback(() => {
263
+ trackWidgetInteraction({
264
+ eventName: EnviveMetricsEventName.WidgetInteraction,
265
+ trigger: {
266
+ widget: WidgetInteractionComponent.FULL_PAGE_SALES_AGENT,
267
+ widget_interaction: WidgetInteractionType.OVERLAY_DISMISSED,
268
+ },
269
+ });
233
270
  setShowOverlay(false);
234
- }, []);
271
+ }, [trackWidgetInteraction]);
235
272
 
236
- // TODO: Migrate to Widget and submit analytics for stringId tracking
237
273
  const handleOverlaySuggestionClick = useCallback(
238
274
  (buttonText: string) => {
275
+ trackWidgetInteraction({
276
+ eventName: EnviveMetricsEventName.WidgetInteraction,
277
+ trigger: {
278
+ widget: WidgetInteractionComponent.FULL_PAGE_SALES_AGENT,
279
+ widget_interaction: WidgetInteractionType.SUGGESTION_CLICKED,
280
+ widget_interaction_data: {
281
+ suggestion_clicked: { suggestion_id: getOverlaySuggestionId(buttonText) },
282
+ },
283
+ },
284
+ });
239
285
  onTypedMessageSubmitted({
240
286
  query: buttonText,
241
287
  userTyped: true,
@@ -246,7 +292,14 @@ export const FullPageSalesAgent = ({
246
292
  setGeneralSuggestions([]);
247
293
  setShowOverlay(false);
248
294
  },
249
- [onTypedMessageSubmitted, setListeningToSpeech, setAnswerSuggestions, setGeneralSuggestions],
295
+ [
296
+ getOverlaySuggestionId,
297
+ trackWidgetInteraction,
298
+ onTypedMessageSubmitted,
299
+ setListeningToSpeech,
300
+ setAnswerSuggestions,
301
+ setGeneralSuggestions,
302
+ ],
250
303
  );
251
304
 
252
305
  const promptSuggestions = useMemo(() => {
@@ -270,7 +323,11 @@ export const FullPageSalesAgent = ({
270
323
  isPendingResponse || isResponseStreaming || generalSuggestions.length === 0
271
324
  }
272
325
  hideEnviveWatermark={showOverlay || !showEnviveLogo}
273
- textFieldPlaceholderText={chatFooterTextFieldPlaceholderText as string}
326
+ textFieldPlaceholderText={
327
+ showOverlay
328
+ ? welcomeOverlayAnimatedPlaceholder
329
+ : (chatFooterTextFieldPlaceholderText as string)
330
+ }
274
331
  promptSuggestions={promptSuggestions}
275
332
  handleButtonClick={buttonText => {
276
333
  const suggestion = suggestions.find(s => s.content === buttonText && !s.isAnswer);
@@ -381,6 +438,10 @@ export const FullPageSalesAgent = ({
381
438
  </motion.div>
382
439
  );
383
440
 
441
+ const productCarouselTitle = Array.isArray(welcomeOverlayProductCarouselTitle)
442
+ ? welcomeOverlayProductCarouselTitle[0]
443
+ : welcomeOverlayProductCarouselTitle;
444
+
384
445
  return (
385
446
  <LayoutGroup>
386
447
  <FullPageSAComponents.Layout
@@ -408,13 +469,20 @@ export const FullPageSalesAgent = ({
408
469
  theme={resolvedTheme}
409
470
  suggestionButtonType={suggestionButtonType}
410
471
  sparkleColor={sparkleColor}
411
- title={welcomeOverlayTitle as string}
472
+ title={overlayTitle}
412
473
  promptSuggestions={overlayPromptSuggestions}
413
- productCarouselTitle={welcomeOverlayProductCarouselTitle as string | undefined}
474
+ productCarouselTitle={productCarouselTitle}
414
475
  productIds={overlayProductIds}
415
476
  backgroundStyle={backgroundStyle}
416
477
  chatFooter={showOverlay ? motionFooter : null}
417
478
  onSuggestionClick={handleOverlaySuggestionClick}
479
+ onSuggestionHover={onOverlayHover}
480
+ onSuggestionDrag={onOverlayDrag}
481
+ onSuggestionMouseDown={onOverlayMouseDown}
482
+ onSuggestionMouseUp={onOverlayMouseUp}
483
+ onSuggestionTouchStart={onOverlayTouchStart}
484
+ onSuggestionTouchEnd={onOverlayTouchEnd}
485
+ onProductCardClick={handleProductCardClick}
418
486
  />
419
487
  ) : null
420
488
  }
@@ -6,6 +6,7 @@ import { SparkleAnimation } from 'src/components/SparkleAnimation';
6
6
  import { PromptButtonVariant } from '../../PromptButton';
7
7
  import { AnimationSpeed, PromptCarousel, PromptCarouselRows } from '../../PromptCarousel';
8
8
  import { SalesAgentProductCardsCarousel } from '../../FloatingChat/components/SalesAgentProductCardsCarousel';
9
+ import { SalesAgentProductCardProps } from '../../SalesAgentProductCard/types/types';
9
10
  import { useWelcomeOverlayProducts } from '../hooks/useWelcomeOverlayProducts';
10
11
 
11
12
  export interface WelcomeOverlayProps {
@@ -22,6 +23,13 @@ export interface WelcomeOverlayProps {
22
23
  /** The ChatFooter node wrapped in motion.div layoutId — shared-element anchor for the dismiss animation. */
23
24
  chatFooter: React.ReactNode;
24
25
  onSuggestionClick: (text: string) => void;
26
+ onSuggestionHover?: (text: string) => void;
27
+ onSuggestionDrag?: () => void;
28
+ onSuggestionMouseDown?: (text: string) => void;
29
+ onSuggestionMouseUp?: (text: string) => void;
30
+ onSuggestionTouchStart?: (text: string) => void;
31
+ onSuggestionTouchEnd?: (text: string) => void;
32
+ onProductCardClick?: (product: SalesAgentProductCardProps) => void;
25
33
  }
26
34
 
27
35
  export const WelcomeOverlay = ({
@@ -36,6 +44,13 @@ export const WelcomeOverlay = ({
36
44
  sparkleColor,
37
45
  backgroundStyle = { backgroundColor: 'white' },
38
46
  onSuggestionClick,
47
+ onSuggestionHover,
48
+ onSuggestionDrag,
49
+ onSuggestionMouseDown,
50
+ onSuggestionMouseUp,
51
+ onSuggestionTouchStart,
52
+ onSuggestionTouchEnd,
53
+ onProductCardClick,
39
54
  }: WelcomeOverlayProps) => {
40
55
  const { products, isLoading } = useWelcomeOverlayProducts(productIds);
41
56
  const showProductCarousel = !isLoading && products.length > 0 && !!productCarouselTitle;
@@ -98,6 +113,12 @@ export const WelcomeOverlay = ({
98
113
  promptCarouselRows={PromptCarouselRows.ALWAYS_TWO}
99
114
  animationSpeed={AnimationSpeed.NONE}
100
115
  handleButtonClick={onSuggestionClick}
116
+ handleButtonHover={onSuggestionHover}
117
+ handleButtonDrag={onSuggestionDrag}
118
+ handleButtonMouseDown={onSuggestionMouseDown}
119
+ handleButtonMouseUp={onSuggestionMouseUp}
120
+ handleButtonTouchStart={onSuggestionTouchStart}
121
+ handleButtonTouchEnd={onSuggestionTouchEnd}
101
122
  />
102
123
  )}
103
124
  </div>
@@ -110,6 +131,7 @@ export const WelcomeOverlay = ({
110
131
  hideBadgeCount
111
132
  products={products}
112
133
  hideNavigation={false}
134
+ onProductCardClick={onProductCardClick}
113
135
  />
114
136
  </div>
115
137
  )}
@@ -7,6 +7,7 @@ type RetrievedProduct = Awaited<
7
7
  >['products'][0];
8
8
 
9
9
  const mapToCardProps = (p: RetrievedProduct): SalesAgentProductCardProps => ({
10
+ id: p.id,
10
11
  productName: p.title ?? '',
11
12
  currentPrice: p.salePrice ?? 0,
12
13
  previousPrice: p.originalPrice === p.salePrice ? undefined : p.originalPrice,
@@ -8,6 +8,7 @@ import { useGetSkeletonProperties } from './hooks/useGetSkeletonProperties';
8
8
  import { useTextFieldFocus } from './hooks/useTextFieldFocus';
9
9
  import { useTextFieldSubmit } from './hooks/useTextFieldSubmit';
10
10
  import { useTextFieldValue } from './hooks/useTextFieldValue';
11
+ import { usePlaceholderAnimation } from './hooks/usePlaceholderAnimation';
11
12
  import { useVoiceInput } from './hooks/useVoiceInput';
12
13
  import type { TextFieldProps } from './types';
13
14
 
@@ -30,10 +31,13 @@ export const TextField = ({
30
31
  style,
31
32
  ariaLabel,
32
33
  isLoading = false,
34
+ multiline = false,
33
35
  enableVoiceInput = false,
34
36
  onTranscriptionStarted,
35
37
  onTranscriptionCompleted,
36
38
  }: TextFieldProps): JSX.Element => {
39
+ const resolvedPlaceholder = usePlaceholderAnimation(placeholder);
40
+
37
41
  const { currentValue, hasValue, handleChange, resetValue } = useTextFieldValue(
38
42
  controlledValue,
39
43
  onChange,
@@ -88,7 +92,7 @@ export const TextField = ({
88
92
  const input = (
89
93
  <TextFieldComponents.Input
90
94
  theme={resolvedTheme}
91
- placeholder={isLoading ? '' : placeholder}
95
+ placeholder={isLoading ? '' : resolvedPlaceholder}
92
96
  value={isLoading ? '' : currentValue}
93
97
  onChange={handleChange}
94
98
  onKeyDown={handleKeyDown}
@@ -97,6 +101,7 @@ export const TextField = ({
97
101
  disabled={disabled || isLoading}
98
102
  ariaLabel={ariaLabel}
99
103
  className={inputClassName}
104
+ multiline={multiline}
100
105
  />
101
106
  );
102
107
 
@@ -138,6 +143,7 @@ export const TextField = ({
138
143
  isFocused={isFocused}
139
144
  hasValue={hasValue}
140
145
  disabled={disabled}
146
+ multiline={multiline}
141
147
  id={id}
142
148
  testId={testId}
143
149
  className={classNames(className, skeletonClass, disabled && 'envive-tw-cursor-not-allowed')}
@@ -1,6 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { getInputClasses } from '../utils/getInputClasses';
3
3
  import { createInputChangeHandler } from '../utils/createInputChangeHandler';
4
+ import { useAutoResize } from '../hooks/useAutoResize';
4
5
  import { Theme } from '../../../../tokens/theme/theme';
5
6
 
6
7
  type InputProps = {
@@ -8,10 +9,11 @@ type InputProps = {
8
9
  placeholder: string;
9
10
  value?: string;
10
11
  onChange?: (value: string) => void;
11
- onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
12
- onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
13
- onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
12
+ onKeyDown?: (event: React.KeyboardEvent<HTMLElement>) => void;
13
+ onFocus?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
14
+ onBlur?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
14
15
  disabled?: boolean;
16
+ multiline?: boolean;
15
17
  id?: string;
16
18
  testId?: string;
17
19
  className?: string;
@@ -28,6 +30,7 @@ export const Input = ({
28
30
  onFocus,
29
31
  onBlur,
30
32
  disabled = false,
33
+ multiline = false,
31
34
  id,
32
35
  testId,
33
36
  className,
@@ -36,6 +39,42 @@ export const Input = ({
36
39
  }: InputProps): JSX.Element => {
37
40
  const { inputClasses } = getInputClasses(theme);
38
41
  const handleChange = createInputChangeHandler(disabled, onChange);
42
+ const textareaRef = useAutoResize(multiline ? value : undefined);
43
+
44
+ const sharedClasses = classNames(
45
+ inputClasses,
46
+ 'focus-visible:envive-tw-shadow-none focus-visible:envive-tw-outline-none',
47
+ className,
48
+ disabled && 'envive-tw-cursor-not-allowed',
49
+ );
50
+
51
+ if (multiline) {
52
+ return (
53
+ <textarea
54
+ ref={textareaRef}
55
+ id={id}
56
+ data-testid={testId}
57
+ placeholder={placeholder}
58
+ value={value}
59
+ rows={1}
60
+ onChange={e => {
61
+ if (!disabled) onChange?.(e.target.value);
62
+ }}
63
+ onKeyDown={e => {
64
+ if (e.key === 'Enter' && !e.shiftKey) {
65
+ onKeyDown?.(e);
66
+ }
67
+ }}
68
+ onFocus={onFocus}
69
+ onBlur={onBlur}
70
+ disabled={disabled}
71
+ className={sharedClasses}
72
+ style={{ resize: 'none', overflow: 'hidden', padding: 0, ...style }}
73
+ aria-label={ariaLabel}
74
+ aria-disabled={disabled}
75
+ />
76
+ );
77
+ }
39
78
 
40
79
  return (
41
80
  <input
@@ -49,12 +88,7 @@ export const Input = ({
49
88
  onFocus={onFocus}
50
89
  onBlur={onBlur}
51
90
  disabled={disabled}
52
- className={classNames(
53
- inputClasses,
54
- 'focus-visible:envive-tw-shadow-none focus-visible:envive-tw-outline-none',
55
- className,
56
- disabled && 'envive-tw-cursor-not-allowed',
57
- )}
91
+ className={sharedClasses}
58
92
  style={style}
59
93
  aria-label={ariaLabel}
60
94
  aria-disabled={disabled}
@@ -11,6 +11,7 @@ type LayoutProps = {
11
11
  isFocused: boolean;
12
12
  hasValue: boolean;
13
13
  disabled?: boolean;
14
+ multiline?: boolean;
14
15
  id?: string;
15
16
  testId?: string;
16
17
  className?: string;
@@ -25,6 +26,7 @@ export const Layout = ({
25
26
  isFocused,
26
27
  hasValue,
27
28
  disabled = false,
29
+ multiline = false,
28
30
  id,
29
31
  testId,
30
32
  className,
@@ -61,7 +63,11 @@ export const Layout = ({
61
63
  disabled && containerDisabledClasses,
62
64
  className,
63
65
  )}
64
- style={style}
66
+ style={
67
+ multiline
68
+ ? { height: 'auto', minHeight: '40px', alignItems: 'flex-end', ...style }
69
+ : style
70
+ }
65
71
  >
66
72
  {input}
67
73
  {sendIcon}
@@ -0,0 +1,14 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ export const useAutoResize = (value: string | undefined): React.RefObject<HTMLTextAreaElement> => {
4
+ const ref = useRef<HTMLTextAreaElement>(null);
5
+
6
+ useEffect(() => {
7
+ const el = ref.current;
8
+ if (!el) return;
9
+ el.style.height = 'auto';
10
+ el.style.height = `${el.scrollHeight}px`;
11
+ }, [value]);
12
+
13
+ return ref;
14
+ };
@@ -0,0 +1,67 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ import { useEffect, useRef, useState } from 'react';
3
+
4
+ const DEFAULT_TYPING_DURATION = 400;
5
+ const DEFAULT_TRANSITION = 3000;
6
+ const CLEAR_PAUSE = 200;
7
+
8
+ export const usePlaceholderAnimation = (
9
+ placeholder: string | string[],
10
+ typingDuration = DEFAULT_TYPING_DURATION,
11
+ transition = DEFAULT_TRANSITION,
12
+ ): string => {
13
+ const [current, setCurrent] = useState(() => (Array.isArray(placeholder) ? '' : placeholder));
14
+ const timeoutsRef = useRef<NodeJS.Timeout[]>([]);
15
+ const isMountedRef = useRef(true);
16
+
17
+ useEffect(() => {
18
+ if (!Array.isArray(placeholder)) {
19
+ setCurrent(placeholder);
20
+ return () => {};
21
+ }
22
+
23
+ if (placeholder.length === 0) {
24
+ setCurrent('');
25
+ return () => {};
26
+ }
27
+
28
+ isMountedRef.current = true;
29
+ timeoutsRef.current = [];
30
+
31
+ const delay = (ms: number): Promise<void> =>
32
+ new Promise(resolve => {
33
+ const id = setTimeout(resolve, ms);
34
+ timeoutsRef.current.push(id);
35
+ });
36
+
37
+ const animateChars = async (text: string) => {
38
+ const charDelay = text.length > 1 ? typingDuration / (text.length - 1) : 0;
39
+ for (let i = 0; i < text.length; i += 1) {
40
+ await delay(charDelay);
41
+ if (isMountedRef.current) setCurrent(text.substring(0, i + 1));
42
+ }
43
+ };
44
+
45
+ const run = async () => {
46
+ while (isMountedRef.current) {
47
+ for (const element of placeholder) {
48
+ if (!isMountedRef.current) return;
49
+ await animateChars(element);
50
+ await delay(transition);
51
+ if (isMountedRef.current) setCurrent('');
52
+ await delay(CLEAR_PAUSE);
53
+ }
54
+ }
55
+ };
56
+
57
+ run();
58
+
59
+ return () => {
60
+ isMountedRef.current = false;
61
+ timeoutsRef.current.forEach(clearTimeout);
62
+ timeoutsRef.current = [];
63
+ };
64
+ }, [placeholder, typingDuration, transition]);
65
+
66
+ return current;
67
+ };
@@ -20,7 +20,7 @@ export const useTextFieldSubmit = (
20
20
  }, [onSubmit, hasValue, disabled, isLoading, currentValue, resetValue]);
21
21
 
22
22
  const handleKeyDown = useCallback(
23
- (event: React.KeyboardEvent<HTMLInputElement>) => {
23
+ (event: React.KeyboardEvent<HTMLElement>) => {
24
24
  if (event.key === 'Enter' && hasValue && !disabled && !isLoading) {
25
25
  event.preventDefault();
26
26
  handleSubmit();
@@ -8,8 +8,9 @@ export type TextFieldProps = {
8
8
  theme?: Theme;
9
9
  /**
10
10
  * Placeholder text displayed when the input is empty.
11
+ * Pass an array of strings to cycle through them with a typing animation.
11
12
  */
12
- placeholder: string;
13
+ placeholder: string | string[];
13
14
  /**
14
15
  * Controlled value of the input. If not provided, the component manages its own state.
15
16
  */
@@ -47,6 +48,11 @@ export type TextFieldProps = {
47
48
  * @default false
48
49
  */
49
50
  isLoading?: boolean;
51
+ /**
52
+ * When true the input expands to multiple lines instead of scrolling horizontally.
53
+ * @default false
54
+ */
55
+ multiline?: boolean;
50
56
  /**
51
57
  * Enable voice input button
52
58
  * @default false