@envive-ai/react-toolkit-v3 0.3.15 → 0.3.16

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 (216) 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 +1 -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 +1 -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 +5 -5
  17. package/dist/ChatFooter/components/index.d.ts +5 -5
  18. package/dist/ChatFooter/hooks/useGetContainerProperties.cjs +1 -1
  19. package/dist/ChatFooter/hooks/useGetContainerProperties.js +1 -1
  20. package/dist/ChatHeader/ChatHeader.d.cts +2 -2
  21. package/dist/ChatHeader/components/Handle.cjs +8 -6
  22. package/dist/ChatHeader/components/Handle.js +8 -6
  23. package/dist/ChatHeader/components/Toggle.cjs +3 -3
  24. package/dist/ChatHeader/components/Toggle.js +3 -3
  25. package/dist/ChatPreview/ChatPreview.cjs +15 -6
  26. package/dist/ChatPreview/ChatPreview.d.cts +2 -2
  27. package/dist/ChatPreview/ChatPreview.d.ts +2 -2
  28. package/dist/ChatPreview/ChatPreview.js +15 -6
  29. package/dist/ChatPreview/components/Message.cjs +3 -2
  30. package/dist/ChatPreview/components/Message.js +3 -2
  31. package/dist/ChatPreview/types/types.d.cts +34 -2
  32. package/dist/ChatPreview/types/types.d.ts +34 -2
  33. package/dist/ChatPreviewComparison/ChatPreviewComparison.cjs +12 -5
  34. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
  35. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
  36. package/dist/ChatPreviewComparison/ChatPreviewComparison.js +12 -5
  37. package/dist/ChatPreviewComparison/components/Headline.cjs +2 -2
  38. package/dist/ChatPreviewComparison/components/Headline.js +2 -2
  39. package/dist/ChatPreviewComparison/components/Layout.cjs +4 -4
  40. package/dist/ChatPreviewComparison/components/Layout.js +4 -4
  41. package/dist/ChatPreviewComparison/components/Message.cjs +5 -4
  42. package/dist/ChatPreviewComparison/components/Message.js +5 -4
  43. package/dist/ChatPreviewComparison/types/types.d.cts +34 -1
  44. package/dist/ChatPreviewComparison/types/types.d.ts +34 -1
  45. package/dist/ChatPreviewLoading/ChatPreviewLoading.cjs +1 -1
  46. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
  47. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
  48. package/dist/ChatPreviewLoading/ChatPreviewLoading.js +1 -1
  49. package/dist/Container/Container.d.cts +173 -173
  50. package/dist/Container/Container.d.ts +173 -173
  51. package/dist/DesignTokens/DesignTokensComponent.d.cts +2 -2
  52. package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
  53. package/dist/Disclaimer/components/Container.cjs +2 -2
  54. package/dist/Disclaimer/components/Container.js +2 -2
  55. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
  56. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
  57. package/dist/DocumentRetrievalCard/components/Layout.cjs +2 -2
  58. package/dist/DocumentRetrievalCard/components/Layout.js +2 -2
  59. package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.cjs +1 -1
  60. package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.js +1 -1
  61. package/dist/FloatingButton/FloatingButton.d.cts +2 -2
  62. package/dist/FloatingButton/FloatingButton.d.ts +2 -2
  63. package/dist/FloatingChat/FloatingChat.cjs +4 -8
  64. package/dist/FloatingChat/FloatingChat.d.cts +2 -2
  65. package/dist/FloatingChat/FloatingChat.d.ts +2 -2
  66. package/dist/FloatingChat/FloatingChat.js +4 -8
  67. package/dist/FloatingChat/components/AgentMessage.cjs +1 -2
  68. package/dist/FloatingChat/components/AgentMessage.js +1 -2
  69. package/dist/FloatingChat/components/ChatMessages.cjs +2 -3
  70. package/dist/FloatingChat/components/ChatMessages.js +2 -3
  71. package/dist/FloatingChat/components/Layout.cjs +3 -3
  72. package/dist/FloatingChat/components/Layout.js +3 -3
  73. package/dist/FloatingChat/components/ModalSheet.cjs +13 -3
  74. package/dist/FloatingChat/components/ModalSheet.js +14 -4
  75. package/dist/FloatingChat/components/SalesAgentProductCardsCarousel.cjs +2 -3
  76. package/dist/FloatingChat/components/SalesAgentProductCardsCarousel.js +2 -3
  77. package/dist/FloatingChat/hooks/useFilteredChatMessages.cjs +1 -1
  78. package/dist/FloatingChat/hooks/useFilteredChatMessages.js +1 -1
  79. package/dist/FloatingChat/hooks/useSnapControl.cjs +17 -16
  80. package/dist/FloatingChat/hooks/useSnapControl.js +17 -16
  81. package/dist/FloatingChat/hooks/useSnapSetup.cjs +9 -27
  82. package/dist/FloatingChat/hooks/useSnapSetup.js +10 -28
  83. package/dist/FloatingChat/snapConstants.cjs +10 -0
  84. package/dist/FloatingChat/snapConstants.js +7 -0
  85. package/dist/FullPageSalesAgent/FullPageSalesAgent.cjs +6 -3
  86. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.ts +2 -2
  87. package/dist/FullPageSalesAgent/FullPageSalesAgent.js +6 -3
  88. package/dist/FullPageSalesAgent/components/Layout.cjs +3 -1
  89. package/dist/FullPageSalesAgent/components/Layout.js +3 -1
  90. package/dist/FullPageSalesAgent/hooks/useGetFooterStyles.cjs +2 -1
  91. package/dist/FullPageSalesAgent/hooks/useGetFooterStyles.js +2 -1
  92. package/dist/FullPageSalesAgent/hooks/useGetMessagesStyles.cjs +10 -0
  93. package/dist/FullPageSalesAgent/hooks/useGetMessagesStyles.js +10 -0
  94. package/dist/FullPageSalesAgent/hooks/useGetScrollContentStyles.cjs +4 -2
  95. package/dist/FullPageSalesAgent/hooks/useGetScrollContentStyles.js +4 -2
  96. package/dist/Image/Image.d.cts +2 -2
  97. package/dist/Image/Image.d.ts +2 -2
  98. package/dist/ImageGallery/ImageGallery.d.cts +2 -2
  99. package/dist/ImageGallery/components/Layout.cjs +1 -1
  100. package/dist/ImageGallery/components/Layout.js +1 -1
  101. package/dist/MarkdownProcessor/MarkdownProcessor.cjs +2 -1
  102. package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +2 -2
  103. package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +2 -2
  104. package/dist/MarkdownProcessor/MarkdownProcessor.js +2 -1
  105. package/dist/Message/components/LinkButton.cjs +1 -1
  106. package/dist/Message/components/LinkButton.js +1 -1
  107. package/dist/OrderLookupCard/OrderLookupCard.cjs +1 -1
  108. package/dist/OrderLookupCard/OrderLookupCard.js +1 -1
  109. package/dist/ProductCard/ProductCard.cjs +10 -4
  110. package/dist/ProductCard/ProductCard.d.cts +8 -2
  111. package/dist/ProductCard/ProductCard.d.ts +8 -2
  112. package/dist/ProductCard/ProductCard.js +10 -4
  113. package/dist/ProductCard/components/Carousel.cjs +9 -3
  114. package/dist/ProductCard/components/Carousel.js +9 -3
  115. package/dist/ProductCard/types/index.d.cts +34 -0
  116. package/dist/ProductCard/types/index.d.ts +34 -0
  117. package/dist/PromptButton/PromptButton.d.cts +2 -2
  118. package/dist/PromptButton/PromptButton.d.ts +2 -2
  119. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
  120. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
  121. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.cjs +1 -1
  122. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.js +1 -1
  123. package/dist/PromptCarousel/PromptCarousel.cjs +3 -3
  124. package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
  125. package/dist/PromptCarousel/PromptCarousel.js +3 -3
  126. package/dist/ReviewCard/ReviewCard.d.cts +2 -2
  127. package/dist/ReviewCard/ReviewCard.d.ts +2 -2
  128. package/dist/ReviewCard/components/Container.cjs +2 -2
  129. package/dist/ReviewCard/components/Container.js +2 -2
  130. package/dist/ReviewCard/components/ReadMoreButton.cjs +1 -1
  131. package/dist/ReviewCard/components/ReadMoreButton.js +1 -1
  132. package/dist/ReviewCard/components/index.d.cts +6 -6
  133. package/dist/ReviewCard/components/index.d.ts +4 -4
  134. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
  135. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
  136. package/dist/SalesAgentProductCard/components/Container.cjs +2 -2
  137. package/dist/SalesAgentProductCard/components/Container.js +2 -2
  138. package/dist/SalesAgentProductCard/components/index.d.cts +6 -6
  139. package/dist/SalesAgentProductCard/components/index.d.ts +6 -6
  140. package/dist/SocialProof/SocialProof.cjs +5 -5
  141. package/dist/SocialProof/SocialProof.d.cts +2 -2
  142. package/dist/SocialProof/SocialProof.d.ts +2 -2
  143. package/dist/SocialProof/SocialProof.js +2 -2
  144. package/dist/SocialProof/components/Headline.cjs +3 -3
  145. package/dist/SocialProof/components/Headline.js +3 -3
  146. package/dist/SocialProof/components/LayoutFourHorizontal.cjs +1 -1
  147. package/dist/SocialProof/components/LayoutFourHorizontal.js +1 -1
  148. package/dist/SocialProof/components/Subheadline.cjs +1 -1
  149. package/dist/SocialProof/components/Subheadline.js +1 -1
  150. package/dist/SparkleAnimation/SparkleAnimation.d.cts +2 -2
  151. package/dist/SparkleAnimation/SparkleAnimation.d.ts +2 -2
  152. package/dist/Stack/Stack.d.ts +2 -2
  153. package/dist/TitledPromptCarousel/TitledPromptCarousel.cjs +1 -1
  154. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.cts +2 -2
  155. package/dist/TitledPromptCarousel/TitledPromptCarousel.js +1 -1
  156. package/dist/Tokens/index.cjs +1 -1
  157. package/dist/Tokens/index.js +1 -1
  158. package/dist/TypingAnimation/TypingAnimation.cjs +9 -3
  159. package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
  160. package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
  161. package/dist/TypingAnimation/TypingAnimation.js +9 -3
  162. package/dist/TypingAnimation/hooks/useGetTypographyVariant.cjs +1 -1
  163. package/dist/TypingAnimation/hooks/useGetTypographyVariant.js +1 -1
  164. package/dist/TypingAnimation/types/index.d.cts +28 -0
  165. package/dist/TypingAnimation/types/index.d.ts +28 -0
  166. package/dist/Typography/Typography.d.ts +4 -4
  167. package/dist/WelcomeMessage/components/Container.cjs +2 -2
  168. package/dist/WelcomeMessage/components/Container.js +2 -2
  169. package/dist/WidgetTextField/WidgetTextField.cjs +1 -1
  170. package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
  171. package/dist/WidgetTextField/WidgetTextField.js +1 -1
  172. package/dist/WidgetTextField/components/Container.cjs +2 -2
  173. package/dist/WidgetTextField/components/Container.js +2 -2
  174. package/dist/WidgetTextField/components/Icon.cjs +3 -3
  175. package/dist/WidgetTextField/components/Icon.js +3 -3
  176. package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
  177. package/dist/WidgetWrapper/WidgetWrapper.d.ts +2 -2
  178. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
  179. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts +2 -2
  180. package/dist/styles.css +1 -1
  181. package/package.json +1 -1
  182. package/src/components/ChatFooter/__tests__/ChatFooter.test.tsx +3 -0
  183. package/src/components/ChatFooter/hooks/useGetContainerProperties.ts +1 -1
  184. package/src/components/ChatHeader/components/Handle.tsx +14 -4
  185. package/src/components/ChatPreview/ChatPreview.tsx +27 -6
  186. package/src/components/ChatPreview/__tests__/ChatPreview.test.tsx +16 -5
  187. package/src/components/ChatPreview/components/Message.tsx +3 -1
  188. package/src/components/ChatPreview/types/types.ts +35 -2
  189. package/src/components/ChatPreviewComparison/ChatPreviewComparison.tsx +23 -6
  190. package/src/components/ChatPreviewComparison/__tests__/ChatPreviewComparison.test.tsx +16 -5
  191. package/src/components/ChatPreviewComparison/components/Message.tsx +7 -1
  192. package/src/components/ChatPreviewComparison/types/types.ts +35 -1
  193. package/src/components/FloatingChat/FloatingChat.tsx +3 -9
  194. package/src/components/FloatingChat/components/AgentMessage.tsx +0 -3
  195. package/src/components/FloatingChat/components/ChatMessages.tsx +0 -3
  196. package/src/components/FloatingChat/components/ModalSheet.tsx +18 -10
  197. package/src/components/FloatingChat/components/SalesAgentProductCardsCarousel.tsx +1 -5
  198. package/src/components/FloatingChat/hooks/useFilteredChatMessages.ts +2 -2
  199. package/src/components/FloatingChat/hooks/useScrollToBottom.ts +1 -0
  200. package/src/components/FloatingChat/hooks/useSnapControl.ts +17 -22
  201. package/src/components/FloatingChat/hooks/useSnapSetup.ts +16 -37
  202. package/src/components/FloatingChat/snapConstants.ts +7 -0
  203. package/src/components/FullPageSalesAgent/FullPageSalesAgent.tsx +5 -2
  204. package/src/components/FullPageSalesAgent/components/Layout.tsx +3 -1
  205. package/src/components/FullPageSalesAgent/hooks/useGetFooterStyles.ts +7 -2
  206. package/src/components/FullPageSalesAgent/hooks/useGetMessagesStyles.ts +11 -0
  207. package/src/components/FullPageSalesAgent/hooks/useGetScrollContentStyles.ts +5 -1
  208. package/src/components/MarkdownProcessor/MarkdownProcessor.tsx +1 -1
  209. package/src/components/Message/__tests__/Message.test.tsx +3 -3
  210. package/src/components/ProductCard/ProductCard.tsx +13 -1
  211. package/src/components/ProductCard/__tests__/ProductCard.test.tsx +73 -1
  212. package/src/components/ProductCard/components/Carousel.tsx +13 -1
  213. package/src/components/ProductCard/types/index.ts +34 -0
  214. package/src/components/TypingAnimation/TypingAnimation.tsx +22 -7
  215. package/src/components/TypingAnimation/types/index.ts +29 -0
  216. package/src/components/WidgetTextField/components/Icon.tsx +2 -2
@@ -136,10 +136,44 @@ export type WidgetEventProps = {
136
136
  * @param text - The text label of the clicked prompt button
137
137
  */
138
138
  handlePromptButtonClick?: (suggestion: Suggestion) => void;
139
+ /**
140
+ * Callback function invoked when the prompt buttons carousel is dragged.
141
+ * Useful for tracking drag-to-scroll interactions.
142
+ */
143
+ handlePromptButtonDrag?: () => void;
144
+ /**
145
+ * Callback function invoked when the user hovers over a prompt button.
146
+ * Receives the hovered button's text as a parameter.
147
+ */
148
+ handlePromptButtonHover?: (text: string) => void;
149
+ /**
150
+ * Callback function invoked when the mouse button is pressed down on a prompt button.
151
+ * Receives the pressed button's text as a parameter.
152
+ */
153
+ handlePromptButtonMouseDown?: (text: string) => void;
154
+ /**
155
+ * Callback function invoked when the mouse button is released after pressing a prompt button.
156
+ */
157
+ handlePromptButtonMouseUp?: () => void;
158
+ /**
159
+ * Callback function invoked when a touch interaction starts on a prompt button.
160
+ * Receives the touched button's text as a parameter.
161
+ */
162
+ handlePromptButtonTouchStart?: (text: string) => void;
163
+ /**
164
+ * Callback function invoked when a touch interaction ends after touching a prompt button.
165
+ */
166
+ handlePromptButtonTouchEnd?: () => void;
139
167
 
140
168
  /**
141
- * Callback function invoked when the text field is clicked.
169
+ * Callback function invoked when a link inside the widget is clicked.
142
170
  *
171
+ * @param url - The URL of the clicked link
172
+ */
173
+ handleLinkClick?: (url: string) => void;
174
+
175
+ /**
176
+ * Callback function invoked when the text field is clicked.
143
177
  */
144
178
  handleTextFieldClick?: () => void;
145
179
  };
@@ -65,7 +65,6 @@ export const FloatingChat = ({
65
65
  showEnviveLogo,
66
66
  ignoreFirstModelResponse,
67
67
  neverShowSingleProductCards,
68
- partialViewConfig,
69
68
  } = floatingChatConfig;
70
69
 
71
70
  const {
@@ -108,8 +107,6 @@ export const FloatingChat = ({
108
107
  }
109
108
  };
110
109
 
111
- const partialViewDisabled = partialViewConfig?.disabled ?? false;
112
-
113
110
  const {
114
111
  modalSheetControl,
115
112
  maxSwipeableViewHeight,
@@ -122,10 +119,8 @@ export const FloatingChat = ({
122
119
  handleSnapChange,
123
120
  animationKey,
124
121
  mobileHeaderHeight,
125
- shouldShowHeader,
126
122
  isFullView,
127
- isPartialView,
128
- } = useSnapSetup({ isFloatingChatOpen, partialViewDisabled });
123
+ } = useSnapSetup({ isFloatingChatOpen });
129
124
 
130
125
  const { showScrollButton, scrollToBottom, isFloatingLayout } = useScrollToBottom({
131
126
  messagesRef: chatMessagesRef,
@@ -137,7 +132,7 @@ export const FloatingChat = ({
137
132
  generalSuggestions,
138
133
  ],
139
134
  scrollThreshold: 100,
140
- useFloatingLayout: isMobile && isPartialView,
135
+ useFloatingLayout: false,
141
136
  footerHeight: 160,
142
137
  isOpen: isFloatingChatOpen,
143
138
  });
@@ -304,7 +299,6 @@ export const FloatingChat = ({
304
299
  ignoreFirstModelResponse={ignoreFirstModelResponse}
305
300
  neverShowSingleProductCards={neverShowSingleProductCards}
306
301
  showVerifiedBuyer={showVerifiedBuyer}
307
- isPartialView={isPartialView}
308
302
  onFormResponseSubmitted={onFormResponseSubmitted}
309
303
  parentWidget={WidgetInteractionComponent.FLOATING_CHAT}
310
304
  />
@@ -367,7 +361,7 @@ export const FloatingChat = ({
367
361
  style={style}
368
362
  testId={testId}
369
363
  theme={finalTheme}
370
- header={shouldShowHeader ? mobileHeader : undefined}
364
+ header={mobileHeader}
371
365
  footer={footer}
372
366
  welcomeMessage={welcomeMessage}
373
367
  chatMessages={chatMessages}
@@ -40,7 +40,6 @@ export interface AgentMessageProps {
40
40
  isPendingResponse?: boolean;
41
41
  neverShowSingleProductCards?: boolean;
42
42
  showVerifiedBuyer?: boolean;
43
- isPartialView?: boolean;
44
43
  onFormResponseSubmitted?: (formResponse: FormSubmittedAttributes) => void;
45
44
  parentWidget: WidgetInteractionComponent;
46
45
  }
@@ -55,7 +54,6 @@ export const AgentMessage = ({
55
54
  isPendingResponse = false,
56
55
  neverShowSingleProductCards = false,
57
56
  showVerifiedBuyer = false,
58
- isPartialView,
59
57
  onFormResponseSubmitted,
60
58
  parentWidget,
61
59
  }: AgentMessageProps) => {
@@ -175,7 +173,6 @@ export const AgentMessage = ({
175
173
  products={products}
176
174
  numberOfProducts={products.length}
177
175
  theme={finalTheme}
178
- isPartialView={isPartialView}
179
176
  onProductCardClick={handleProductCardClick}
180
177
  />
181
178
  );
@@ -30,7 +30,6 @@ export interface ChatMessagesProps {
30
30
  ignoreFirstModelResponse?: boolean;
31
31
  neverShowSingleProductCards?: boolean;
32
32
  showVerifiedBuyer?: boolean;
33
- isPartialView?: boolean;
34
33
  onFormResponseSubmitted?: (formResponse: FormSubmittedAttributes) => void;
35
34
  parentWidget: WidgetInteractionComponent;
36
35
  }
@@ -49,7 +48,6 @@ export const ChatMessages = forwardRef<HTMLDivElement, ChatMessagesProps>(
49
48
  ignoreFirstModelResponse,
50
49
  neverShowSingleProductCards,
51
50
  showVerifiedBuyer,
52
- isPartialView,
53
51
  onFormResponseSubmitted,
54
52
  parentWidget,
55
53
  },
@@ -143,7 +141,6 @@ export const ChatMessages = forwardRef<HTMLDivElement, ChatMessagesProps>(
143
141
  isPendingResponse={isLoading && isLastMessageTurn}
144
142
  neverShowSingleProductCards={neverShowSingleProductCards}
145
143
  showVerifiedBuyer={showVerifiedBuyer}
146
- isPartialView={isPartialView}
147
144
  onFormResponseSubmitted={onFormResponseSubmitted}
148
145
  parentWidget={parentWidget}
149
146
  />
@@ -5,14 +5,12 @@ import {
5
5
  motion,
6
6
  useAnimate,
7
7
  } from 'framer-motion';
8
- import React, { FC, TouchEvent, useEffect, useImperativeHandle } from 'react';
8
+ import React, { FC, TouchEvent, useEffect, useImperativeHandle, useRef } from 'react';
9
9
  import { usePreventScroll } from '../hooks/usePreventScroll';
10
10
  import { Unit } from '../hooks/useSnapCalculator';
11
11
  import { useSnapControl } from '../hooks/useSnapControl';
12
-
13
- export interface ModalSheetControl {
14
- jumpToSnap: (snapIndex: number) => void;
15
- }
12
+ import { FULL_SNAP_INDEX, HIDDEN_SNAP_INDEX } from '../snapConstants';
13
+ import type { ModalSheetControl } from '../snapConstants';
16
14
 
17
15
  interface ModalSheetProps {
18
16
  animationKey: MotionValue;
@@ -47,6 +45,7 @@ export const ModalSheet: FC<ModalSheetProps> = ({
47
45
  }) => {
48
46
  const [layerRef] = useAnimate();
49
47
  const [containerRef] = useAnimate();
48
+ const justDraggedRef = useRef(false);
50
49
 
51
50
  const {
52
51
  gestureRef,
@@ -98,10 +97,15 @@ export const ModalSheet: FC<ModalSheetProps> = ({
98
97
  },
99
98
  }));
100
99
 
101
- const expandToFullView = () => {
102
- const idx = snaps.indexOf(currentSnap);
103
- if (idx === 1) {
104
- jumpTo(getSnapToPixel(2));
100
+ const handleHandlerClick = () => {
101
+ if (justDraggedRef.current) {
102
+ justDraggedRef.current = false;
103
+ return;
104
+ }
105
+ if (snaps.length === 2) {
106
+ // Toggle between open and closed. if full (100): close. if closed (0): open.
107
+ const targetSnap = currentSnap === 100 ? snaps[HIDDEN_SNAP_INDEX] : snaps[FULL_SNAP_INDEX];
108
+ jumpTo(getSnapToPixel(targetSnap));
105
109
  }
106
110
  };
107
111
 
@@ -148,6 +152,10 @@ export const ModalSheet: FC<ModalSheetProps> = ({
148
152
  }, [open]);
149
153
 
150
154
  const handleDragEnd = () => {
155
+ justDraggedRef.current = true;
156
+ setTimeout(() => {
157
+ justDraggedRef.current = false;
158
+ }, 200);
151
159
  const snap = defineNextSnapByPosition();
152
160
  jumpTo(snap);
153
161
  };
@@ -229,7 +237,7 @@ export const ModalSheet: FC<ModalSheetProps> = ({
229
237
  exit={{ y: swipeviewHeightPx }}
230
238
  transition={animation}
231
239
  onDragEnd={handleDragEnd}
232
- onClick={expandToFullView}
240
+ onClick={handleHandlerClick}
233
241
  style={{
234
242
  y: animatedY,
235
243
  bottom: swipeviewHeightPx,
@@ -13,7 +13,6 @@ export interface SalesAgentProductCardsCarouselProps {
13
13
  numberOfProducts?: number;
14
14
  products: SalesAgentProductCardProps[];
15
15
  variant?: SalesAgentProductCardVariant;
16
- isPartialView?: boolean;
17
16
  onProductCardClick?: (product: SalesAgentProductCardProps) => void;
18
17
  }
19
18
 
@@ -23,13 +22,10 @@ export const SalesAgentProductCardsCarousel = ({
23
22
  hideNavigation = false,
24
23
  numberOfProducts,
25
24
  variant = SalesAgentProductCardVariant.LARGE,
26
- isPartialView = false,
27
25
  onProductCardClick,
28
26
  }: SalesAgentProductCardsCarouselProps) => {
29
27
  const finalTheme = resolveTheme(theme);
30
28
 
31
- const finalVariant = isPartialView ? SalesAgentProductCardVariant.SMALL : variant;
32
-
33
29
  const forceShowCurrentPriceSpace = products.some(
34
30
  product => product.currentPrice && product.previousPrice !== product.currentPrice,
35
31
  );
@@ -44,7 +40,7 @@ export const SalesAgentProductCardsCarousel = ({
44
40
  elements={products.map(product => (
45
41
  <SalesAgentProductCard
46
42
  key={product.id}
47
- variant={finalVariant}
43
+ variant={variant}
48
44
  productName={product.productName}
49
45
  currentPrice={product.currentPrice}
50
46
  previousPrice={product.previousPrice}
@@ -1,7 +1,7 @@
1
1
  import { RefObject, useMemo } from 'react';
2
2
  import { Message } from '@envive-ai/react-hooks/application/models';
3
3
  import { useMessageFilter } from '@envive-ai/react-hooks/hooks/MessageFilter';
4
- import { ModalSheetControl } from '../components';
4
+ import type { ModalSheetControl } from '../types';
5
5
 
6
6
  export interface UseFilteredChatMessagesProps {
7
7
  messages: Message[][];
@@ -33,7 +33,7 @@ export const useFilteredChatMessages = ({
33
33
 
34
34
  const hasFilteredMessages = filteredMessages.length !== messages.length && isMobile;
35
35
 
36
- const handlePreviousDiscussions = () => modalSheetControl.current?.jumpToSnap(2);
36
+ const handlePreviousDiscussions = () => modalSheetControl.current?.jumpToSnap(1);
37
37
 
38
38
  return {
39
39
  filteredMessages,
@@ -125,6 +125,7 @@ export const useScrollToBottom = ({
125
125
  }
126
126
  });
127
127
  }
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- autoScrollDependencies is intentionally spread for dynamic deps
128
129
  }, [...autoScrollDependencies, getScrollableContainer, useFloatingLayout]);
129
130
 
130
131
  useEffect(() => {
@@ -8,6 +8,7 @@ import {
8
8
  } from 'framer-motion';
9
9
  import { useMemo, useState } from 'react';
10
10
  import { Unit, useSnapCalculator } from './useSnapCalculator';
11
+ import { FULL_SNAP_INDEX, HIDDEN_SNAP_INDEX } from '../snapConstants';
11
12
 
12
13
  type SnapControl = {
13
14
  animationKey?: MotionValue;
@@ -21,8 +22,6 @@ type SnapControl = {
21
22
  onSnapComplete: (currentSnap: number, nextSnap: number, collapsed: boolean) => void;
22
23
  };
23
24
 
24
- const MIDDLE_SNAP_OFFSET = 5;
25
-
26
25
  export const useSnapControl = ({
27
26
  animationKey,
28
27
  animation,
@@ -45,26 +44,22 @@ export const useSnapControl = ({
45
44
 
46
45
  const contentHeight = useTransform(animatedY, [0, swipeviewHeightPx], [swipeviewHeightPx, 0]);
47
46
 
48
- const snapOverlayReference = useMemo(
49
- () => [
50
- getSnapToPixel(snaps[0]),
51
- getSnapToPixel(snaps[1]) - MIDDLE_SNAP_OFFSET,
52
- getSnapToPixel(snaps[2]),
53
- ],
54
- [getSnapToPixel, snaps],
55
- );
56
-
57
- const displayOverlay = useTransform(() =>
58
- animatedY.get() === -1
59
- ? 'none'
60
- : transform(animatedY.get(), snapOverlayReference, ['none', 'none', 'block']),
61
- );
62
-
63
- const opacityOverlay = useTransform(() =>
64
- animatedY.get() === -1
65
- ? 0
66
- : transform(animatedY.get(), snapOverlayReference, [0, 0, overlayOpacity]),
67
- );
47
+ const snapOverlayReference = useMemo(() => {
48
+ if (snaps.length === 1) {
49
+ return [0, swipeviewHeightPx];
50
+ }
51
+ return [getSnapToPixel(snaps[HIDDEN_SNAP_INDEX]), getSnapToPixel(snaps[FULL_SNAP_INDEX])];
52
+ }, [getSnapToPixel, snaps, swipeviewHeightPx]);
53
+
54
+ const displayOverlay = useTransform(() => {
55
+ if (animatedY.get() === -1) return 'none';
56
+ return transform(animatedY.get(), snapOverlayReference, ['none', 'block']) as string;
57
+ });
58
+
59
+ const opacityOverlay = useTransform(() => {
60
+ if (animatedY.get() === -1) return 0;
61
+ return transform(animatedY.get(), snapOverlayReference, [0, overlayOpacity]) as number;
62
+ });
68
63
 
69
64
  const initSnapInPixels = snapsToPixels?.[initSnap];
70
65
  const getInitSnap = () => snaps?.[initSnap];
@@ -1,7 +1,7 @@
1
- import { useEffect, useRef, useState } from 'react';
1
+ import { useRef, useState } from 'react';
2
2
  import { MotionValue, useMotionValue, useTransform } from 'framer-motion';
3
3
  import { useCheckIsMobile } from '../../utils/useCheckIsMobile';
4
- import { ModalSheetControl } from '../components';
4
+ import { MAX_SWIPEABLE_VIEW_HEIGHT, ModalSheetControl } from '../snapConstants';
5
5
 
6
6
  export interface UseSnapSetupReturn {
7
7
  modalSheetControl: React.RefObject<ModalSheetControl>;
@@ -20,24 +20,19 @@ export interface UseSnapSetupReturn {
20
20
  animationKey: MotionValue<number>;
21
21
  mobileHeaderHeight: MotionValue<number>;
22
22
 
23
- snap43Percent: number;
24
- snap100Percent: number;
25
-
26
- shouldShowHeader: boolean;
27
23
  isFullView: boolean;
28
- isPartialView: boolean;
29
24
  }
30
25
 
31
26
  export interface UseSnapSetupProps {
32
27
  isFloatingChatOpen: boolean;
33
- partialViewDisabled?: boolean;
34
28
  }
35
29
 
36
- export const useSnapSetup = ({
37
- isFloatingChatOpen,
38
- partialViewDisabled,
39
- }: UseSnapSetupProps): UseSnapSetupReturn => {
40
- const maxSwipeableViewHeight = 89;
30
+ export { MAX_SWIPEABLE_VIEW_HEIGHT, HIDDEN_SNAP_INDEX, FULL_SNAP_INDEX } from '../snapConstants';
31
+
32
+ const SNAPS_NO_AUTO_EXPAND = [0, 100];
33
+
34
+ export const useSnapSetup = ({ isFloatingChatOpen }: UseSnapSetupProps): UseSnapSetupReturn => {
35
+ const maxSwipeableViewHeight = MAX_SWIPEABLE_VIEW_HEIGHT;
41
36
  const modalSheetControl = useRef<ModalSheetControl>(null);
42
37
  const { viewportWidth } = useCheckIsMobile();
43
38
 
@@ -49,35 +44,23 @@ export const useSnapSetup = ({
49
44
  ?.selectedCustomizeOption,
50
45
  );
51
46
 
52
- const snaps = (() => {
53
- if (partialViewDisabled) return shouldAutoExpand ? [100] : [0, 100];
54
- return shouldAutoExpand ? [43, 100] : [0, 43, 100];
55
- })();
56
- const partialViewDisabledValue = shouldAutoExpand ? 0 : 1;
57
- const initialSnap = partialViewDisabled ? partialViewDisabledValue : 1;
47
+ const snaps = shouldAutoExpand ? [100] : SNAPS_NO_AUTO_EXPAND;
48
+ const initialSnap = shouldAutoExpand ? 0 : 1;
58
49
 
59
50
  const [currentSnapPercentage, setCurrentSnapPercentage] = useState<number>(
60
- snaps[initialSnap] || 43,
51
+ snaps[initialSnap] ?? 100,
61
52
  );
62
53
 
63
54
  const animationKey = useMotionValue(0);
64
55
 
65
- const snap43Percent = ((100 - 43) / 100) * window.innerHeight;
66
- const snap100Percent = 0;
67
-
68
- const mobileHeaderHeight = useTransform(animationKey, [snap100Percent, snap43Percent], [56, 0]);
69
-
70
- const [shouldShowHeader, setShouldShowHeader] = useState(false);
56
+ // Y=0 when full screen, Y=swipeviewHeightPx when closed (matches useSnapCalculator)
57
+ const swipeviewHeightPx = Math.floor(
58
+ (typeof window !== 'undefined' ? window.innerHeight : 0) * (maxSwipeableViewHeight / 100),
59
+ );
71
60
 
72
- useEffect(() => {
73
- const unsubscribe = animationKey.on('change', value => {
74
- setShouldShowHeader(value < snap43Percent - 10);
75
- });
76
- return unsubscribe;
77
- }, [animationKey, snap43Percent]);
61
+ const mobileHeaderHeight = useTransform(animationKey, [0, swipeviewHeightPx], [56, 0]);
78
62
 
79
63
  const isFullView = isMobile && currentSnapPercentage === 100;
80
- const isPartialView = isMobile && currentSnapPercentage >= 0 && currentSnapPercentage <= 43;
81
64
 
82
65
  const handleSnapChange = (snapPercentage: number) => {
83
66
  setCurrentSnapPercentage(snapPercentage);
@@ -101,10 +84,6 @@ export const useSnapSetup = ({
101
84
  handleSnapChange,
102
85
  animationKey,
103
86
  mobileHeaderHeight,
104
- snap43Percent,
105
- snap100Percent,
106
- shouldShowHeader,
107
87
  isFullView,
108
- isPartialView,
109
88
  };
110
89
  };
@@ -0,0 +1,7 @@
1
+ export const MAX_SWIPEABLE_VIEW_HEIGHT = 89;
2
+ export const HIDDEN_SNAP_INDEX = 0;
3
+ export const FULL_SNAP_INDEX = 1;
4
+
5
+ export interface ModalSheetControl {
6
+ jumpToSnap: (snapIndex: number) => void;
7
+ }
@@ -21,6 +21,7 @@ import { resolveTheme } from '../utils/resolveTheme';
21
21
  import { SparkleIconColor, WelcomeMessage } from '../WelcomeMessage';
22
22
  import { FullPageSAComponents } from './components';
23
23
  import { useGetFooterStyles } from './hooks/useGetFooterStyles';
24
+ import { useGetMessagesStyles } from './hooks/useGetMessagesStyles';
24
25
  import { useIsMobile } from './hooks/useIsMobile';
25
26
 
26
27
  interface FullPageSalesAgentProps {
@@ -44,7 +45,8 @@ export const FullPageSalesAgent = ({
44
45
  const salesAgentData = useSalesAgent(WidgetInteractionComponent.FULL_PAGE_SALES_AGENT);
45
46
  const [query, setQuery] = useState('');
46
47
  const chatMessagesRef = useRef<HTMLDivElement>(null);
47
- const { footerStyles } = useGetFooterStyles();
48
+ const { footerStyles, footerClasses } = useGetFooterStyles();
49
+ const { messageClasses } = useGetMessagesStyles();
48
50
  const { isMobile } = useIsMobile();
49
51
  const { trackWidgetInteraction } = useWidgetInteraction();
50
52
  const { onDrag, onHover, onMouseDown, onMouseUp, onTouchStart, onTouchEnd } =
@@ -135,7 +137,7 @@ export const FullPageSalesAgent = ({
135
137
 
136
138
  const footer = (
137
139
  <ChatFooter
138
- className="envive-tw-bg-background-light"
140
+ className={footerClasses}
139
141
  style={footerStyles}
140
142
  theme={resolvedTheme}
141
143
  isScrolled={isMobile ? isFloatingLayout : false}
@@ -177,6 +179,7 @@ export const FullPageSalesAgent = ({
177
179
 
178
180
  const chatMessages = (
179
181
  <FloatingChatComponents.ChatMessages
182
+ className={messageClasses}
180
183
  theme={resolvedTheme}
181
184
  ref={chatMessagesRef}
182
185
  isLoading={isPendingResponse && !isResponseStreaming}
@@ -5,6 +5,7 @@ import { Stack } from '../../Stack';
5
5
  import { useGetContainerStyles } from '../hooks/useGetContainerStyles';
6
6
  import { useGetFooterStyles } from '../hooks/useGetFooterStyles';
7
7
  import { useGetScrollContentStyles } from '../hooks/useGetScrollContentStyles';
8
+ import { useIsMobile } from '../hooks/useIsMobile';
8
9
 
9
10
  export interface LayoutProps {
10
11
  theme: Theme;
@@ -31,6 +32,7 @@ export const Layout = ({
31
32
  }: LayoutProps) => {
32
33
  const hasWelcomeMessage = isValidElement(welcomeMessage);
33
34
  const hasAnswerSuggestions = isValidElement(answerSuggestions);
35
+ const { isMobile } = useIsMobile();
34
36
  const { contentClasses, messageContainerClasses } = useGetScrollContentStyles();
35
37
  const { footerContainerClasses } = useGetFooterStyles();
36
38
  const { containerClasses, containerStyles } = useGetContainerStyles({
@@ -59,7 +61,7 @@ export const Layout = ({
59
61
  (!hasWelcomeMessage || (hasWelcomeMessage && theme === Theme.STANDARD)) &&
60
62
  !hasAnswerSuggestions &&
61
63
  'envive-tw-pb-4',
62
- 'envive-tw-pt-4',
64
+ isMobile ? 'envive-tw-pt-4' : 'envive-tw-pt-6',
63
65
  )}
64
66
  >
65
67
  {chatMessages}
@@ -6,12 +6,17 @@ export const useGetFooterStyles = () => {
6
6
  ? { boxShadow: '0px 2px 10px 0px rgba(0, 0, 0, 0.2)', borderWidth: '1px' }
7
7
  : null;
8
8
 
9
+ const footerClasses = isMobile
10
+ ? 'envive-tw-rounded-t-[var(--envive-global-custom-border-radius)]'
11
+ : 'envive-tw-rounded-[var(--envive-global-custom-border-radius)]';
12
+
9
13
  const footerContainerClasses = isMobile
10
- ? 'envive-tw-absolute envive-tw-bottom-[0] envive-tw-left-[0] envive-tw-right-[0]'
11
- : 'envive-tw-pb-5';
14
+ ? 'envive-tw-z-10 envive-tw-absolute envive-tw-bottom-[0] envive-tw-left-[0] envive-tw-right-[0]'
15
+ : 'envive-tw-z-10 envive-tw-absolute envive-tw-bottom-5 envive-tw-left-[calc((100vw-768px)/2)] envive-tw-right-[calc((100vw-768px)/2)] envive-tw-max-w-[768px]';
12
16
 
13
17
  return {
14
18
  footerStyles,
19
+ footerClasses,
15
20
  footerContainerClasses,
16
21
  };
17
22
  };
@@ -0,0 +1,11 @@
1
+ import { useIsMobile } from './useIsMobile';
2
+
3
+ export const useGetMessagesStyles = () => {
4
+ const { isMobile } = useIsMobile();
5
+
6
+ const messageClasses = !isMobile ? '!envive-tw-gap-6' : '';
7
+
8
+ return {
9
+ messageClasses,
10
+ };
11
+ };
@@ -5,10 +5,14 @@ export const useGetScrollContentStyles = () => {
5
5
  const { isMobile } = useIsMobile();
6
6
  const contentClasses = classNames({
7
7
  'envive-tw-flex-1 envive-tw-overflow-y-auto envive-tw-overflow-x-hidden envive-tw-transition-all envive-tw-duration-300 envive-tw-ease-in-out': true,
8
+ 'envive-tw-mb-5': !isMobile,
8
9
  'envive-tw-pb-[131px]': isMobile,
10
+ 'envive-tw-pb-[150px]': !isMobile,
9
11
  });
10
12
 
11
- const messageContainerClasses = !isMobile ? 'envive-tw-pt-4' : null;
13
+ const messageContainerClasses = !isMobile
14
+ ? 'envive-tw-rounded-[var(--envive-global-custom-border-radius)] envive-tw-mt-4 envive-tw-overflow-hidden'
15
+ : 'envive-tw-rounded-[var(--envive-global-custom-border-radius)] envive-tw-mx-4 envive-tw-overflow-hidden';
12
16
 
13
17
  return {
14
18
  contentClasses,
@@ -21,7 +21,7 @@ export const MarkdownProcessor = ({
21
21
  a: createMarkdownLinkComponent({ onLinkClick }),
22
22
  p: createMarkdownParagraphComponent({ clampParagraphs, textColor, textVariant }),
23
23
  }),
24
- [clampParagraphs, textColor, textVariant],
24
+ [clampParagraphs, textColor, textVariant, onLinkClick],
25
25
  );
26
26
 
27
27
  return <ReactMarkdown components={components}>{processedContent}</ReactMarkdown>;
@@ -12,13 +12,13 @@ vi.mock('../../MarkdownProcessor/MarkdownProcessor', () => {
12
12
  const urlRegex = /(https?:\/\/[^\s]+)/g;
13
13
  return {
14
14
  MarkdownProcessor: function MockMarkdownProcessor({ content }: { content: string }) {
15
- const matches = [...content.matchAll(urlRegex)];
15
+ const matches = Array.from(content.matchAll(urlRegex));
16
16
  if (matches.length === 0) {
17
17
  return createElement('p', null, content);
18
18
  }
19
19
  const nodes: ReactNode[] = [];
20
20
  let lastIndex = 0;
21
- matches.forEach((m: RegExpMatchArray, i: number) => {
21
+ matches.forEach((m: RegExpMatchArray) => {
22
22
  const url = m[0];
23
23
  const index = m.index ?? 0;
24
24
  nodes.push(content.slice(lastIndex, index));
@@ -26,7 +26,7 @@ vi.mock('../../MarkdownProcessor/MarkdownProcessor', () => {
26
26
  createElement(
27
27
  'span',
28
28
  {
29
- key: i,
29
+ key: `link-${index}-${url}`,
30
30
  role: 'button',
31
31
  'aria-label': `${url} (opens in new tab)`,
32
32
  className: 'hover:envive-tw-underline',
@@ -1,10 +1,10 @@
1
1
  import classNames from 'classnames';
2
2
  import { Theme } from '../Tokens';
3
+ import { TypographyColor } from '../Typography/types';
3
4
  import { resolveTheme } from '../utils/resolveTheme';
4
5
  import { WidgetTextField } from '../WidgetTextField';
5
6
  import { ProductCardWidgetComponents } from './components';
6
7
  import { ProductCardProps } from './types';
7
- import { TypographyColor } from '../Typography/types';
8
8
 
9
9
  export const ProductCard = ({
10
10
  theme = Theme.GLOBAL_CUSTOM,
@@ -21,6 +21,12 @@ export const ProductCard = ({
21
21
  textTransition,
22
22
  loop,
23
23
  onSelect,
24
+ onDrag,
25
+ onHover,
26
+ onMouseDown,
27
+ onMouseUp,
28
+ onTouchStart,
29
+ onTouchEnd,
24
30
  onInputClick,
25
31
  }: ProductCardProps) => {
26
32
  const resolvedTheme = resolveTheme(theme);
@@ -44,6 +50,12 @@ export const ProductCard = ({
44
50
  prompts={prompts}
45
51
  promptButtonType={promptButtonType}
46
52
  onSelect={onSelect}
53
+ onDrag={onDrag}
54
+ onHover={onHover}
55
+ onMouseDown={onMouseDown}
56
+ onMouseUp={onMouseUp}
57
+ onTouchStart={onTouchStart}
58
+ onTouchEnd={onTouchEnd}
47
59
  />
48
60
  <WidgetTextField
49
61
  theme={resolvedTheme}