@envive-ai/react-toolkit-v3 0.3.6 → 0.3.7

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 (157) hide show
  1. package/dist/AnimatedText/AnimatedText.d.cts +3 -3
  2. package/dist/AnimatedText/AnimatedText.d.ts +3 -3
  3. package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.cts +2 -2
  4. package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.ts +2 -2
  5. package/dist/Carousel/Carousel.d.cts +2 -2
  6. package/dist/Carousel/Carousel.d.ts +2 -2
  7. package/dist/ChatFooter/ChatFooter.d.cts +2 -2
  8. package/dist/ChatFooter/ChatFooter.d.ts +2 -2
  9. package/dist/ChatFooter/components/index.d.cts +5 -5
  10. package/dist/ChatFooter/components/index.d.ts +5 -5
  11. package/dist/ChatFooter/hooks/useGetContainerProperties.cjs +2 -2
  12. package/dist/ChatFooter/hooks/useGetContainerProperties.js +2 -2
  13. package/dist/ChatHeader/ChatHeader.cjs +3 -2
  14. package/dist/ChatHeader/ChatHeader.d.cts +3 -2
  15. package/dist/ChatHeader/ChatHeader.d.ts +3 -2
  16. package/dist/ChatHeader/ChatHeader.js +3 -2
  17. package/dist/ChatHeader/components/Handle.cjs +27 -1
  18. package/dist/ChatHeader/components/Handle.js +27 -1
  19. package/dist/ChatHeader/types/index.d.cts +2 -0
  20. package/dist/ChatHeader/types/index.d.ts +2 -0
  21. package/dist/ChatPreview/ChatPreview.d.cts +2 -2
  22. package/dist/ChatPreview/ChatPreview.d.ts +2 -2
  23. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
  24. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
  25. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
  26. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
  27. package/dist/Container/Container.d.cts +176 -176
  28. package/dist/Container/Container.d.ts +176 -176
  29. package/dist/DesignTokens/DesignTokensComponent.d.cts +2 -2
  30. package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
  31. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
  32. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
  33. package/dist/FloatingButton/FloatingButton.cjs +2 -1
  34. package/dist/FloatingButton/FloatingButton.d.cts +4 -3
  35. package/dist/FloatingButton/FloatingButton.d.ts +4 -3
  36. package/dist/FloatingButton/FloatingButton.js +2 -1
  37. package/dist/FloatingButton/components/Container.cjs +2 -2
  38. package/dist/FloatingButton/components/Container.js +2 -2
  39. package/dist/FloatingButton/hooks/useGetContainerProperties.cjs +2 -2
  40. package/dist/FloatingButton/hooks/useGetContainerProperties.js +2 -2
  41. package/dist/FloatingButton/types/types.cjs +4 -4
  42. package/dist/FloatingButton/types/types.d.cts +8 -4
  43. package/dist/FloatingButton/types/types.d.ts +8 -4
  44. package/dist/FloatingButton/types/types.js +4 -4
  45. package/dist/FloatingChat/FloatingChat.cjs +106 -39
  46. package/dist/FloatingChat/FloatingChat.d.cts +3 -2
  47. package/dist/FloatingChat/FloatingChat.d.ts +3 -2
  48. package/dist/FloatingChat/FloatingChat.js +108 -41
  49. package/dist/FloatingChat/components/AgentMessage.cjs +3 -2
  50. package/dist/FloatingChat/components/AgentMessage.js +3 -2
  51. package/dist/FloatingChat/components/ChatMessages.cjs +59 -41
  52. package/dist/FloatingChat/components/ChatMessages.js +58 -40
  53. package/dist/FloatingChat/components/Layout.cjs +2 -2
  54. package/dist/FloatingChat/components/Layout.js +2 -2
  55. package/dist/FloatingChat/components/ModalSheet.cjs +184 -0
  56. package/dist/FloatingChat/components/ModalSheet.js +182 -0
  57. package/dist/FloatingChat/components/SalesAgentProductCardsCarousel.cjs +3 -2
  58. package/dist/FloatingChat/components/SalesAgentProductCardsCarousel.js +3 -2
  59. package/dist/FloatingChat/components/index.cjs +1 -0
  60. package/dist/FloatingChat/components/index.js +1 -0
  61. package/dist/FloatingChat/hooks/useChatSuggestions.cjs +25 -0
  62. package/dist/FloatingChat/hooks/useChatSuggestions.js +24 -0
  63. package/dist/FloatingChat/hooks/useFilteredChatMessages.cjs +24 -0
  64. package/dist/FloatingChat/hooks/useFilteredChatMessages.js +23 -0
  65. package/dist/FloatingChat/hooks/usePreventScroll.cjs +117 -0
  66. package/dist/FloatingChat/hooks/usePreventScroll.js +116 -0
  67. package/dist/FloatingChat/hooks/useSnapCalculator.cjs +37 -0
  68. package/dist/FloatingChat/hooks/useSnapCalculator.js +35 -0
  69. package/dist/FloatingChat/hooks/useSnapControl.cjs +82 -0
  70. package/dist/FloatingChat/hooks/useSnapControl.js +81 -0
  71. package/dist/FloatingChat/hooks/useSnapSetup.cjs +59 -0
  72. package/dist/FloatingChat/hooks/useSnapSetup.js +58 -0
  73. package/dist/FloatingChat/types/types.d.cts +4 -0
  74. package/dist/FloatingChat/types/types.d.ts +4 -0
  75. package/dist/Image/Image.d.cts +2 -2
  76. package/dist/Image/Image.d.ts +2 -2
  77. package/dist/ImageGallery/ImageGallery.d.cts +2 -2
  78. package/dist/ImageGallery/ImageGallery.d.ts +2 -2
  79. package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +2 -2
  80. package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +2 -2
  81. package/dist/PromptButton/PromptButton.d.cts +2 -2
  82. package/dist/PromptButton/PromptButton.d.ts +2 -2
  83. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
  84. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
  85. package/dist/PromptCarousel/PromptCarousel.cjs +0 -1
  86. package/dist/PromptCarousel/PromptCarousel.d.cts +2 -2
  87. package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
  88. package/dist/PromptCarousel/PromptCarousel.js +0 -1
  89. package/dist/ReviewCard/ReviewCard.d.cts +2 -2
  90. package/dist/ReviewCard/ReviewCard.d.ts +2 -2
  91. package/dist/ReviewCard/components/index.d.cts +6 -6
  92. package/dist/ReviewCard/components/index.d.ts +6 -6
  93. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
  94. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
  95. package/dist/SalesAgentProductCard/components/index.d.cts +2 -2
  96. package/dist/SalesAgentProductCard/components/index.d.ts +8 -8
  97. package/dist/SocialProof/SocialProof.cjs +9 -2
  98. package/dist/SocialProof/SocialProof.d.cts +2 -2
  99. package/dist/SocialProof/SocialProof.d.ts +2 -2
  100. package/dist/SocialProof/SocialProof.js +9 -2
  101. package/dist/SocialProof/hooks/index.cjs +1 -0
  102. package/dist/SocialProof/hooks/index.js +3 -0
  103. package/dist/SocialProof/hooks/useSocialProofCount.cjs +48 -0
  104. package/dist/SocialProof/hooks/useSocialProofCount.d.cts +15 -0
  105. package/dist/SocialProof/hooks/useSocialProofCount.d.ts +15 -0
  106. package/dist/SocialProof/hooks/useSocialProofCount.js +46 -0
  107. package/dist/SocialProof/index.cjs +5 -1
  108. package/dist/SocialProof/index.d.cts +3 -2
  109. package/dist/SocialProof/index.d.ts +3 -2
  110. package/dist/SocialProof/index.js +4 -2
  111. package/dist/SocialProof/types/types.cjs +8 -1
  112. package/dist/SocialProof/types/types.d.cts +16 -6
  113. package/dist/SocialProof/types/types.d.ts +16 -6
  114. package/dist/SocialProof/types/types.js +7 -1
  115. package/dist/Stack/Stack.d.cts +2 -2
  116. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.cts +2 -2
  117. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.ts +2 -2
  118. package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
  119. package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
  120. package/dist/Typography/Typography.d.cts +4 -4
  121. package/dist/Typography/Typography.d.ts +4 -4
  122. package/dist/WidgetTextField/WidgetTextField.d.cts +2 -2
  123. package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
  124. package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
  125. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
  126. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts +2 -2
  127. package/dist/styles.css +1 -1
  128. package/package.json +1 -1
  129. package/src/components/ChatFooter/hooks/useGetContainerProperties.ts +2 -2
  130. package/src/components/ChatHeader/ChatHeader.tsx +2 -0
  131. package/src/components/ChatHeader/components/Handle.tsx +29 -1
  132. package/src/components/ChatHeader/types/index.ts +3 -0
  133. package/src/components/FloatingButton/FloatingButton.tsx +2 -0
  134. package/src/components/FloatingButton/components/Container.tsx +3 -0
  135. package/src/components/FloatingButton/hooks/useGetContainerProperties.ts +2 -1
  136. package/src/components/FloatingButton/types/types.ts +9 -4
  137. package/src/components/FloatingChat/FloatingChat.tsx +160 -59
  138. package/src/components/FloatingChat/components/AgentMessage.tsx +3 -0
  139. package/src/components/FloatingChat/components/ChatMessages.tsx +25 -0
  140. package/src/components/FloatingChat/components/Layout.tsx +2 -2
  141. package/src/components/FloatingChat/components/ModalSheet.tsx +288 -0
  142. package/src/components/FloatingChat/components/SalesAgentProductCardsCarousel.tsx +7 -2
  143. package/src/components/FloatingChat/components/index.ts +3 -0
  144. package/src/components/FloatingChat/hooks/useChatSuggestions.ts +49 -0
  145. package/src/components/FloatingChat/hooks/useFilteredChatMessages.ts +43 -0
  146. package/src/components/FloatingChat/hooks/usePreventScroll.ts +207 -0
  147. package/src/components/FloatingChat/hooks/useSnapCalculator.ts +41 -0
  148. package/src/components/FloatingChat/hooks/useSnapControl.ts +131 -0
  149. package/src/components/FloatingChat/hooks/useSnapSetup.ts +106 -0
  150. package/src/components/FloatingChat/types/types.ts +4 -0
  151. package/src/components/PromptCarousel/PromptCarousel.tsx +0 -1
  152. package/src/components/SocialProof/SocialProof.tsx +8 -2
  153. package/src/components/SocialProof/__tests__/SocialProof.test.tsx +66 -17
  154. package/src/components/SocialProof/hooks/index.ts +2 -0
  155. package/src/components/SocialProof/hooks/useSocialProofCount.ts +67 -0
  156. package/src/components/SocialProof/index.ts +2 -1
  157. package/src/components/SocialProof/types/types.ts +18 -6
@@ -5,14 +5,15 @@ import { SalesAgentProductCard } from "../../SalesAgentProductCard/SalesAgentPro
5
5
  import { jsx } from "react/jsx-runtime";
6
6
 
7
7
  //#region src/components/FloatingChat/components/SalesAgentProductCardsCarousel.tsx
8
- const SalesAgentProductCardsCarousel = ({ products, theme, hideNavigation = false, numberOfProducts }) => {
8
+ const SalesAgentProductCardsCarousel = ({ products, theme, hideNavigation = false, numberOfProducts, variant = SalesAgentProductCardVariant.LARGE, isPartialView = false }) => {
9
9
  const finalTheme = resolveTheme(theme);
10
+ const finalVariant = isPartialView ? SalesAgentProductCardVariant.SMALL : variant;
10
11
  const forceShowCurrentPriceSpace = products.some((product) => product.currentPrice && product.previousPrice !== product.currentPrice);
11
12
  return /* @__PURE__ */ jsx(Carousel, {
12
13
  hideNavigation,
13
14
  badgeLabel: numberOfProducts && numberOfProducts > 1 ? `${numberOfProducts} Products` : void 0,
14
15
  elements: products.map((product) => /* @__PURE__ */ jsx(SalesAgentProductCard, {
15
- variant: SalesAgentProductCardVariant.LARGE,
16
+ variant: finalVariant,
16
17
  productName: product.productName,
17
18
  currentPrice: product.currentPrice,
18
19
  previousPrice: product.previousPrice,
@@ -8,6 +8,7 @@ const require_AgentMessage = require('./AgentMessage.cjs');
8
8
  const require_MessageDivider = require('./MessageDivider.cjs');
9
9
  const require_ChatMessages = require('./ChatMessages.cjs');
10
10
  const require_ScrollToBottomButton = require('./ScrollToBottomButton.cjs');
11
+ const require_ModalSheet = require('./ModalSheet.cjs');
11
12
 
12
13
  //#region src/components/FloatingChat/components/index.ts
13
14
  const FloatingChatComponents = {
@@ -8,6 +8,7 @@ import { AgentMessage } from "./AgentMessage.js";
8
8
  import { MessageDivider } from "./MessageDivider.js";
9
9
  import { ChatMessages } from "./ChatMessages.js";
10
10
  import { ScrollToBottomButton } from "./ScrollToBottomButton.js";
11
+ import { ModalSheet } from "./ModalSheet.js";
11
12
 
12
13
  //#region src/components/FloatingChat/components/index.ts
13
14
  const FloatingChatComponents = {
@@ -0,0 +1,25 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ let react = require("react");
3
+
4
+ //#region src/components/FloatingChat/hooks/useChatSuggestions.ts
5
+ const useChatSuggestions = ({ suggestions, isPendingResponse, isResponseStreaming }) => {
6
+ const [answerSuggestions, setAnswerSuggestions] = (0, react.useState)([]);
7
+ const [generalSuggestions, setGeneralSuggestions] = (0, react.useState)([]);
8
+ const showAnswerSuggestions = answerSuggestions.length > 0 && !isPendingResponse && !isResponseStreaming;
9
+ (0, react.useEffect)(() => {
10
+ if (suggestions.length > 0) {
11
+ setAnswerSuggestions(suggestions.filter((suggestion) => suggestion.isAnswer).map((suggestion) => suggestion.content));
12
+ setGeneralSuggestions(suggestions.filter((suggestion) => !suggestion.isAnswer).map((suggestion) => suggestion.content));
13
+ }
14
+ }, [suggestions]);
15
+ return {
16
+ answerSuggestions,
17
+ generalSuggestions,
18
+ showAnswerSuggestions,
19
+ setAnswerSuggestions,
20
+ setGeneralSuggestions
21
+ };
22
+ };
23
+
24
+ //#endregion
25
+ exports.useChatSuggestions = useChatSuggestions;
@@ -0,0 +1,24 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ //#region src/components/FloatingChat/hooks/useChatSuggestions.ts
4
+ const useChatSuggestions = ({ suggestions, isPendingResponse, isResponseStreaming }) => {
5
+ const [answerSuggestions, setAnswerSuggestions] = useState([]);
6
+ const [generalSuggestions, setGeneralSuggestions] = useState([]);
7
+ const showAnswerSuggestions = answerSuggestions.length > 0 && !isPendingResponse && !isResponseStreaming;
8
+ useEffect(() => {
9
+ if (suggestions.length > 0) {
10
+ setAnswerSuggestions(suggestions.filter((suggestion) => suggestion.isAnswer).map((suggestion) => suggestion.content));
11
+ setGeneralSuggestions(suggestions.filter((suggestion) => !suggestion.isAnswer).map((suggestion) => suggestion.content));
12
+ }
13
+ }, [suggestions]);
14
+ return {
15
+ answerSuggestions,
16
+ generalSuggestions,
17
+ showAnswerSuggestions,
18
+ setAnswerSuggestions,
19
+ setGeneralSuggestions
20
+ };
21
+ };
22
+
23
+ //#endregion
24
+ export { useChatSuggestions };
@@ -0,0 +1,24 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ let react = require("react");
3
+ let __envive_ai_react_hooks_hooks_MessageFilter = require("@envive-ai/react-hooks/hooks/MessageFilter");
4
+
5
+ //#region src/components/FloatingChat/hooks/useFilteredChatMessages.ts
6
+ const useFilteredChatMessages = ({ messages, isMobile, currentSnapPercentage, modalSheetControl }) => {
7
+ const { getFilteredMessages } = (0, __envive_ai_react_hooks_hooks_MessageFilter.useMessageFilter)();
8
+ const keepMessagesExpanded = !isMobile || isMobile && currentSnapPercentage === 100;
9
+ const filteredMessages = (0, react.useMemo)(() => getFilteredMessages(messages, keepMessagesExpanded), [
10
+ getFilteredMessages,
11
+ messages,
12
+ keepMessagesExpanded
13
+ ]);
14
+ const hasFilteredMessages = filteredMessages.length !== messages.length && isMobile;
15
+ const handlePreviousDiscussions = () => modalSheetControl.current?.jumpToSnap(2);
16
+ return {
17
+ filteredMessages,
18
+ hasFilteredMessages,
19
+ handlePreviousDiscussions
20
+ };
21
+ };
22
+
23
+ //#endregion
24
+ exports.useFilteredChatMessages = useFilteredChatMessages;
@@ -0,0 +1,23 @@
1
+ import { useMemo } from "react";
2
+ import { useMessageFilter } from "@envive-ai/react-hooks/hooks/MessageFilter";
3
+
4
+ //#region src/components/FloatingChat/hooks/useFilteredChatMessages.ts
5
+ const useFilteredChatMessages = ({ messages, isMobile, currentSnapPercentage, modalSheetControl }) => {
6
+ const { getFilteredMessages } = useMessageFilter();
7
+ const keepMessagesExpanded = !isMobile || isMobile && currentSnapPercentage === 100;
8
+ const filteredMessages = useMemo(() => getFilteredMessages(messages, keepMessagesExpanded), [
9
+ getFilteredMessages,
10
+ messages,
11
+ keepMessagesExpanded
12
+ ]);
13
+ const hasFilteredMessages = filteredMessages.length !== messages.length && isMobile;
14
+ const handlePreviousDiscussions = () => modalSheetControl.current?.jumpToSnap(2);
15
+ return {
16
+ filteredMessages,
17
+ hasFilteredMessages,
18
+ handlePreviousDiscussions
19
+ };
20
+ };
21
+
22
+ //#endregion
23
+ export { useFilteredChatMessages };
@@ -0,0 +1,117 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ let react = require("react");
3
+
4
+ //#region src/components/FloatingChat/hooks/usePreventScroll.ts
5
+ /**
6
+ * Prevent the body element from scrolling when a modal (partial view) is open.
7
+ *
8
+ * @returns
9
+ */
10
+ const usePreventScroll = () => {
11
+ const gestureRef = (0, react.useRef)(null);
12
+ /**
13
+ * Calculate the angle of a user gesture (grab/drop).
14
+ *
15
+ * @param startX
16
+ * @param startY
17
+ * @param endX
18
+ * @param endY
19
+ * @returns
20
+ */
21
+ const calculateAngle = (startX, startY, endX, endY) => {
22
+ const deltaX = endX - startX;
23
+ const deltaY = endY - startY;
24
+ return (Math.atan2(deltaY, deltaX) * (180 / Math.PI) + 360) % 360;
25
+ };
26
+ /**
27
+ * Test if an element has scrollable capabilities.
28
+ *
29
+ * @param node
30
+ * @returns
31
+ */
32
+ const isScrollable = (node) => {
33
+ const style = window.getComputedStyle(node);
34
+ return /(auto|scroll)/.test(style.overflow + style.overflowX + style.overflowY);
35
+ };
36
+ /**
37
+ * Find the parent node that has scrollable capabilities.
38
+ *
39
+ * @param node
40
+ * @returns
41
+ */
42
+ const getScrollParent = (node, ignoreCurrentNode = false) => {
43
+ let parentNode = ignoreCurrentNode ? node?.parentElement : node;
44
+ if (!parentNode) return null;
45
+ if (isScrollable(parentNode)) return parentNode;
46
+ while (parentNode && !isScrollable(parentNode)) parentNode = parentNode.parentElement;
47
+ if (!parentNode && isScrollable(document.body)) return document.body;
48
+ return parentNode || document.scrollingElement || document.documentElement;
49
+ };
50
+ /**
51
+ * Get the scrollable directions an element can scroll.
52
+ *
53
+ * @returns
54
+ */
55
+ const getScrollDirections = (scrollableElement) => {
56
+ const horizontalScroll = (scrollableElement?.scrollWidth || 0) > (scrollableElement?.clientWidth || 0);
57
+ const verticalScroll = (scrollableElement?.scrollHeight || 0) > (scrollableElement?.clientHeight || 0);
58
+ const scrollDirections = [];
59
+ if (horizontalScroll) scrollDirections.push("horizontal");
60
+ if (verticalScroll) scrollDirections.push("vertical");
61
+ return scrollDirections;
62
+ };
63
+ /**
64
+ * Determine the direction of a gesture event based on the angle of a grab/drop event.
65
+ *
66
+ * @param fingerX
67
+ * @param fingerY
68
+ * @returns
69
+ */
70
+ const getGestureDirection = (fingerX, fingerY) => {
71
+ const directionAngle = calculateAngle(gestureRef?.current?.event?.clientX || 0, gestureRef?.current?.event?.clientY || 0, fingerX, fingerY);
72
+ if (directionAngle < 45 || directionAngle > 315) return "right";
73
+ if (directionAngle > 45 && directionAngle < 135) return "down";
74
+ if (directionAngle > 135 && directionAngle < 225) return "left";
75
+ return "up";
76
+ };
77
+ /**
78
+ * Determine whether the direction of the gesture can scroll the element in context.
79
+ *
80
+ * @param param0
81
+ * @param direction
82
+ * @returns
83
+ */
84
+ const isScrollDirectionAllowed = ({ element, scrollableDirections }, direction) => {
85
+ if (element?.tagName === "BODY" || element?.tagName === "HTML" || scrollableDirections?.length === 0) return false;
86
+ const { clientHeight = 0, clientWidth = 0, scrollHeight = 0, scrollWidth = 0, scrollTop = 0, scrollLeft = 0 } = element || {};
87
+ const atTop = scrollTop === 0;
88
+ const atLeft = scrollLeft === 0;
89
+ const atBottom = 100 / scrollHeight * (scrollTop + clientHeight) > 99.9;
90
+ const atRight = 100 / scrollWidth * (scrollLeft + clientWidth) > 99.9;
91
+ const verticalScrollBlocked = atBottom && direction === "up" || atTop && direction === "down" || direction === "left" || direction === "right";
92
+ if (scrollableDirections?.includes("vertical") && verticalScrollBlocked) return false;
93
+ const horizontalScrollBlocked = atRight && direction === "left" || atLeft && direction === "right" || direction === "up" || direction === "down";
94
+ if (scrollableDirections?.includes("horizontal") && horizontalScrollBlocked) return false;
95
+ return true;
96
+ };
97
+ /**
98
+ * Test if the selected scrollable element can scroll in the direction of the grab/drop event.
99
+ *
100
+ * @param direction
101
+ * @returns
102
+ */
103
+ const isScrollableArea = (direction) => {
104
+ const { scrollableElements } = gestureRef.current || {};
105
+ return scrollableElements?.some((el) => isScrollDirectionAllowed(el, direction));
106
+ };
107
+ return {
108
+ gestureRef,
109
+ getScrollParent,
110
+ isScrollableArea,
111
+ getGestureDirection,
112
+ getScrollDirections
113
+ };
114
+ };
115
+
116
+ //#endregion
117
+ exports.usePreventScroll = usePreventScroll;
@@ -0,0 +1,116 @@
1
+ import { useRef } from "react";
2
+
3
+ //#region src/components/FloatingChat/hooks/usePreventScroll.ts
4
+ /**
5
+ * Prevent the body element from scrolling when a modal (partial view) is open.
6
+ *
7
+ * @returns
8
+ */
9
+ const usePreventScroll = () => {
10
+ const gestureRef = useRef(null);
11
+ /**
12
+ * Calculate the angle of a user gesture (grab/drop).
13
+ *
14
+ * @param startX
15
+ * @param startY
16
+ * @param endX
17
+ * @param endY
18
+ * @returns
19
+ */
20
+ const calculateAngle = (startX, startY, endX, endY) => {
21
+ const deltaX = endX - startX;
22
+ const deltaY = endY - startY;
23
+ return (Math.atan2(deltaY, deltaX) * (180 / Math.PI) + 360) % 360;
24
+ };
25
+ /**
26
+ * Test if an element has scrollable capabilities.
27
+ *
28
+ * @param node
29
+ * @returns
30
+ */
31
+ const isScrollable = (node) => {
32
+ const style = window.getComputedStyle(node);
33
+ return /(auto|scroll)/.test(style.overflow + style.overflowX + style.overflowY);
34
+ };
35
+ /**
36
+ * Find the parent node that has scrollable capabilities.
37
+ *
38
+ * @param node
39
+ * @returns
40
+ */
41
+ const getScrollParent = (node, ignoreCurrentNode = false) => {
42
+ let parentNode = ignoreCurrentNode ? node?.parentElement : node;
43
+ if (!parentNode) return null;
44
+ if (isScrollable(parentNode)) return parentNode;
45
+ while (parentNode && !isScrollable(parentNode)) parentNode = parentNode.parentElement;
46
+ if (!parentNode && isScrollable(document.body)) return document.body;
47
+ return parentNode || document.scrollingElement || document.documentElement;
48
+ };
49
+ /**
50
+ * Get the scrollable directions an element can scroll.
51
+ *
52
+ * @returns
53
+ */
54
+ const getScrollDirections = (scrollableElement) => {
55
+ const horizontalScroll = (scrollableElement?.scrollWidth || 0) > (scrollableElement?.clientWidth || 0);
56
+ const verticalScroll = (scrollableElement?.scrollHeight || 0) > (scrollableElement?.clientHeight || 0);
57
+ const scrollDirections = [];
58
+ if (horizontalScroll) scrollDirections.push("horizontal");
59
+ if (verticalScroll) scrollDirections.push("vertical");
60
+ return scrollDirections;
61
+ };
62
+ /**
63
+ * Determine the direction of a gesture event based on the angle of a grab/drop event.
64
+ *
65
+ * @param fingerX
66
+ * @param fingerY
67
+ * @returns
68
+ */
69
+ const getGestureDirection = (fingerX, fingerY) => {
70
+ const directionAngle = calculateAngle(gestureRef?.current?.event?.clientX || 0, gestureRef?.current?.event?.clientY || 0, fingerX, fingerY);
71
+ if (directionAngle < 45 || directionAngle > 315) return "right";
72
+ if (directionAngle > 45 && directionAngle < 135) return "down";
73
+ if (directionAngle > 135 && directionAngle < 225) return "left";
74
+ return "up";
75
+ };
76
+ /**
77
+ * Determine whether the direction of the gesture can scroll the element in context.
78
+ *
79
+ * @param param0
80
+ * @param direction
81
+ * @returns
82
+ */
83
+ const isScrollDirectionAllowed = ({ element, scrollableDirections }, direction) => {
84
+ if (element?.tagName === "BODY" || element?.tagName === "HTML" || scrollableDirections?.length === 0) return false;
85
+ const { clientHeight = 0, clientWidth = 0, scrollHeight = 0, scrollWidth = 0, scrollTop = 0, scrollLeft = 0 } = element || {};
86
+ const atTop = scrollTop === 0;
87
+ const atLeft = scrollLeft === 0;
88
+ const atBottom = 100 / scrollHeight * (scrollTop + clientHeight) > 99.9;
89
+ const atRight = 100 / scrollWidth * (scrollLeft + clientWidth) > 99.9;
90
+ const verticalScrollBlocked = atBottom && direction === "up" || atTop && direction === "down" || direction === "left" || direction === "right";
91
+ if (scrollableDirections?.includes("vertical") && verticalScrollBlocked) return false;
92
+ const horizontalScrollBlocked = atRight && direction === "left" || atLeft && direction === "right" || direction === "up" || direction === "down";
93
+ if (scrollableDirections?.includes("horizontal") && horizontalScrollBlocked) return false;
94
+ return true;
95
+ };
96
+ /**
97
+ * Test if the selected scrollable element can scroll in the direction of the grab/drop event.
98
+ *
99
+ * @param direction
100
+ * @returns
101
+ */
102
+ const isScrollableArea = (direction) => {
103
+ const { scrollableElements } = gestureRef.current || {};
104
+ return scrollableElements?.some((el) => isScrollDirectionAllowed(el, direction));
105
+ };
106
+ return {
107
+ gestureRef,
108
+ getScrollParent,
109
+ isScrollableArea,
110
+ getGestureDirection,
111
+ getScrollDirections
112
+ };
113
+ };
114
+
115
+ //#endregion
116
+ export { usePreventScroll };
@@ -0,0 +1,37 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ let react = require("react");
3
+
4
+ //#region src/components/FloatingChat/hooks/useSnapCalculator.ts
5
+ let Unit = /* @__PURE__ */ function(Unit$1) {
6
+ Unit$1["PERCENT"] = "percent";
7
+ Unit$1["PIXEL"] = "pixel";
8
+ return Unit$1;
9
+ }({});
10
+ const useSnapCalculator = (snaps, maxHeight, unit) => {
11
+ const viewportHeightPx = document.documentElement.clientHeight;
12
+ const swipeviewHeightPx = unit === Unit.PERCENT ? Math.floor(viewportHeightPx * (maxHeight / 100)) : maxHeight;
13
+ const snapsToPixels = (0, react.useMemo)(() => snaps?.map((snap) => Math.abs((unit === Unit.PERCENT ? Math.floor(swipeviewHeightPx * (snap / 100)) : snap) - swipeviewHeightPx)), [
14
+ swipeviewHeightPx,
15
+ unit,
16
+ snaps
17
+ ]);
18
+ const getPixelToSnap = (pixels) => {
19
+ const snapIdx = snapsToPixels?.indexOf(pixels) || 0;
20
+ return snaps?.[snapIdx] || 0;
21
+ };
22
+ const getSnapToPixel = (snap) => {
23
+ const snapIdx = snaps?.indexOf(snap) || 0;
24
+ return snapsToPixels?.[snapIdx] || 0;
25
+ };
26
+ return {
27
+ viewportHeightPx,
28
+ snapsToPixels,
29
+ swipeviewHeightPx,
30
+ getPixelToSnap,
31
+ getSnapToPixel
32
+ };
33
+ };
34
+
35
+ //#endregion
36
+ exports.Unit = Unit;
37
+ exports.useSnapCalculator = useSnapCalculator;
@@ -0,0 +1,35 @@
1
+ import { useMemo } from "react";
2
+
3
+ //#region src/components/FloatingChat/hooks/useSnapCalculator.ts
4
+ let Unit = /* @__PURE__ */ function(Unit$1) {
5
+ Unit$1["PERCENT"] = "percent";
6
+ Unit$1["PIXEL"] = "pixel";
7
+ return Unit$1;
8
+ }({});
9
+ const useSnapCalculator = (snaps, maxHeight, unit) => {
10
+ const viewportHeightPx = document.documentElement.clientHeight;
11
+ const swipeviewHeightPx = unit === Unit.PERCENT ? Math.floor(viewportHeightPx * (maxHeight / 100)) : maxHeight;
12
+ const snapsToPixels = useMemo(() => snaps?.map((snap) => Math.abs((unit === Unit.PERCENT ? Math.floor(swipeviewHeightPx * (snap / 100)) : snap) - swipeviewHeightPx)), [
13
+ swipeviewHeightPx,
14
+ unit,
15
+ snaps
16
+ ]);
17
+ const getPixelToSnap = (pixels) => {
18
+ const snapIdx = snapsToPixels?.indexOf(pixels) || 0;
19
+ return snaps?.[snapIdx] || 0;
20
+ };
21
+ const getSnapToPixel = (snap) => {
22
+ const snapIdx = snaps?.indexOf(snap) || 0;
23
+ return snapsToPixels?.[snapIdx] || 0;
24
+ };
25
+ return {
26
+ viewportHeightPx,
27
+ snapsToPixels,
28
+ swipeviewHeightPx,
29
+ getPixelToSnap,
30
+ getSnapToPixel
31
+ };
32
+ };
33
+
34
+ //#endregion
35
+ export { Unit, useSnapCalculator };
@@ -0,0 +1,82 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_useSnapCalculator = require('./useSnapCalculator.cjs');
3
+ let react = require("react");
4
+ let framer_motion = require("framer-motion");
5
+
6
+ //#region src/components/FloatingChat/hooks/useSnapControl.ts
7
+ const MIDDLE_SNAP_OFFSET = 5;
8
+ const useSnapControl = ({ animationKey, animation, height, unit, snaps, initSnap, onSnapComplete, overlayOpacity }) => {
9
+ const [scope, animate] = (0, framer_motion.useAnimate)();
10
+ const defaultAnimationKey = (0, framer_motion.useMotionValue)(-1);
11
+ const animatedY = animationKey || defaultAnimationKey;
12
+ const { swipeviewHeightPx, snapsToPixels, getPixelToSnap, getSnapToPixel } = require_useSnapCalculator.useSnapCalculator(snaps, height, unit);
13
+ const contentHeight = (0, framer_motion.useTransform)(animatedY, [0, swipeviewHeightPx], [swipeviewHeightPx, 0]);
14
+ const snapOverlayReference = (0, react.useMemo)(() => [
15
+ getSnapToPixel(snaps[0]),
16
+ getSnapToPixel(snaps[1]) - MIDDLE_SNAP_OFFSET,
17
+ getSnapToPixel(snaps[2])
18
+ ], [getSnapToPixel, snaps]);
19
+ const displayOverlay = (0, framer_motion.useTransform)(() => animatedY.get() === -1 ? "none" : (0, framer_motion.transform)(animatedY.get(), snapOverlayReference, [
20
+ "none",
21
+ "none",
22
+ "block"
23
+ ]));
24
+ const opacityOverlay = (0, framer_motion.useTransform)(() => animatedY.get() === -1 ? 0 : (0, framer_motion.transform)(animatedY.get(), snapOverlayReference, [
25
+ 0,
26
+ 0,
27
+ overlayOpacity
28
+ ]));
29
+ const initSnapInPixels = snapsToPixels?.[initSnap];
30
+ const getInitSnap = () => snaps?.[initSnap];
31
+ const [currentSnap, setCurrentSnap] = (0, react.useState)(getInitSnap());
32
+ const defineNextSnapByPosition = () => {
33
+ const currentY = animatedY.get();
34
+ let closestSnap = snapsToPixels[0];
35
+ let minDistance = Math.abs(currentY - snapsToPixels[0]);
36
+ snapsToPixels.forEach((snapPx) => {
37
+ const distance = Math.abs(currentY - snapPx);
38
+ if (distance < minDistance) {
39
+ minDistance = distance;
40
+ closestSnap = snapPx;
41
+ }
42
+ });
43
+ return closestSnap;
44
+ };
45
+ const jumpTo = (snapPx) => {
46
+ const collapsed = snapPx === swipeviewHeightPx;
47
+ const nextSnap = getPixelToSnap(snapPx);
48
+ animate(scope.current, { y: snapPx }, {
49
+ ...animation,
50
+ onComplete: () => {
51
+ onSnapComplete(currentSnap, nextSnap, collapsed);
52
+ setCurrentSnap(nextSnap);
53
+ }
54
+ });
55
+ return {
56
+ nextSnap,
57
+ collapsed
58
+ };
59
+ };
60
+ const resetControls = () => {
61
+ setCurrentSnap(getInitSnap());
62
+ return 0;
63
+ };
64
+ return {
65
+ scope,
66
+ animatedY,
67
+ animate,
68
+ swipeviewHeightPx,
69
+ initSnapInPixels,
70
+ contentHeight,
71
+ currentSnap,
72
+ displayOverlay,
73
+ opacityOverlay,
74
+ getSnapToPixel,
75
+ jumpTo,
76
+ defineNextSnapByPosition,
77
+ resetControls
78
+ };
79
+ };
80
+
81
+ //#endregion
82
+ exports.useSnapControl = useSnapControl;
@@ -0,0 +1,81 @@
1
+ import { useSnapCalculator } from "./useSnapCalculator.js";
2
+ import { useMemo, useState } from "react";
3
+ import { transform, useAnimate, useMotionValue, useTransform } from "framer-motion";
4
+
5
+ //#region src/components/FloatingChat/hooks/useSnapControl.ts
6
+ const MIDDLE_SNAP_OFFSET = 5;
7
+ const useSnapControl = ({ animationKey, animation, height, unit, snaps, initSnap, onSnapComplete, overlayOpacity }) => {
8
+ const [scope, animate] = useAnimate();
9
+ const defaultAnimationKey = useMotionValue(-1);
10
+ const animatedY = animationKey || defaultAnimationKey;
11
+ const { swipeviewHeightPx, snapsToPixels, getPixelToSnap, getSnapToPixel } = useSnapCalculator(snaps, height, unit);
12
+ const contentHeight = useTransform(animatedY, [0, swipeviewHeightPx], [swipeviewHeightPx, 0]);
13
+ const snapOverlayReference = useMemo(() => [
14
+ getSnapToPixel(snaps[0]),
15
+ getSnapToPixel(snaps[1]) - MIDDLE_SNAP_OFFSET,
16
+ getSnapToPixel(snaps[2])
17
+ ], [getSnapToPixel, snaps]);
18
+ const displayOverlay = useTransform(() => animatedY.get() === -1 ? "none" : transform(animatedY.get(), snapOverlayReference, [
19
+ "none",
20
+ "none",
21
+ "block"
22
+ ]));
23
+ const opacityOverlay = useTransform(() => animatedY.get() === -1 ? 0 : transform(animatedY.get(), snapOverlayReference, [
24
+ 0,
25
+ 0,
26
+ overlayOpacity
27
+ ]));
28
+ const initSnapInPixels = snapsToPixels?.[initSnap];
29
+ const getInitSnap = () => snaps?.[initSnap];
30
+ const [currentSnap, setCurrentSnap] = useState(getInitSnap());
31
+ const defineNextSnapByPosition = () => {
32
+ const currentY = animatedY.get();
33
+ let closestSnap = snapsToPixels[0];
34
+ let minDistance = Math.abs(currentY - snapsToPixels[0]);
35
+ snapsToPixels.forEach((snapPx) => {
36
+ const distance = Math.abs(currentY - snapPx);
37
+ if (distance < minDistance) {
38
+ minDistance = distance;
39
+ closestSnap = snapPx;
40
+ }
41
+ });
42
+ return closestSnap;
43
+ };
44
+ const jumpTo = (snapPx) => {
45
+ const collapsed = snapPx === swipeviewHeightPx;
46
+ const nextSnap = getPixelToSnap(snapPx);
47
+ animate(scope.current, { y: snapPx }, {
48
+ ...animation,
49
+ onComplete: () => {
50
+ onSnapComplete(currentSnap, nextSnap, collapsed);
51
+ setCurrentSnap(nextSnap);
52
+ }
53
+ });
54
+ return {
55
+ nextSnap,
56
+ collapsed
57
+ };
58
+ };
59
+ const resetControls = () => {
60
+ setCurrentSnap(getInitSnap());
61
+ return 0;
62
+ };
63
+ return {
64
+ scope,
65
+ animatedY,
66
+ animate,
67
+ swipeviewHeightPx,
68
+ initSnapInPixels,
69
+ contentHeight,
70
+ currentSnap,
71
+ displayOverlay,
72
+ opacityOverlay,
73
+ getSnapToPixel,
74
+ jumpTo,
75
+ defineNextSnapByPosition,
76
+ resetControls
77
+ };
78
+ };
79
+
80
+ //#endregion
81
+ export { useSnapControl };
@@ -0,0 +1,59 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_useCheckIsMobile = require('../../utils/useCheckIsMobile.cjs');
3
+ let react = require("react");
4
+ let framer_motion = require("framer-motion");
5
+
6
+ //#region src/components/FloatingChat/hooks/useSnapSetup.ts
7
+ const useSnapSetup = ({ isFloatingChatOpen }) => {
8
+ const maxSwipeableViewHeight = 89;
9
+ const modalSheetControl = (0, react.useRef)(null);
10
+ const { viewportWidth } = require_useCheckIsMobile.useCheckIsMobile();
11
+ const isMobile = viewportWidth !== void 0 && viewportWidth < 512;
12
+ const shouldAutoExpand = Boolean(isMobile && window?._spiffy?.selectedCustomizeOption);
13
+ const snaps = shouldAutoExpand ? [43, 100] : [
14
+ 0,
15
+ 43,
16
+ 100
17
+ ];
18
+ const initialSnap = 1;
19
+ const [currentSnapPercentage, setCurrentSnapPercentage] = (0, react.useState)(snaps[initialSnap] || 43);
20
+ const animationKey = (0, framer_motion.useMotionValue)(0);
21
+ const snap43Percent = 57 / 100 * window.innerHeight;
22
+ const snap100Percent = 0;
23
+ const mobileHeaderHeight = (0, framer_motion.useTransform)(animationKey, [snap100Percent, snap43Percent], [56, 0]);
24
+ const [shouldShowHeader, setShouldShowHeader] = (0, react.useState)(false);
25
+ const [shouldShowScrolled, setShouldShowScrolled] = (0, react.useState)(false);
26
+ (0, react.useEffect)(() => {
27
+ return animationKey.on("change", (value) => {
28
+ setShouldShowHeader(value < snap43Percent - 10);
29
+ setShouldShowScrolled(value > snap43Percent);
30
+ });
31
+ }, [animationKey, snap43Percent]);
32
+ const isFullView = isMobile && currentSnapPercentage === 100;
33
+ const isPartialView = isMobile && currentSnapPercentage >= 0 && currentSnapPercentage <= 43;
34
+ const handleSnapChange = (snapPercentage) => {
35
+ setCurrentSnapPercentage(snapPercentage);
36
+ };
37
+ return {
38
+ modalSheetControl,
39
+ maxSwipeableViewHeight,
40
+ isOpen: window?._spiffy?.selectedCustomizeOption === "SalesAgent" ? true : Boolean(isFloatingChatOpen),
41
+ isMobile,
42
+ snaps,
43
+ initialSnap,
44
+ shouldAutoExpand,
45
+ currentSnapPercentage,
46
+ handleSnapChange,
47
+ animationKey,
48
+ mobileHeaderHeight,
49
+ snap43Percent,
50
+ snap100Percent,
51
+ shouldShowHeader,
52
+ shouldShowScrolled,
53
+ isFullView,
54
+ isPartialView
55
+ };
56
+ };
57
+
58
+ //#endregion
59
+ exports.useSnapSetup = useSnapSetup;