@envive-ai/react-toolkit-v3 0.3.27 → 0.3.29
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.
- package/dist/AnimatedText/AnimatedText.d.cts +3 -3
- package/dist/AnimatedText/AnimatedText.d.ts +3 -3
- package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.cts +2 -2
- package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.ts +2 -2
- package/dist/Carousel/Carousel.cjs +1 -1
- package/dist/Carousel/Carousel.d.cts +2 -2
- package/dist/Carousel/Carousel.d.ts +2 -2
- package/dist/Carousel/Carousel.js +1 -1
- package/dist/Carousel/components/Container.cjs +2 -2
- package/dist/Carousel/components/Container.js +2 -2
- package/dist/ChatFooter/ChatFooter.cjs +2 -1
- package/dist/ChatFooter/ChatFooter.d.cts +2 -2
- package/dist/ChatFooter/ChatFooter.d.ts +2 -2
- package/dist/ChatFooter/ChatFooter.js +2 -1
- package/dist/ChatFooter/components/Layout.cjs +2 -2
- package/dist/ChatFooter/components/Layout.js +2 -2
- package/dist/ChatFooter/components/index.d.cts +6 -5
- package/dist/ChatFooter/components/index.d.ts +6 -5
- package/dist/ChatFooter/types/types.d.cts +3 -2
- package/dist/ChatFooter/types/types.d.ts +3 -2
- package/dist/ChatHeader/ChatHeader.d.cts +2 -2
- package/dist/ChatHeader/ChatHeader.d.ts +2 -2
- package/dist/ChatHeader/components/Handle.cjs +2 -2
- package/dist/ChatHeader/components/Handle.js +2 -2
- package/dist/ChatHeader/components/Toggle.cjs +3 -3
- package/dist/ChatHeader/components/Toggle.js +3 -3
- package/dist/ChatPreview/ChatPreview.cjs +1 -1
- package/dist/ChatPreview/ChatPreview.d.cts +2 -2
- package/dist/ChatPreview/ChatPreview.d.ts +2 -2
- package/dist/ChatPreview/ChatPreview.js +1 -1
- package/dist/ChatPreviewComparison/ChatPreviewComparison.cjs +1 -1
- package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
- package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
- package/dist/ChatPreviewComparison/ChatPreviewComparison.js +1 -1
- package/dist/ChatPreviewComparison/components/Headline.cjs +2 -2
- package/dist/ChatPreviewComparison/components/Headline.js +2 -2
- package/dist/ChatPreviewComparison/components/Layout.cjs +4 -4
- package/dist/ChatPreviewComparison/components/Layout.js +4 -4
- package/dist/ChatPreviewComparison/components/Message.cjs +2 -2
- package/dist/ChatPreviewComparison/components/Message.js +2 -2
- package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
- package/dist/Container/Container.d.cts +218 -218
- package/dist/Container/Container.d.ts +51 -51
- package/dist/DesignTokens/DesignTokensComponent.d.cts +2 -2
- package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
- package/dist/Disclaimer/components/Container.cjs +2 -2
- package/dist/Disclaimer/components/Container.js +2 -2
- package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
- package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
- package/dist/DocumentRetrievalCard/components/Layout.cjs +2 -2
- package/dist/DocumentRetrievalCard/components/Layout.js +2 -2
- package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.cjs +1 -1
- package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.js +1 -1
- package/dist/DocumentRetrievalCard/components/ViewArticleButton.cjs +1 -1
- package/dist/DocumentRetrievalCard/components/ViewArticleButton.js +1 -1
- package/dist/FloatingButton/FloatingButton.d.cts +2 -2
- package/dist/FloatingButton/FloatingButton.d.ts +2 -2
- package/dist/FloatingChat/FloatingChat.d.cts +2 -2
- package/dist/FloatingChat/FloatingChat.d.ts +2 -2
- package/dist/FloatingChat/components/ChatMessages.cjs +1 -1
- package/dist/FloatingChat/components/ChatMessages.js +1 -1
- package/dist/FloatingChat/components/Layout.cjs +3 -3
- package/dist/FloatingChat/components/Layout.js +3 -3
- package/dist/FloatingChat/components/ResultsGridView.cjs +1 -1
- package/dist/FloatingChat/components/ResultsGridView.js +1 -1
- package/dist/FloatingChat/components/SalesAgentBadgeContent.cjs +1 -1
- package/dist/FloatingChat/components/SalesAgentBadgeContent.js +1 -1
- package/dist/FullPageSalesAgent/FullPageSalesAgent.cjs +44 -10
- package/dist/FullPageSalesAgent/FullPageSalesAgent.d.cts +2 -2
- package/dist/FullPageSalesAgent/FullPageSalesAgent.d.ts +2 -2
- package/dist/FullPageSalesAgent/FullPageSalesAgent.js +44 -10
- package/dist/FullPageSalesAgent/components/Layout.cjs +24 -27
- package/dist/FullPageSalesAgent/components/Layout.js +24 -27
- package/dist/FullPageSalesAgent/components/WelcomeOverlay.cjs +37 -20
- package/dist/FullPageSalesAgent/components/WelcomeOverlay.js +37 -20
- package/dist/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.cjs +1 -0
- package/dist/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.js +1 -0
- package/dist/Image/Image.d.cts +2 -2
- package/dist/Image/Image.d.ts +2 -2
- package/dist/ImageGallery/ImageGallery.d.cts +2 -2
- package/dist/ImageGallery/ImageGallery.d.ts +2 -2
- package/dist/ImageGallery/components/Layout.cjs +1 -1
- package/dist/ImageGallery/components/Layout.js +1 -1
- package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +2 -2
- package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +2 -2
- package/dist/Message/components/LinkButton.cjs +2 -2
- package/dist/Message/components/LinkButton.js +2 -2
- package/dist/OrderLookupCard/OrderLookupCard.cjs +1 -1
- package/dist/OrderLookupCard/OrderLookupCard.js +1 -1
- package/dist/ProductCard/ProductCard.cjs +2 -2
- package/dist/ProductCard/ProductCard.d.cts +2 -2
- package/dist/ProductCard/ProductCard.d.ts +2 -2
- package/dist/ProductCard/ProductCard.js +2 -2
- package/dist/PromptButton/PromptButton.d.cts +2 -2
- package/dist/PromptButton/PromptButton.d.ts +2 -2
- package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
- package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
- package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.cjs +1 -1
- package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.js +1 -1
- package/dist/PromptCarousel/PromptCarousel.cjs +3 -3
- package/dist/PromptCarousel/PromptCarousel.d.cts +2 -2
- package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
- package/dist/PromptCarousel/PromptCarousel.js +3 -3
- package/dist/ReviewCard/ReviewCard.d.cts +2 -2
- package/dist/ReviewCard/ReviewCard.d.ts +2 -2
- package/dist/ReviewCard/components/Container.cjs +2 -2
- package/dist/ReviewCard/components/Container.js +2 -2
- package/dist/ReviewCard/components/ReadMoreButton.cjs +1 -1
- package/dist/ReviewCard/components/ReadMoreButton.js +1 -1
- package/dist/ReviewCard/components/index.d.cts +6 -6
- package/dist/ReviewCard/components/index.d.ts +6 -6
- package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
- package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
- package/dist/SalesAgentProductCard/components/Container.cjs +2 -2
- package/dist/SalesAgentProductCard/components/Container.js +2 -2
- package/dist/SalesAgentProductCard/components/index.d.cts +6 -6
- package/dist/SalesAgentProductCard/components/index.d.ts +8 -8
- package/dist/SocialProof/SocialProof.cjs +1 -1
- package/dist/SocialProof/SocialProof.d.cts +2 -2
- package/dist/SocialProof/SocialProof.d.ts +2 -2
- package/dist/SocialProof/SocialProof.js +1 -1
- package/dist/SocialProof/components/Headline.cjs +3 -3
- package/dist/SocialProof/components/Headline.js +3 -3
- package/dist/SocialProof/components/LayoutFourHorizontal.cjs +1 -1
- package/dist/SocialProof/components/LayoutFourHorizontal.js +1 -1
- package/dist/SocialProof/components/Subheadline.cjs +1 -1
- package/dist/SocialProof/components/Subheadline.js +1 -1
- package/dist/SparkleAnimation/SparkleAnimation.d.cts +2 -2
- package/dist/SparkleAnimation/SparkleAnimation.d.ts +2 -2
- package/dist/Stack/Stack.d.cts +2 -2
- package/dist/Stack/Stack.d.ts +2 -2
- package/dist/TextField/TextField.cjs +7 -3
- package/dist/TextField/TextField.d.cts +1 -0
- package/dist/TextField/TextField.d.ts +1 -0
- package/dist/TextField/TextField.js +7 -3
- package/dist/TextField/components/Input.cjs +31 -2
- package/dist/TextField/components/Input.js +31 -2
- package/dist/TextField/components/Layout.cjs +7 -2
- package/dist/TextField/components/Layout.js +7 -2
- package/dist/TextField/hooks/useAutoResize.cjs +17 -0
- package/dist/TextField/hooks/useAutoResize.js +16 -0
- package/dist/TextField/hooks/usePlaceholderAnimation.cjs +58 -0
- package/dist/TextField/hooks/usePlaceholderAnimation.js +57 -0
- package/dist/TextField/types/index.d.cts +7 -1
- package/dist/TextField/types/index.d.ts +7 -1
- package/dist/TitledPromptCarousel/TitledPromptCarousel.cjs +1 -1
- package/dist/TitledPromptCarousel/TitledPromptCarousel.d.cts +2 -2
- package/dist/TitledPromptCarousel/TitledPromptCarousel.js +1 -1
- package/dist/Tokens/index.cjs +1 -1
- package/dist/Tokens/index.js +1 -1
- package/dist/TypingAnimation/TypingAnimation.cjs +1 -1
- package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
- package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
- package/dist/TypingAnimation/TypingAnimation.js +1 -1
- package/dist/TypingAnimation/hooks/useGetTypographyVariant.cjs +1 -1
- package/dist/TypingAnimation/hooks/useGetTypographyVariant.js +1 -1
- package/dist/Typography/Typography.d.cts +4 -4
- package/dist/Typography/Typography.d.ts +4 -4
- package/dist/WelcomeMessage/components/Container.cjs +2 -2
- package/dist/WelcomeMessage/components/Container.js +2 -2
- package/dist/WidgetTextField/WidgetTextField.cjs +4 -4
- package/dist/WidgetTextField/WidgetTextField.d.cts +2 -2
- package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
- package/dist/WidgetTextField/WidgetTextField.js +1 -1
- package/dist/WidgetTextField/components/Container.cjs +2 -2
- package/dist/WidgetTextField/components/Container.js +2 -2
- package/dist/WidgetTextField/components/Icon.cjs +1 -1
- package/dist/WidgetTextField/components/Icon.js +1 -1
- package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
- package/dist/WidgetWrapper/WidgetWrapper.d.ts +2 -2
- package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
- package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts +2 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ChatFooter/ChatFooter.tsx +1 -0
- package/src/components/ChatFooter/components/TextField.tsx +4 -1
- package/src/components/ChatFooter/types/types.ts +3 -2
- package/src/components/FullPageSalesAgent/FullPageSalesAgent.tsx +76 -9
- package/src/components/FullPageSalesAgent/components/Layout.tsx +4 -1
- package/src/components/FullPageSalesAgent/components/WelcomeOverlay.tsx +52 -17
- package/src/components/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.ts +1 -0
- package/src/components/TextField/TextField.tsx +7 -1
- package/src/components/TextField/components/Input.tsx +43 -9
- package/src/components/TextField/components/Layout.tsx +7 -1
- package/src/components/TextField/hooks/useAutoResize.ts +14 -0
- package/src/components/TextField/hooks/usePlaceholderAnimation.ts +67 -0
- package/src/components/TextField/hooks/useTextFieldSubmit.ts +1 -1
- package/src/components/TextField/types/index.ts +7 -1
|
@@ -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
|
|
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
|
-
[
|
|
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={
|
|
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
|
|
@@ -400,21 +461,27 @@ export const FullPageSalesAgent = ({
|
|
|
400
461
|
headerContainer={headerContainer}
|
|
401
462
|
autoHeight={autoHeight}
|
|
402
463
|
scrollContainerRef={scrollContainerRef}
|
|
403
|
-
backgroundStyle={backgroundStyle}
|
|
404
464
|
overlay={
|
|
405
|
-
overlayEnabled ? (
|
|
465
|
+
overlayEnabled && showOverlay ? (
|
|
406
466
|
<WelcomeOverlay
|
|
407
467
|
show={showOverlay}
|
|
408
468
|
theme={resolvedTheme}
|
|
409
469
|
suggestionButtonType={suggestionButtonType}
|
|
410
470
|
sparkleColor={sparkleColor}
|
|
411
|
-
title={
|
|
471
|
+
title={overlayTitle}
|
|
412
472
|
promptSuggestions={overlayPromptSuggestions}
|
|
413
|
-
productCarouselTitle={
|
|
473
|
+
productCarouselTitle={productCarouselTitle}
|
|
414
474
|
productIds={overlayProductIds}
|
|
415
475
|
backgroundStyle={backgroundStyle}
|
|
416
476
|
chatFooter={showOverlay ? motionFooter : null}
|
|
417
477
|
onSuggestionClick={handleOverlaySuggestionClick}
|
|
478
|
+
onSuggestionHover={onOverlayHover}
|
|
479
|
+
onSuggestionDrag={onOverlayDrag}
|
|
480
|
+
onSuggestionMouseDown={onOverlayMouseDown}
|
|
481
|
+
onSuggestionMouseUp={onOverlayMouseUp}
|
|
482
|
+
onSuggestionTouchStart={onOverlayTouchStart}
|
|
483
|
+
onSuggestionTouchEnd={onOverlayTouchEnd}
|
|
484
|
+
onProductCardClick={handleProductCardClick}
|
|
418
485
|
/>
|
|
419
486
|
) : null
|
|
420
487
|
}
|
|
@@ -49,6 +49,10 @@ export const Layout = ({
|
|
|
49
49
|
autoHeight,
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
if (overlay) {
|
|
53
|
+
return overlay;
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
return (
|
|
53
57
|
<div
|
|
54
58
|
className={classNames(containerClasses, 'envive-tw-relative')}
|
|
@@ -89,7 +93,6 @@ export const Layout = ({
|
|
|
89
93
|
)}
|
|
90
94
|
{footer}
|
|
91
95
|
</div>
|
|
92
|
-
{overlay}
|
|
93
96
|
</div>
|
|
94
97
|
);
|
|
95
98
|
};
|
|
@@ -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,28 +44,27 @@ 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;
|
|
42
57
|
|
|
43
58
|
const welcomeOverlayClassNames = classNames([
|
|
59
|
+
'envive-overlay',
|
|
44
60
|
'envive-tw-inset-0',
|
|
45
61
|
'envive-tw-absolute',
|
|
46
62
|
'envive-tw-z-20',
|
|
47
63
|
'envive-tw-flex',
|
|
48
64
|
'envive-tw-w-full',
|
|
49
|
-
'envive-tw-h-full',
|
|
50
|
-
'envive-tw-max-w-[768px]',
|
|
51
65
|
'envive-tw-flex-col',
|
|
52
66
|
]);
|
|
53
67
|
|
|
54
|
-
const titleClassNames = classNames([
|
|
55
|
-
'envive-tw-flex',
|
|
56
|
-
'envive-tw-flex-row',
|
|
57
|
-
'envive-tw-gap-2',
|
|
58
|
-
'envive-tw-items-center',
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
68
|
const titleBoxClassNames = classNames([
|
|
62
69
|
'envive-tw-flex',
|
|
63
70
|
'envive-tw-py-4',
|
|
@@ -70,6 +77,22 @@ export const WelcomeOverlay = ({
|
|
|
70
77
|
'envive-tw-border',
|
|
71
78
|
'envive-tw-rounded-global-custom',
|
|
72
79
|
]);
|
|
80
|
+
const overlayContentClassNames = classNames([
|
|
81
|
+
'envive-tw-inset-0',
|
|
82
|
+
'envive-tw-mx-auto',
|
|
83
|
+
'envive-tw-flex',
|
|
84
|
+
'envive-tw-w-full',
|
|
85
|
+
'envive-tw-max-w-[768px]',
|
|
86
|
+
'envive-tw-flex-1',
|
|
87
|
+
'envive-tw-flex-col',
|
|
88
|
+
'envive-tw-gap-6',
|
|
89
|
+
'envive-tw-overflow-y-auto',
|
|
90
|
+
'envive-tw-overflow-x-hidden',
|
|
91
|
+
'envive-tw-px-4',
|
|
92
|
+
'envive-tw-pb-4',
|
|
93
|
+
'envive-tw-pt-6',
|
|
94
|
+
'lg:envive-tw-gap-10',
|
|
95
|
+
]);
|
|
73
96
|
return (
|
|
74
97
|
<AnimatePresence>
|
|
75
98
|
{show && (
|
|
@@ -80,15 +103,20 @@ export const WelcomeOverlay = ({
|
|
|
80
103
|
initial={{ opacity: 1 }}
|
|
81
104
|
exit={{ opacity: 0, transition: { duration: 0.5, ease: 'easeIn' } }}
|
|
82
105
|
>
|
|
83
|
-
<div className=
|
|
106
|
+
<div className={overlayContentClassNames}>
|
|
84
107
|
<div className={titleBoxClassNames}>
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
<Typography
|
|
109
|
+
variant={TypographyVariant.T3_MD}
|
|
110
|
+
as="span"
|
|
111
|
+
>
|
|
112
|
+
{title}
|
|
113
|
+
<span className="envive-tw-ml-1 envive-tw-inline-block envive-tw-align-top">
|
|
114
|
+
<SparkleAnimation
|
|
115
|
+
color={sparkleColor}
|
|
116
|
+
animate={false}
|
|
117
|
+
/>
|
|
118
|
+
</span>
|
|
119
|
+
</Typography>
|
|
92
120
|
{chatFooter}
|
|
93
121
|
{promptSuggestions.length > 0 && (
|
|
94
122
|
<PromptCarousel
|
|
@@ -98,6 +126,12 @@ export const WelcomeOverlay = ({
|
|
|
98
126
|
promptCarouselRows={PromptCarouselRows.ALWAYS_TWO}
|
|
99
127
|
animationSpeed={AnimationSpeed.NONE}
|
|
100
128
|
handleButtonClick={onSuggestionClick}
|
|
129
|
+
handleButtonHover={onSuggestionHover}
|
|
130
|
+
handleButtonDrag={onSuggestionDrag}
|
|
131
|
+
handleButtonMouseDown={onSuggestionMouseDown}
|
|
132
|
+
handleButtonMouseUp={onSuggestionMouseUp}
|
|
133
|
+
handleButtonTouchStart={onSuggestionTouchStart}
|
|
134
|
+
handleButtonTouchEnd={onSuggestionTouchEnd}
|
|
101
135
|
/>
|
|
102
136
|
)}
|
|
103
137
|
</div>
|
|
@@ -110,6 +144,7 @@ export const WelcomeOverlay = ({
|
|
|
110
144
|
hideBadgeCount
|
|
111
145
|
products={products}
|
|
112
146
|
hideNavigation={false}
|
|
147
|
+
onProductCardClick={onProductCardClick}
|
|
113
148
|
/>
|
|
114
149
|
</div>
|
|
115
150
|
)}
|
|
@@ -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 ? '' :
|
|
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<
|
|
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={
|
|
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={
|
|
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<
|
|
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
|