@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.
- package/dist/AnimatedText/AnimatedText.d.cts +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 +4 -3
- 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/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
- package/dist/Container/Container.d.cts +219 -219
- package/dist/Container/Container.d.ts +57 -57
- 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 +43 -8
- package/dist/FullPageSalesAgent/FullPageSalesAgent.d.cts +2 -2
- package/dist/FullPageSalesAgent/FullPageSalesAgent.d.ts +2 -2
- package/dist/FullPageSalesAgent/FullPageSalesAgent.js +43 -8
- package/dist/FullPageSalesAgent/components/WelcomeOverlay.cjs +10 -3
- package/dist/FullPageSalesAgent/components/WelcomeOverlay.js +10 -3
- 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.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.d.ts +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.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/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 +75 -7
- package/src/components/FullPageSalesAgent/components/WelcomeOverlay.tsx +22 -0
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WidgetWrapperProps } from "./types/types.cjs";
|
|
2
|
-
import * as
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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
|
|
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) =>
|
|
17
|
+
}: WidgetWrapperWithTitleProps) => react_jsx_runtime6.JSX.Element;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { WidgetWrapperWithTitle };
|
package/package.json
CHANGED
|
@@ -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
|
|
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
|
|
@@ -408,13 +469,20 @@ export const FullPageSalesAgent = ({
|
|
|
408
469
|
theme={resolvedTheme}
|
|
409
470
|
suggestionButtonType={suggestionButtonType}
|
|
410
471
|
sparkleColor={sparkleColor}
|
|
411
|
-
title={
|
|
472
|
+
title={overlayTitle}
|
|
412
473
|
promptSuggestions={overlayPromptSuggestions}
|
|
413
|
-
productCarouselTitle={
|
|
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 ? '' :
|
|
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
|