@envive-ai/react-toolkit-v3 0.3.11 → 0.3.13

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 (119) 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.d.cts +2 -2
  5. package/dist/Carousel/Carousel.d.ts +2 -2
  6. package/dist/Carousel/components/Container.cjs +11 -3
  7. package/dist/Carousel/components/Container.js +12 -4
  8. package/dist/ChatFooter/ChatFooter.d.cts +2 -2
  9. package/dist/ChatFooter/ChatFooter.d.ts +2 -2
  10. package/dist/ChatFooter/components/Layout.cjs +2 -8
  11. package/dist/ChatFooter/components/Layout.js +2 -8
  12. package/dist/ChatFooter/components/index.d.cts +5 -5
  13. package/dist/ChatFooter/components/index.d.ts +3 -3
  14. package/dist/ChatHeader/ChatHeader.d.cts +2 -2
  15. package/dist/ChatHeader/ChatHeader.d.ts +2 -2
  16. package/dist/ChatHeader/hooks/useGetCloseButtonProperties.cjs +1 -1
  17. package/dist/ChatHeader/hooks/useGetCloseButtonProperties.js +1 -1
  18. package/dist/ChatPreview/ChatPreview.d.cts +2 -2
  19. package/dist/ChatPreview/ChatPreview.d.ts +2 -2
  20. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
  21. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
  22. package/dist/ChatPreviewComparison/components/Layout.cjs +4 -3
  23. package/dist/ChatPreviewComparison/components/Layout.js +4 -3
  24. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
  25. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
  26. package/dist/Container/Container.d.cts +178 -178
  27. package/dist/Container/Container.d.ts +8 -8
  28. package/dist/DesignTokens/DesignTokensComponent.d.cts +2 -2
  29. package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
  30. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
  31. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
  32. package/dist/FloatingButton/FloatingButton.d.cts +2 -2
  33. package/dist/FloatingButton/FloatingButton.d.ts +2 -2
  34. package/dist/FloatingChat/FloatingChat.cjs +6 -3
  35. package/dist/FloatingChat/FloatingChat.d.cts +2 -2
  36. package/dist/FloatingChat/FloatingChat.d.ts +2 -2
  37. package/dist/FloatingChat/FloatingChat.js +6 -3
  38. package/dist/FloatingChat/hooks/useSnapSetup.cjs +10 -7
  39. package/dist/FloatingChat/hooks/useSnapSetup.js +10 -7
  40. package/dist/FullPageSalesAgent/FullPageSalesAgent.cjs +3 -2
  41. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.cts +2 -2
  42. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.ts +2 -2
  43. package/dist/FullPageSalesAgent/FullPageSalesAgent.js +3 -2
  44. package/dist/FullPageSalesAgent/hooks/useContainerResizerObserver.cjs +3 -3
  45. package/dist/FullPageSalesAgent/hooks/useContainerResizerObserver.js +3 -3
  46. package/dist/Image/Image.cjs +5 -0
  47. package/dist/Image/Image.d.cts +2 -2
  48. package/dist/Image/Image.d.ts +2 -2
  49. package/dist/Image/Image.js +5 -0
  50. package/dist/ImageGallery/ImageGallery.d.cts +2 -2
  51. package/dist/MarkdownProcessor/MarkdownProcessor.cjs +14 -27
  52. package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +3 -5
  53. package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +1 -3
  54. package/dist/MarkdownProcessor/MarkdownProcessor.js +15 -26
  55. package/dist/MarkdownProcessor/components/index.cjs +1 -3
  56. package/dist/MarkdownProcessor/components/index.js +1 -3
  57. package/dist/MarkdownProcessor/utils/functions.cjs +1 -11
  58. package/dist/MarkdownProcessor/utils/functions.js +1 -10
  59. package/dist/ProductCard/ProductCard.d.cts +2 -2
  60. package/dist/ProductCard/components/Header.cjs +33 -7
  61. package/dist/ProductCard/components/Header.js +34 -8
  62. package/dist/PromptButton/PromptButton.d.cts +2 -2
  63. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
  64. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
  65. package/dist/PromptCarousel/PromptCarousel.cjs +19 -28
  66. package/dist/PromptCarousel/PromptCarousel.d.cts +2 -2
  67. package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
  68. package/dist/PromptCarousel/PromptCarousel.js +19 -28
  69. package/dist/ReviewCard/ReviewCard.d.cts +2 -2
  70. package/dist/ReviewCard/ReviewCard.d.ts +2 -2
  71. package/dist/ReviewCard/components/index.d.cts +6 -6
  72. package/dist/ReviewCard/components/index.d.ts +4 -4
  73. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
  74. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
  75. package/dist/SalesAgentProductCard/components/index.d.cts +8 -8
  76. package/dist/SalesAgentProductCard/components/index.d.ts +6 -6
  77. package/dist/SocialProof/SocialProof.d.cts +2 -2
  78. package/dist/SocialProof/SocialProof.d.ts +2 -2
  79. package/dist/Stack/Stack.d.ts +2 -2
  80. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.ts +2 -2
  81. package/dist/TypingAnimation/TypingAnimation.cjs +58 -18
  82. package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
  83. package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
  84. package/dist/TypingAnimation/TypingAnimation.js +59 -19
  85. package/dist/Typography/Typography.d.cts +4 -4
  86. package/dist/Typography/Typography.d.ts +4 -4
  87. package/dist/WidgetTextField/WidgetTextField.d.cts +2 -2
  88. package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
  89. package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
  90. package/dist/WidgetWrapper/WidgetWrapper.d.ts +2 -2
  91. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
  92. package/dist/styles.css +1 -1
  93. package/dist/utils/useAnimatedTextMinHeight.cjs +28 -0
  94. package/dist/utils/useAnimatedTextMinHeight.js +27 -0
  95. package/package.json +1 -3
  96. package/src/components/Carousel/components/Container.tsx +15 -3
  97. package/src/components/ChatFooter/components/Layout.tsx +2 -14
  98. package/src/components/ChatHeader/hooks/useGetCloseButtonProperties.ts +1 -1
  99. package/src/components/ChatPreviewComparison/components/Layout.tsx +2 -2
  100. package/src/components/FloatingChat/FloatingChat.tsx +5 -2
  101. package/src/components/FloatingChat/hooks/useSnapSetup.ts +11 -4
  102. package/src/components/FullPageSalesAgent/FullPageSalesAgent.tsx +6 -2
  103. package/src/components/FullPageSalesAgent/components/Layout.tsx +1 -1
  104. package/src/components/FullPageSalesAgent/hooks/useContainerResizerObserver.ts +4 -3
  105. package/src/components/FullPageSalesAgent/hooks/useIsMobile.ts +1 -1
  106. package/src/components/Image/Image.tsx +2 -0
  107. package/src/components/MarkdownProcessor/MarkdownProcessor.tsx +3 -19
  108. package/src/components/MarkdownProcessor/__tests__/MarkdownProcessor.test.tsx +1 -39
  109. package/src/components/MarkdownProcessor/components/index.ts +0 -2
  110. package/src/components/MarkdownProcessor/utils/functions.tsx +0 -19
  111. package/src/components/ProductCard/components/Header.tsx +39 -9
  112. package/src/components/PromptCarousel/PromptCarousel.tsx +29 -31
  113. package/src/components/TypingAnimation/TypingAnimation.tsx +68 -22
  114. package/src/components/utils/useAnimatedTextMinHeight.ts +29 -0
  115. package/dist/ChatFooter/hooks/useGetButtonScrollProperties.cjs +0 -18
  116. package/dist/ChatFooter/hooks/useGetButtonScrollProperties.js +0 -17
  117. package/dist/MarkdownProcessor/components/MarkdownSubscript.cjs +0 -15
  118. package/dist/MarkdownProcessor/components/MarkdownSubscript.js +0 -14
  119. package/src/components/MarkdownProcessor/components/MarkdownSubscript.tsx +0 -22
@@ -55,6 +55,7 @@ export const FloatingChat = ({
55
55
  showEnviveLogo,
56
56
  ignoreFirstModelResponse,
57
57
  neverShowSingleProductCards,
58
+ partialViewConfig,
58
59
  } = floatingChatConfig;
59
60
 
60
61
  const {
@@ -95,6 +96,8 @@ export const FloatingChat = ({
95
96
  }
96
97
  };
97
98
 
99
+ const partialViewDisabled = partialViewConfig?.disabled ?? false;
100
+
98
101
  const {
99
102
  modalSheetControl,
100
103
  maxSwipeableViewHeight,
@@ -110,7 +113,7 @@ export const FloatingChat = ({
110
113
  shouldShowHeader,
111
114
  isFullView,
112
115
  isPartialView,
113
- } = useSnapSetup({ isFloatingChatOpen });
116
+ } = useSnapSetup({ isFloatingChatOpen, partialViewDisabled });
114
117
 
115
118
  const { showScrollButton, scrollToBottom, isFloatingLayout } = useScrollToBottom({
116
119
  messagesRef: chatMessagesRef,
@@ -206,7 +209,7 @@ export const FloatingChat = ({
206
209
  }}
207
210
  textFieldPlaceholderText={chatFooterTextFieldPlaceholderText as string}
208
211
  promptSuggestions={
209
- isPendingResponse || isResponseStreaming || generalSuggestions.length === 0
212
+ isPendingResponse || isResponseStreaming
210
213
  ? ['Loading suggestions 1...', 'Loading suggestions 2...'] // This is strings will not be shown to the user
211
214
  : generalSuggestions
212
215
  }
@@ -24,16 +24,19 @@ export interface UseSnapSetupReturn {
24
24
  snap100Percent: number;
25
25
 
26
26
  shouldShowHeader: boolean;
27
- shouldShowScrolled: boolean;
28
27
  isFullView: boolean;
29
28
  isPartialView: boolean;
30
29
  }
31
30
 
32
31
  export interface UseSnapSetupProps {
33
32
  isFloatingChatOpen: boolean;
33
+ partialViewDisabled?: boolean;
34
34
  }
35
35
 
36
- export const useSnapSetup = ({ isFloatingChatOpen }: UseSnapSetupProps): UseSnapSetupReturn => {
36
+ export const useSnapSetup = ({
37
+ isFloatingChatOpen,
38
+ partialViewDisabled,
39
+ }: UseSnapSetupProps): UseSnapSetupReturn => {
37
40
  const maxSwipeableViewHeight = 89;
38
41
  const modalSheetControl = useRef<ModalSheetControl>(null);
39
42
  const { viewportWidth } = useCheckIsMobile();
@@ -46,8 +49,12 @@ export const useSnapSetup = ({ isFloatingChatOpen }: UseSnapSetupProps): UseSnap
46
49
  ?.selectedCustomizeOption,
47
50
  );
48
51
 
49
- const snaps = shouldAutoExpand ? [43, 100] : [0, 43, 100];
50
- const initialSnap = 1;
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;
51
58
 
52
59
  const [currentSnapPercentage, setCurrentSnapPercentage] = useState<number>(
53
60
  snaps[initialSnap] || 43,
@@ -117,7 +117,7 @@ export const FullPageSalesAgent = ({
117
117
  hideEnviveWatermark={!showEnviveLogo}
118
118
  textFieldPlaceholderText={chatFooterTextFieldPlaceholderText as string}
119
119
  promptSuggestions={
120
- isPendingResponse || isResponseStreaming || generalSuggestions.length === 0
120
+ isPendingResponse || isResponseStreaming
121
121
  ? ['Loading suggestions 1...', 'Loading suggestions 2...']
122
122
  : generalSuggestions
123
123
  }
@@ -132,7 +132,11 @@ export const FullPageSalesAgent = ({
132
132
  }}
133
133
  onChange={setQuery}
134
134
  onSubmit={() => {
135
- onTypedMessageSubmitted({ query, userTyped: true });
135
+ onTypedMessageSubmitted({
136
+ query,
137
+ userTyped: true,
138
+ displayLocation: ChatElementDisplayLocationV3.FLOATING_CHAT_TEXT_INPUT,
139
+ });
136
140
  setAnswerSuggestions([]);
137
141
  setGeneralSuggestions([]);
138
142
  }}
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { isValidElement } from 'react';
3
- import { Stack } from 'src/components/Stack';
4
3
  import { Theme } from 'tokens/theme/theme';
4
+ 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';
@@ -11,12 +11,13 @@ export const useContainerResizerObserver = ({
11
11
 
12
12
  useEffect(() => {
13
13
  if (!autoHeight) {
14
- return null;
14
+ return () => {};
15
15
  }
16
16
 
17
17
  const watchResizing = () => {
18
- const header = document.querySelector(headerContainer)?.getBoundingClientRect()?.height || 0;
19
- setContainerHeight(window.innerHeight - header);
18
+ const { height = 0, top = 0 } =
19
+ document.querySelector(headerContainer)?.getBoundingClientRect() || {};
20
+ setContainerHeight(window.innerHeight - (height + top));
20
21
  };
21
22
 
22
23
  window.addEventListener('resize', watchResizing);
@@ -1,3 +1,3 @@
1
- import { useCheckIsMobile } from 'src/components/utils/useCheckIsMobile';
1
+ import { useCheckIsMobile } from '../../utils/useCheckIsMobile';
2
2
 
3
3
  export const useIsMobile = () => useCheckIsMobile('md');
@@ -88,8 +88,10 @@ export const Image = ({
88
88
  objectFitClass,
89
89
  isLoading && 'envive-tw-opacity-0',
90
90
  )}
91
+ style={{ userSelect: 'none', WebkitUserDrag: 'none' } as React.CSSProperties}
91
92
  onLoad={handleLoad}
92
93
  onError={handleError}
94
+ draggable={false}
93
95
  {...accessibilityProps}
94
96
  {...rest}
95
97
  />
@@ -1,21 +1,14 @@
1
1
  import { useMemo } from 'react';
2
2
  import ReactMarkdown from 'react-markdown';
3
- import remarkGfm from 'remark-gfm';
4
- import rehypeRaw from 'rehype-raw';
5
3
  import { MarkdownProcessorProps } from './types/types';
6
4
  import { MarkdownProcessorComponents } from './components';
7
- import {
8
- createMarkdownParagraphComponent,
9
- createMarkdownSubscriptComponent,
10
- } from './utils/functions';
5
+ import { createMarkdownParagraphComponent } from './utils/functions';
11
6
 
12
7
  export const MarkdownProcessor = ({
13
8
  content,
14
9
  clampParagraphs = undefined,
15
10
  textColor,
16
11
  textVariant,
17
- subTextVariant,
18
- subTextColor,
19
12
  }: MarkdownProcessorProps) => {
20
13
  const processedContent = content.replace(/<br\s*[\\/]?>/gi, '\n\n');
21
14
 
@@ -26,18 +19,9 @@ export const MarkdownProcessor = ({
26
19
  ol: MarkdownProcessorComponents.MarkdownOrderedList,
27
20
  a: MarkdownProcessorComponents.MarkdownLink,
28
21
  p: createMarkdownParagraphComponent({ clampParagraphs, textColor, textVariant }),
29
- sub: createMarkdownSubscriptComponent({ subTextVariant, subTextColor }),
30
22
  }),
31
- [clampParagraphs, textColor, textVariant, subTextVariant, subTextColor],
23
+ [clampParagraphs, textColor, textVariant],
32
24
  );
33
25
 
34
- return (
35
- <ReactMarkdown
36
- remarkPlugins={[remarkGfm]}
37
- rehypePlugins={[rehypeRaw]}
38
- components={components}
39
- >
40
- {processedContent}
41
- </ReactMarkdown>
42
- );
26
+ return <ReactMarkdown components={components}>{processedContent}</ReactMarkdown>;
43
27
  };
@@ -69,22 +69,6 @@ describe('MarkdownProcessor', () => {
69
69
  });
70
70
  });
71
71
 
72
- describe('Subscript', () => {
73
- it('should render subscript text', () => {
74
- const content = 'Regular text<sub>subscript</sub>';
75
- render(<MarkdownProcessor content={content} />);
76
- expect(screen.getByText('Regular text')).toBeInTheDocument();
77
- expect(screen.getByText('subscript')).toBeInTheDocument();
78
- });
79
-
80
- it('should render multiple subscript elements', () => {
81
- const content = 'First<sub>sub1</sub> and second<sub>sub2</sub>';
82
- render(<MarkdownProcessor content={content} />);
83
- expect(screen.getByText('sub1')).toBeInTheDocument();
84
- expect(screen.getByText('sub2')).toBeInTheDocument();
85
- });
86
- });
87
-
88
72
  describe('Paragraph clamping', () => {
89
73
  it('should not clamp paragraphs when clampParagraphs is undefined', () => {
90
74
  const content =
@@ -131,34 +115,12 @@ describe('MarkdownProcessor', () => {
131
115
  );
132
116
  expect(screen.getByText('Custom color text')).toBeInTheDocument();
133
117
  });
134
-
135
- it('should apply custom subTextVariant', () => {
136
- const content = 'Text<sub>subscript</sub>';
137
- render(
138
- <MarkdownProcessor
139
- content={content}
140
- subTextVariant={TypographyVariant.B4_RG}
141
- />,
142
- );
143
- expect(screen.getByText('subscript')).toBeInTheDocument();
144
- });
145
-
146
- it('should apply custom subTextColor', () => {
147
- const content = 'Text<sub>subscript</sub>';
148
- render(
149
- <MarkdownProcessor
150
- content={content}
151
- subTextColor={TypographyColor.TEXT_ACCENT}
152
- />,
153
- );
154
- expect(screen.getByText('subscript')).toBeInTheDocument();
155
- });
156
118
  });
157
119
 
158
120
  describe('Complex content', () => {
159
121
  it('should render complex markdown with multiple elements', () => {
160
122
  const content =
161
- '# Heading\n\nThis is a paragraph with **bold** and *italic*.\n\n- List item 1\n- List item 2\n\n1. Ordered item 1\n2. Ordered item 2\n\n[Link text](https://example.com)\n\nText with<sub>subscript</sub>.';
123
+ '# Heading\n\nThis is a paragraph with **bold** and *italic*.\n\n- List item 1\n- List item 2\n\n1. Ordered item 1\n2. Ordered item 2\n\n[Link text](https://example.com)';
162
124
  render(<MarkdownProcessor content={content} />);
163
125
  expect(screen.getByText(/This is a paragraph/i)).toBeInTheDocument();
164
126
  expect(screen.getByText('List item 1')).toBeInTheDocument();
@@ -3,7 +3,6 @@ import { MarkdownLink } from './MarkdownLink';
3
3
  import { MarkdownOrderedList } from './MarkdownOrderedList';
4
4
  import { MarkdownUnorderedList } from './MarkdownUnorderedList';
5
5
  import { MarkdownParagraph } from './MarkdownParagraph';
6
- import { MarkdownSubscript } from './MarkdownSubscript';
7
6
 
8
7
  export const MarkdownProcessorComponents = {
9
8
  MarkdownListItem,
@@ -11,5 +10,4 @@ export const MarkdownProcessorComponents = {
11
10
  MarkdownOrderedList,
12
11
  MarkdownUnorderedList,
13
12
  MarkdownParagraph,
14
- MarkdownSubscript,
15
13
  };
@@ -22,22 +22,3 @@ export const createMarkdownParagraphComponent = ({
22
22
  Component.displayName = 'MarkdownParagraphComponent';
23
23
  return Component;
24
24
  };
25
-
26
- export const createMarkdownSubscriptComponent = ({
27
- subTextVariant,
28
- subTextColor,
29
- }: {
30
- subTextVariant?: TypographyVariant;
31
- subTextColor?: TypographyColor;
32
- }) => {
33
- const Component = ({ children }: { children?: React.ReactNode }) => (
34
- <MarkdownProcessorComponents.MarkdownSubscript
35
- subTextVariant={subTextVariant}
36
- subTextColor={subTextColor}
37
- >
38
- {children}
39
- </MarkdownProcessorComponents.MarkdownSubscript>
40
- );
41
- Component.displayName = 'MarkdownSubscriptComponent';
42
- return Component;
43
- };
@@ -1,7 +1,8 @@
1
- import { useCallback } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { AnimatedText } from '../../AnimatedText';
3
3
  import { Stack } from '../../Stack';
4
4
  import { Typography, TypographyColor, TypographyVariant } from '../../Typography';
5
+ import { useAnimatedTextMinHeight } from '../../utils/useAnimatedTextMinHeight';
5
6
  import { useGetHeaderProperties } from '../hooks/useGetHeaderProperties';
6
7
  import { HeaderProps } from '../types';
7
8
 
@@ -14,13 +15,19 @@ export const Header = ({
14
15
  loop,
15
16
  }: HeaderProps) => {
16
17
  const { stackClasses, headlineClasses } = useGetHeaderProperties(italicizeHeadline);
18
+ const { measuringRef, minHeight } = useAnimatedTextMinHeight(animatedText);
19
+
20
+ const biggestText = useMemo(() => {
21
+ return animatedText.reduce((maxText, currText) => {
22
+ return currText.length > maxText.length ? currText : maxText;
23
+ }, '');
24
+ }, [animatedText]);
17
25
 
18
26
  const animatedTextWrapper = useCallback(
19
27
  (text: string) => (
20
28
  <Typography
21
29
  variant={TypographyVariant.B3_MD}
22
30
  color={TypographyColor.TEXT_LIGHT}
23
- numberOfLines={2}
24
31
  >
25
32
  {text}
26
33
  </Typography>
@@ -42,13 +49,36 @@ export const Header = ({
42
49
  {headline}
43
50
  </Typography>
44
51
  {animatedText.length > 0 && (
45
- <AnimatedText
46
- sequence={animatedText}
47
- getNodeWrapper={animatedTextWrapper}
48
- typingDuration={textTypingDuration}
49
- transition={textTransition}
50
- loop={loop}
51
- />
52
+ <div style={{ position: 'relative' }}>
53
+ <div
54
+ ref={measuringRef}
55
+ aria-hidden="true"
56
+ style={{
57
+ position: 'absolute',
58
+ visibility: 'hidden',
59
+ pointerEvents: 'none',
60
+ width: '100%',
61
+ }}
62
+ >
63
+ <div>
64
+ <Typography
65
+ variant={TypographyVariant.B3_MD}
66
+ color={TypographyColor.TEXT_LIGHT}
67
+ >
68
+ {biggestText}
69
+ </Typography>
70
+ </div>
71
+ </div>
72
+ <div style={{ minHeight }}>
73
+ <AnimatedText
74
+ sequence={animatedText}
75
+ getNodeWrapper={animatedTextWrapper}
76
+ typingDuration={textTypingDuration}
77
+ transition={textTransition}
78
+ loop={loop}
79
+ />
80
+ </div>
81
+ </div>
52
82
  )}
53
83
  </Stack>
54
84
  );
@@ -83,16 +83,20 @@ export const PromptCarousel = ({
83
83
  const buttonKey = `button-${buttonId}`;
84
84
 
85
85
  return (
86
- <PromptButton
87
- id={buttonId}
86
+ <div
88
87
  key={buttonKey}
89
- label={text}
90
- variant={promptButtonType}
91
- theme={finalTheme}
92
- isLoading={isLoading}
93
- bold={boldFirstButton && index === 0 && duplicateIndex === 0}
94
- onClick={() => handleButtonClick?.(text)}
95
- />
88
+ className="envive-tw-flex-shrink-0"
89
+ >
90
+ <PromptButton
91
+ id={buttonId}
92
+ label={text}
93
+ variant={promptButtonType}
94
+ theme={finalTheme}
95
+ isLoading={isLoading}
96
+ bold={boldFirstButton && index === 0 && duplicateIndex === 0}
97
+ onClick={() => handleButtonClick?.(text)}
98
+ />
99
+ </div>
96
100
  );
97
101
  },
98
102
  [id, promptButtonType, boldFirstButton, handleButtonClick, isLoading, finalTheme],
@@ -127,36 +131,30 @@ export const PromptCarousel = ({
127
131
  gap="2"
128
132
  >
129
133
  <div
130
- className="envive-tw-no-scrollbar envive-tw-relative envive-tw-w-full envive-tw-overflow-x-scroll"
131
134
  ref={setRef1}
132
- style={{ cursor: 'grab', userSelect: 'none' }}
135
+ className="[&::-webkit-scrollbar]:hidden envive-tw-flex envive-tw-gap-2 envive-tw-overflow-x-auto"
136
+ style={{
137
+ scrollbarWidth: 'none',
138
+ msOverflowStyle: 'none',
139
+ cursor: 'grab',
140
+ userSelect: 'none',
141
+ }}
133
142
  >
134
- <div className="envive-tw-relative envive-tw-inline-block envive-tw-whitespace-nowrap">
135
- <Stack
136
- direction="row"
137
- gap="2"
138
- className="envive-tw-pl-0 envive-tw-h-full envive-tw-items-center"
139
- >
140
- {renderButtonRow(visibleButtonsFirstRow, 0)}
141
- </Stack>
142
- </div>
143
+ {renderButtonRow(visibleButtonsFirstRow, 0)}
143
144
  </div>
144
145
 
145
146
  {shouldShowTwoRowsValue && (
146
147
  <div
147
- className="envive-tw-no-scrollbar envive-tw-relative envive-tw-w-full envive-tw-overflow-x-scroll"
148
148
  ref={setRef2}
149
- style={{ cursor: 'grab', userSelect: 'none' }}
149
+ className="[&::-webkit-scrollbar]:hidden envive-tw-flex envive-tw-gap-2 envive-tw-overflow-x-auto"
150
+ style={{
151
+ scrollbarWidth: 'none',
152
+ msOverflowStyle: 'none',
153
+ cursor: 'grab',
154
+ userSelect: 'none',
155
+ }}
150
156
  >
151
- <div className="envive-tw-relative envive-tw-inline-block envive-tw-whitespace-nowrap">
152
- <Stack
153
- direction="row"
154
- gap="2"
155
- className="envive-tw-pl-0 envive-tw-h-full envive-tw-items-center"
156
- >
157
- {renderButtonRow(visibleButtonsSecondRow, visibleButtonsFirstRow.length)}
158
- </Stack>
159
- </div>
157
+ {renderButtonRow(visibleButtonsSecondRow, visibleButtonsFirstRow.length)}
160
158
  </div>
161
159
  )}
162
160
  </Stack>
@@ -1,4 +1,4 @@
1
- import { useCallback } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { AnimatedText } from '../AnimatedText';
3
3
  import { Typography, TypographyColor } from '../Typography';
4
4
  import { PromptCarousel, PromptCarouselRows } from '../PromptCarousel';
@@ -9,6 +9,7 @@ import { Theme } from '../Tokens';
9
9
  import { WidgetWrapperWithTitle } from '../WidgetWrapperWithTitle';
10
10
  import type { TypingAnimationProps } from './types';
11
11
  import { useGetTypographyVariant } from './hooks/useGetTypographyVariant';
12
+ import { useAnimatedTextMinHeight } from '../utils/useAnimatedTextMinHeight';
12
13
  import { Stack } from '../Stack';
13
14
 
14
15
  export const TypingAnimation = ({
@@ -40,6 +41,15 @@ export const TypingAnimation = ({
40
41
 
41
42
  const { handleButtonClick, handleTextFieldClick } = widgetEventProps || {};
42
43
  const typographyVariant = useGetTypographyVariant(theme);
44
+ const { measuringRef, minHeight } = useAnimatedTextMinHeight(animatedTextSequence ?? []);
45
+
46
+ const biggestAnimatedText = useMemo(() => {
47
+ if (!animatedTextSequence || animatedTextSequence.length === 0) return '';
48
+ return animatedTextSequence.reduce(
49
+ (maxText, currText) => (currText.length > maxText.length ? currText : maxText),
50
+ '',
51
+ );
52
+ }, [animatedTextSequence]);
43
53
 
44
54
  const getAnimatedTextWrapper = useCallback(
45
55
  (text: string) => (
@@ -71,28 +81,64 @@ export const TypingAnimation = ({
71
81
  >
72
82
  {(headlineText || (animatedTextSequence && animatedTextSequence.length > 0)) &&
73
83
  !isLoading && (
74
- <p
75
- data-testid="typing-animation-headline-text"
76
- className="envive-tw-max-w-[90ch] envive-tw-overflow-hidden envive-tw-text-ellipsis envive-tw-whitespace-nowrap"
77
- style={{ textAlign: 'left' }}
78
- >
79
- {headlineText && (
80
- <Typography
81
- variant={typographyVariant}
82
- color={TypographyColor.TEXT_PRIMARY}
83
- as="span"
84
+ <div style={{ position: 'relative' }}>
85
+ <div
86
+ ref={measuringRef}
87
+ aria-hidden="true"
88
+ style={{
89
+ position: 'absolute',
90
+ visibility: 'hidden',
91
+ pointerEvents: 'none',
92
+ width: '100%',
93
+ }}
94
+ >
95
+ <p
96
+ className="envive-tw-max-w-[90ch]"
97
+ style={{ textAlign: 'left' }}
98
+ >
99
+ {headlineText && (
100
+ <Typography
101
+ variant={typographyVariant}
102
+ color={TypographyColor.TEXT_PRIMARY}
103
+ as="span"
104
+ >
105
+ {headlineText}
106
+ </Typography>
107
+ )}{' '}
108
+ <Typography
109
+ variant={typographyVariant}
110
+ color={TypographyColor.TEXT_ACCENT}
111
+ as="span"
112
+ >
113
+ {biggestAnimatedText}
114
+ </Typography>
115
+ </p>
116
+ </div>
117
+ <div style={{ minHeight }}>
118
+ <p
119
+ data-testid="typing-animation-headline-text"
120
+ className="envive-tw-max-w-[90ch]"
121
+ style={{ textAlign: 'left' }}
84
122
  >
85
- {headlineText}
86
- </Typography>
87
- )}{' '}
88
- {animatedTextSequence && animatedTextSequence.length > 0 ? (
89
- <AnimatedText
90
- sequence={animatedTextSequence}
91
- loop
92
- getNodeWrapper={getAnimatedTextWrapper}
93
- />
94
- ) : null}
95
- </p>
123
+ {headlineText && (
124
+ <Typography
125
+ variant={typographyVariant}
126
+ color={TypographyColor.TEXT_PRIMARY}
127
+ as="span"
128
+ >
129
+ {headlineText}
130
+ </Typography>
131
+ )}{' '}
132
+ {animatedTextSequence && animatedTextSequence.length > 0 ? (
133
+ <AnimatedText
134
+ sequence={animatedTextSequence}
135
+ loop
136
+ getNodeWrapper={getAnimatedTextWrapper}
137
+ />
138
+ ) : null}
139
+ </p>
140
+ </div>
141
+ </div>
96
142
  )}
97
143
  {promptButtonTexts && promptButtonTexts.length > 0 && handleButtonClick && (
98
144
  <PromptCarousel
@@ -0,0 +1,29 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+
3
+ export const useAnimatedTextMinHeight = (animatedText: string[]) => {
4
+ const measuringRef = useRef<HTMLDivElement>(null);
5
+ const [minHeight, setMinHeight] = useState(0);
6
+
7
+ useEffect(() => {
8
+ const updateMinHeight = () => {
9
+ if (!measuringRef.current) return;
10
+ let maxHeight = 0;
11
+ const { children } = measuringRef.current;
12
+ for (let i = 0; i < children.length; i += 1) {
13
+ maxHeight = Math.max(maxHeight, (children[i] as HTMLElement).offsetHeight);
14
+ }
15
+ setMinHeight(maxHeight);
16
+ };
17
+
18
+ updateMinHeight();
19
+
20
+ const observer = new ResizeObserver(updateMinHeight);
21
+ if (measuringRef.current) {
22
+ observer.observe(measuringRef.current);
23
+ }
24
+
25
+ return () => observer.disconnect();
26
+ }, [animatedText]);
27
+
28
+ return { measuringRef, minHeight };
29
+ };
@@ -1,18 +0,0 @@
1
-
2
- //#region src/components/ChatFooter/hooks/useGetButtonScrollProperties.ts
3
- const useGetButtonScrollProperties = () => {
4
- return {
5
- buttonScrollClasses: [
6
- "envive-tw-overflow-x-scroll",
7
- "envive-tw-overflow-y-hidden",
8
- "[&::-webkit-scrollbar]:hidden"
9
- ],
10
- buttonScrollStyle: {
11
- scrollbarWidth: "none",
12
- msOverflowStyle: "none"
13
- }
14
- };
15
- };
16
-
17
- //#endregion
18
- exports.useGetButtonScrollProperties = useGetButtonScrollProperties;
@@ -1,17 +0,0 @@
1
- //#region src/components/ChatFooter/hooks/useGetButtonScrollProperties.ts
2
- const useGetButtonScrollProperties = () => {
3
- return {
4
- buttonScrollClasses: [
5
- "envive-tw-overflow-x-scroll",
6
- "envive-tw-overflow-y-hidden",
7
- "[&::-webkit-scrollbar]:hidden"
8
- ],
9
- buttonScrollStyle: {
10
- scrollbarWidth: "none",
11
- msOverflowStyle: "none"
12
- }
13
- };
14
- };
15
-
16
- //#endregion
17
- export { useGetButtonScrollProperties };
@@ -1,15 +0,0 @@
1
- const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
- const require_index = require('../../Typography/types/index.cjs');
3
- const require_Typography = require('../../Typography/Typography.cjs');
4
- let react_jsx_runtime = require("react/jsx-runtime");
5
-
6
- //#region src/components/MarkdownProcessor/components/MarkdownSubscript.tsx
7
- const MarkdownSubscript = ({ children, subTextVariant, subTextColor }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Typography.Typography, {
8
- variant: subTextVariant ?? require_index.TypographyVariant.B5_RG,
9
- color: subTextColor ?? require_index.TypographyColor.TEXT_SECONDARY,
10
- className: "envive-tw-inline",
11
- children
12
- });
13
-
14
- //#endregion
15
- exports.MarkdownSubscript = MarkdownSubscript;
@@ -1,14 +0,0 @@
1
- import { TypographyColor, TypographyVariant } from "../../Typography/types/index.js";
2
- import { Typography } from "../../Typography/Typography.js";
3
- import { jsx } from "react/jsx-runtime";
4
-
5
- //#region src/components/MarkdownProcessor/components/MarkdownSubscript.tsx
6
- const MarkdownSubscript = ({ children, subTextVariant, subTextColor }) => /* @__PURE__ */ jsx(Typography, {
7
- variant: subTextVariant ?? TypographyVariant.B5_RG,
8
- color: subTextColor ?? TypographyColor.TEXT_SECONDARY,
9
- className: "envive-tw-inline",
10
- children
11
- });
12
-
13
- //#endregion
14
- export { MarkdownSubscript };