@envive-ai/react-widgets-v3 0.3.68 → 0.3.69

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 (75) hide show
  1. package/dist/CXIntegration/hooks/useUnifiedCXButton.cjs +1 -1
  2. package/dist/CXIntegration/hooks/useUnifiedCXButton.js +1 -1
  3. package/dist/CXIntegration/implementations/useGladlyUnifiedCXButton.cjs +112 -36
  4. package/dist/CXIntegration/implementations/useGladlyUnifiedCXButton.js +112 -36
  5. package/dist/debug/chatEmbed.cjs +3 -3
  6. package/dist/debug/chatEmbed.js +3 -3
  7. package/dist/debug/reportIssue.cjs +18 -6
  8. package/dist/debug/reportIssue.js +19 -7
  9. package/dist/hocs/withBaseWidget/types.d.ts +1 -1
  10. package/dist/hocs/withBaseWidget/withBaseWidget.cjs +2 -2
  11. package/dist/hocs/withBaseWidget/withBaseWidget.d.cts +2 -2
  12. package/dist/hocs/withBaseWidget/withBaseWidget.d.ts +2 -2
  13. package/dist/hocs/withBaseWidget/withBaseWidget.js +2 -2
  14. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.cjs +8 -8
  15. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.cts +3 -3
  16. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +3 -3
  17. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js +8 -8
  18. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.cjs +3 -3
  19. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.cts +3 -3
  20. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +3 -3
  21. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.js +3 -3
  22. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.cjs +6 -6
  23. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.cts +3 -3
  24. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.ts +3 -3
  25. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.js +6 -6
  26. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.cjs +7 -4
  27. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.cts +2 -2
  28. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.ts +2 -2
  29. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.js +7 -4
  30. package/dist/widgets/FloatingChatWidget/hooks/useAutoPopup.cjs +2 -2
  31. package/dist/widgets/FloatingChatWidget/hooks/useAutoPopup.js +2 -2
  32. package/dist/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.cjs +3 -3
  33. package/dist/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.js +3 -3
  34. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.cjs +2 -2
  35. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.cts +2 -2
  36. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.ts +2 -2
  37. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.js +2 -2
  38. package/dist/widgets/ProductCardWidget/ProductCardWidget.cjs +4 -4
  39. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.cts +2 -2
  40. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.ts +2 -2
  41. package/dist/widgets/ProductCardWidget/ProductCardWidget.js +4 -4
  42. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.cjs +6 -6
  43. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.cts +3 -3
  44. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.ts +3 -3
  45. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.js +6 -6
  46. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.cjs +3 -3
  47. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.ts +2 -2
  48. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.js +3 -3
  49. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.cjs +2 -2
  50. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.cts +2 -2
  51. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.js +2 -2
  52. package/dist/widgets/SocialProofWidget/SocialProofWidget.cjs +8 -8
  53. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.cts +3 -3
  54. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.ts +3 -3
  55. package/dist/widgets/SocialProofWidget/SocialProofWidget.js +8 -8
  56. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.cjs +2 -2
  57. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.cts +2 -2
  58. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.ts +2 -2
  59. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.js +2 -2
  60. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.cjs +2 -2
  61. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.cts +2 -2
  62. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +2 -2
  63. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.js +2 -2
  64. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.cjs +4 -4
  65. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.cts +3 -3
  66. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.ts +3 -3
  67. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.js +4 -4
  68. package/dist/widgets/hooks/useGetWidgetStatus.cjs +1 -1
  69. package/dist/widgets/hooks/useGetWidgetStatus.js +1 -1
  70. package/package.json +1 -1
  71. package/src/CXIntegration/implementations/__tests__/useGladlyUnifiedCXButton.test.ts +233 -0
  72. package/src/CXIntegration/implementations/useGladlyUnifiedCXButton.ts +173 -40
  73. package/src/debug/reportIssue.tsx +44 -4
  74. package/src/widgets/FloatingChatWidget/FloatingChatWidget.tsx +14 -1
  75. package/src/widgets/FloatingChatWidget/__tests__/FloatingChatWidget.cxClose.test.tsx +138 -0
@@ -1,8 +1,8 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  const require_types = require('../types.cjs');
3
3
  const require_functions = require('../utils/functions.cjs');
4
- let jotai = require("jotai");
5
4
  let __envive_ai_react_hooks_contexts_pageContext = require("@envive-ai/react-hooks/contexts/pageContext");
5
+ let jotai = require("jotai");
6
6
  let __envive_ai_react_hooks_atoms_app = require("@envive-ai/react-hooks/atoms/app");
7
7
 
8
8
  //#region src/CXIntegration/hooks/useUnifiedCXButton.ts
@@ -1,7 +1,7 @@
1
1
  import { CustomerServiceType } from "../types.js";
2
2
  import { findCustomerServiceImpl } from "../utils/functions.js";
3
- import { useAtomValue } from "jotai";
4
3
  import { usePage } from "@envive-ai/react-hooks/contexts/pageContext";
4
+ import { useAtomValue } from "jotai";
5
5
  import { hasParsedVariantInfoAtom } from "@envive-ai/react-hooks/atoms/app";
6
6
 
7
7
  //#region src/CXIntegration/hooks/useUnifiedCXButton.ts
@@ -6,9 +6,12 @@ let __envive_ai_react_hooks_hooks_ElementObserver = require("@envive-ai/react-ho
6
6
 
7
7
  //#region src/CXIntegration/implementations/useGladlyUnifiedCXButton.ts
8
8
  const GLADLY_CONTAINER_ID = "gladlyChat_container";
9
- const GLADLY_BUTTON_SELECTOR = "[data-aid*=\"gladlyChatChatButton\"]";
10
- const GLADLY_OPEN_SIZE_THRESHOLD = 200;
11
- const POLL_INTERVAL_MS = 400;
9
+ const GLADLY_BUTTON_SELECTOR = "#custom-gladly-pill";
10
+ const HIDE_STYLE_ID = "envive-gladly-pill-hide";
11
+ const ENVIVE_BUTTON_HIDE_STYLE_ID = "envive-floating-button-hide";
12
+ const GLADLY_PANEL_OPEN_SIZE_THRESHOLD = 200;
13
+ const SHADOW_ATTACH_RETRY_MS = 300;
14
+ const SHADOW_POLL_MS = 250;
12
15
  const getGladly = () => window.Gladly;
13
16
  const forceHideContainer = (node) => {
14
17
  node?.style.setProperty("display", "none", "important");
@@ -16,11 +19,76 @@ const forceHideContainer = (node) => {
16
19
  const restoreContainer = (node) => {
17
20
  node?.style.removeProperty("display");
18
21
  };
22
+ /**
23
+ * Hide the merchant's floating pill with an injected CSS rule instead of
24
+ * toggling `display` on a specific element reference. Gladly can re-create
25
+ * the pill node after our reference is taken (re-renders, SDK re-init), so a
26
+ * rule keyed by selector keeps applying no matter how many times the node is
27
+ * swapped out, whereas a stale/detached node reference would silently no-op
28
+ * and let the merchant pill reappear next to ours.
29
+ */
30
+ const hideMerchantButton = () => {
31
+ if (document.getElementById(HIDE_STYLE_ID)) return;
32
+ const style = document.createElement("style");
33
+ style.id = HIDE_STYLE_ID;
34
+ style.textContent = `${GLADLY_BUTTON_SELECTOR} { display: none !important; }`;
35
+ document.head.appendChild(style);
36
+ };
37
+ const showMerchantButton = () => {
38
+ document.getElementById(HIDE_STYLE_ID)?.remove();
39
+ };
40
+ /**
41
+ * Hide/show the Envive floating button via an injected CSS rule rather than
42
+ * `enviveFloatingButton.hide()/.show()`, which toggles inline `display` on a
43
+ * cached node reference. `FloatingChatWidget` unmounts and remounts that
44
+ * button in response to `isCXOpen` (see `buttonShouldRender`), so the cached
45
+ * reference can point at a node React has already removed — the toggle then
46
+ * silently no-ops and the button stays invisible after Gladly closes. A rule
47
+ * keyed by id keeps applying across remounts instead.
48
+ */
49
+ const hideEnviveButton = () => {
50
+ if (document.getElementById(ENVIVE_BUTTON_HIDE_STYLE_ID)) return;
51
+ const style = document.createElement("style");
52
+ style.id = ENVIVE_BUTTON_HIDE_STYLE_ID;
53
+ style.textContent = `#${require_constants.FLOATING_BUTTON_ID} { display: none !important; }`;
54
+ document.head.appendChild(style);
55
+ };
56
+ const showEnviveButton = () => {
57
+ document.getElementById(ENVIVE_BUTTON_HIDE_STYLE_ID)?.remove();
58
+ };
59
+ const isPanelOpenInShadowRoot = (shadowRoot) => Array.from(shadowRoot.querySelectorAll("*")).some((el) => {
60
+ const rect = el.getBoundingClientRect();
61
+ return rect.width > GLADLY_PANEL_OPEN_SIZE_THRESHOLD && rect.height > GLADLY_PANEL_OPEN_SIZE_THRESHOLD;
62
+ });
19
63
  const useGladlyUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchantButton }) => {
20
64
  const gladlyContainer = (0, __envive_ai_react_hooks_hooks_ElementObserver.useElementObserver)(__envive_ai_react_hooks_application_utils.SelectorFactory.id(GLADLY_CONTAINER_ID));
21
- const enviveFloatingButton = (0, __envive_ai_react_hooks_hooks_ElementObserver.useElementObserver)(__envive_ai_react_hooks_application_utils.SelectorFactory.id(require_constants.FLOATING_BUTTON_ID));
22
65
  const wasOpenRef = (0, react.useRef)(false);
23
- const isSwitchEnabled = () => !!document.getElementById(GLADLY_CONTAINER_ID);
66
+ const hasConfirmedOpenRef = (0, react.useRef)(false);
67
+ const isSwitchEnabled = () => {
68
+ const gladly = getGladly();
69
+ const hasGladlySdk = !!gladly && typeof gladly.show === "function";
70
+ const hasGladlyButton = !!document.querySelector(GLADLY_BUTTON_SELECTOR);
71
+ const hasGladlyContainer = !!document.getElementById(GLADLY_CONTAINER_ID);
72
+ return hasGladlySdk || hasGladlyButton || hasGladlyContainer;
73
+ };
74
+ const handleOpen = () => {
75
+ wasOpenRef.current = true;
76
+ hideEnviveButton();
77
+ };
78
+ const handleClose = () => {
79
+ wasOpenRef.current = false;
80
+ hasConfirmedOpenRef.current = false;
81
+ onCXClose?.();
82
+ if (suppressMerchantButton) forceHideContainer(document.getElementById(GLADLY_CONTAINER_ID));
83
+ showEnviveButton();
84
+ };
85
+ const checkShadowOpenStateRef = (0, react.useRef)(() => {});
86
+ checkShadowOpenStateRef.current = (shadowRoot) => {
87
+ if (isPanelOpenInShadowRoot(shadowRoot)) {
88
+ hasConfirmedOpenRef.current = true;
89
+ if (!wasOpenRef.current) handleOpen();
90
+ } else if (wasOpenRef.current && hasConfirmedOpenRef.current) handleClose();
91
+ };
24
92
  gladlyContainer.onAdd((el) => {
25
93
  if (suppressMerchantButton && el && !wasOpenRef.current) forceHideContainer(el);
26
94
  });
@@ -28,45 +96,53 @@ const useGladlyUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchant
28
96
  if (!suppressMerchantButton || !el || wasOpenRef.current) return;
29
97
  if (el.style.display !== "none") forceHideContainer(el);
30
98
  });
99
+ gladlyContainer.onRemove(() => {
100
+ if (wasOpenRef.current) handleClose();
101
+ });
31
102
  (0, react.useEffect)(() => {
32
- if (!suppressMerchantButton) restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
103
+ if (suppressMerchantButton) hideMerchantButton();
104
+ else {
105
+ showMerchantButton();
106
+ restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
107
+ }
108
+ return () => {
109
+ showMerchantButton();
110
+ restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
111
+ };
33
112
  }, [suppressMerchantButton]);
34
113
  (0, react.useEffect)(() => {
35
- const handleOpen = () => {
36
- wasOpenRef.current = true;
37
- enviveFloatingButton.hide();
38
- };
39
- const handleClose = () => {
40
- wasOpenRef.current = false;
41
- onCXClose?.();
42
- const node = document.getElementById(GLADLY_CONTAINER_ID);
43
- if (suppressMerchantButton) forceHideContainer(node);
44
- enviveFloatingButton.show();
45
- };
46
- const checkState = () => {
47
- const node = document.getElementById(GLADLY_CONTAINER_ID);
48
- if (!node) return;
49
- const styles = window.getComputedStyle(node);
50
- if (styles.display === "none" || styles.visibility === "hidden") {
51
- if (wasOpenRef.current) handleClose();
52
- return;
114
+ let shadowObserver = null;
115
+ let retryIntervalId;
116
+ let pollIntervalId;
117
+ const attach = () => {
118
+ const shadowRoot = document.getElementById(GLADLY_CONTAINER_ID)?.shadowRoot;
119
+ if (!shadowRoot || shadowObserver) return;
120
+ shadowObserver = new MutationObserver(() => checkShadowOpenStateRef.current(shadowRoot));
121
+ shadowObserver.observe(shadowRoot, {
122
+ childList: true,
123
+ subtree: true,
124
+ attributes: true
125
+ });
126
+ checkShadowOpenStateRef.current(shadowRoot);
127
+ pollIntervalId = window.setInterval(() => checkShadowOpenStateRef.current(shadowRoot), SHADOW_POLL_MS);
128
+ if (retryIntervalId) {
129
+ window.clearInterval(retryIntervalId);
130
+ retryIntervalId = void 0;
53
131
  }
54
- const rect = node.getBoundingClientRect();
55
- const isOpen = rect.width > GLADLY_OPEN_SIZE_THRESHOLD && rect.height > GLADLY_OPEN_SIZE_THRESHOLD;
56
- if (isOpen && !wasOpenRef.current) handleOpen();
57
- else if (!isOpen && wasOpenRef.current) handleClose();
58
132
  };
59
- const intervalId = window.setInterval(checkState, POLL_INTERVAL_MS);
60
- return () => window.clearInterval(intervalId);
61
- }, [
62
- suppressMerchantButton,
63
- enviveFloatingButton,
64
- onCXClose
65
- ]);
133
+ retryIntervalId = window.setInterval(attach, SHADOW_ATTACH_RETRY_MS);
134
+ attach();
135
+ return () => {
136
+ shadowObserver?.disconnect();
137
+ if (retryIntervalId) window.clearInterval(retryIntervalId);
138
+ if (pollIntervalId) window.clearInterval(pollIntervalId);
139
+ };
140
+ }, []);
66
141
  const toggle = () => {
67
142
  onSwitchToAgent();
68
- enviveFloatingButton.hide();
143
+ hideEnviveButton();
69
144
  wasOpenRef.current = true;
145
+ hasConfirmedOpenRef.current = false;
70
146
  restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
71
147
  const gladly = getGladly();
72
148
  if (gladly && typeof gladly.show === "function") {
@@ -5,9 +5,12 @@ import { useElementObserver } from "@envive-ai/react-hooks/hooks/ElementObserver
5
5
 
6
6
  //#region src/CXIntegration/implementations/useGladlyUnifiedCXButton.ts
7
7
  const GLADLY_CONTAINER_ID = "gladlyChat_container";
8
- const GLADLY_BUTTON_SELECTOR = "[data-aid*=\"gladlyChatChatButton\"]";
9
- const GLADLY_OPEN_SIZE_THRESHOLD = 200;
10
- const POLL_INTERVAL_MS = 400;
8
+ const GLADLY_BUTTON_SELECTOR = "#custom-gladly-pill";
9
+ const HIDE_STYLE_ID = "envive-gladly-pill-hide";
10
+ const ENVIVE_BUTTON_HIDE_STYLE_ID = "envive-floating-button-hide";
11
+ const GLADLY_PANEL_OPEN_SIZE_THRESHOLD = 200;
12
+ const SHADOW_ATTACH_RETRY_MS = 300;
13
+ const SHADOW_POLL_MS = 250;
11
14
  const getGladly = () => window.Gladly;
12
15
  const forceHideContainer = (node) => {
13
16
  node?.style.setProperty("display", "none", "important");
@@ -15,11 +18,76 @@ const forceHideContainer = (node) => {
15
18
  const restoreContainer = (node) => {
16
19
  node?.style.removeProperty("display");
17
20
  };
21
+ /**
22
+ * Hide the merchant's floating pill with an injected CSS rule instead of
23
+ * toggling `display` on a specific element reference. Gladly can re-create
24
+ * the pill node after our reference is taken (re-renders, SDK re-init), so a
25
+ * rule keyed by selector keeps applying no matter how many times the node is
26
+ * swapped out, whereas a stale/detached node reference would silently no-op
27
+ * and let the merchant pill reappear next to ours.
28
+ */
29
+ const hideMerchantButton = () => {
30
+ if (document.getElementById(HIDE_STYLE_ID)) return;
31
+ const style = document.createElement("style");
32
+ style.id = HIDE_STYLE_ID;
33
+ style.textContent = `${GLADLY_BUTTON_SELECTOR} { display: none !important; }`;
34
+ document.head.appendChild(style);
35
+ };
36
+ const showMerchantButton = () => {
37
+ document.getElementById(HIDE_STYLE_ID)?.remove();
38
+ };
39
+ /**
40
+ * Hide/show the Envive floating button via an injected CSS rule rather than
41
+ * `enviveFloatingButton.hide()/.show()`, which toggles inline `display` on a
42
+ * cached node reference. `FloatingChatWidget` unmounts and remounts that
43
+ * button in response to `isCXOpen` (see `buttonShouldRender`), so the cached
44
+ * reference can point at a node React has already removed — the toggle then
45
+ * silently no-ops and the button stays invisible after Gladly closes. A rule
46
+ * keyed by id keeps applying across remounts instead.
47
+ */
48
+ const hideEnviveButton = () => {
49
+ if (document.getElementById(ENVIVE_BUTTON_HIDE_STYLE_ID)) return;
50
+ const style = document.createElement("style");
51
+ style.id = ENVIVE_BUTTON_HIDE_STYLE_ID;
52
+ style.textContent = `#${FLOATING_BUTTON_ID} { display: none !important; }`;
53
+ document.head.appendChild(style);
54
+ };
55
+ const showEnviveButton = () => {
56
+ document.getElementById(ENVIVE_BUTTON_HIDE_STYLE_ID)?.remove();
57
+ };
58
+ const isPanelOpenInShadowRoot = (shadowRoot) => Array.from(shadowRoot.querySelectorAll("*")).some((el) => {
59
+ const rect = el.getBoundingClientRect();
60
+ return rect.width > GLADLY_PANEL_OPEN_SIZE_THRESHOLD && rect.height > GLADLY_PANEL_OPEN_SIZE_THRESHOLD;
61
+ });
18
62
  const useGladlyUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchantButton }) => {
19
63
  const gladlyContainer = useElementObserver(SelectorFactory.id(GLADLY_CONTAINER_ID));
20
- const enviveFloatingButton = useElementObserver(SelectorFactory.id(FLOATING_BUTTON_ID));
21
64
  const wasOpenRef = useRef(false);
22
- const isSwitchEnabled = () => !!document.getElementById(GLADLY_CONTAINER_ID);
65
+ const hasConfirmedOpenRef = useRef(false);
66
+ const isSwitchEnabled = () => {
67
+ const gladly = getGladly();
68
+ const hasGladlySdk = !!gladly && typeof gladly.show === "function";
69
+ const hasGladlyButton = !!document.querySelector(GLADLY_BUTTON_SELECTOR);
70
+ const hasGladlyContainer = !!document.getElementById(GLADLY_CONTAINER_ID);
71
+ return hasGladlySdk || hasGladlyButton || hasGladlyContainer;
72
+ };
73
+ const handleOpen = () => {
74
+ wasOpenRef.current = true;
75
+ hideEnviveButton();
76
+ };
77
+ const handleClose = () => {
78
+ wasOpenRef.current = false;
79
+ hasConfirmedOpenRef.current = false;
80
+ onCXClose?.();
81
+ if (suppressMerchantButton) forceHideContainer(document.getElementById(GLADLY_CONTAINER_ID));
82
+ showEnviveButton();
83
+ };
84
+ const checkShadowOpenStateRef = useRef(() => {});
85
+ checkShadowOpenStateRef.current = (shadowRoot) => {
86
+ if (isPanelOpenInShadowRoot(shadowRoot)) {
87
+ hasConfirmedOpenRef.current = true;
88
+ if (!wasOpenRef.current) handleOpen();
89
+ } else if (wasOpenRef.current && hasConfirmedOpenRef.current) handleClose();
90
+ };
23
91
  gladlyContainer.onAdd((el) => {
24
92
  if (suppressMerchantButton && el && !wasOpenRef.current) forceHideContainer(el);
25
93
  });
@@ -27,45 +95,53 @@ const useGladlyUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchant
27
95
  if (!suppressMerchantButton || !el || wasOpenRef.current) return;
28
96
  if (el.style.display !== "none") forceHideContainer(el);
29
97
  });
98
+ gladlyContainer.onRemove(() => {
99
+ if (wasOpenRef.current) handleClose();
100
+ });
30
101
  useEffect(() => {
31
- if (!suppressMerchantButton) restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
102
+ if (suppressMerchantButton) hideMerchantButton();
103
+ else {
104
+ showMerchantButton();
105
+ restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
106
+ }
107
+ return () => {
108
+ showMerchantButton();
109
+ restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
110
+ };
32
111
  }, [suppressMerchantButton]);
33
112
  useEffect(() => {
34
- const handleOpen = () => {
35
- wasOpenRef.current = true;
36
- enviveFloatingButton.hide();
37
- };
38
- const handleClose = () => {
39
- wasOpenRef.current = false;
40
- onCXClose?.();
41
- const node = document.getElementById(GLADLY_CONTAINER_ID);
42
- if (suppressMerchantButton) forceHideContainer(node);
43
- enviveFloatingButton.show();
44
- };
45
- const checkState = () => {
46
- const node = document.getElementById(GLADLY_CONTAINER_ID);
47
- if (!node) return;
48
- const styles = window.getComputedStyle(node);
49
- if (styles.display === "none" || styles.visibility === "hidden") {
50
- if (wasOpenRef.current) handleClose();
51
- return;
113
+ let shadowObserver = null;
114
+ let retryIntervalId;
115
+ let pollIntervalId;
116
+ const attach = () => {
117
+ const shadowRoot = document.getElementById(GLADLY_CONTAINER_ID)?.shadowRoot;
118
+ if (!shadowRoot || shadowObserver) return;
119
+ shadowObserver = new MutationObserver(() => checkShadowOpenStateRef.current(shadowRoot));
120
+ shadowObserver.observe(shadowRoot, {
121
+ childList: true,
122
+ subtree: true,
123
+ attributes: true
124
+ });
125
+ checkShadowOpenStateRef.current(shadowRoot);
126
+ pollIntervalId = window.setInterval(() => checkShadowOpenStateRef.current(shadowRoot), SHADOW_POLL_MS);
127
+ if (retryIntervalId) {
128
+ window.clearInterval(retryIntervalId);
129
+ retryIntervalId = void 0;
52
130
  }
53
- const rect = node.getBoundingClientRect();
54
- const isOpen = rect.width > GLADLY_OPEN_SIZE_THRESHOLD && rect.height > GLADLY_OPEN_SIZE_THRESHOLD;
55
- if (isOpen && !wasOpenRef.current) handleOpen();
56
- else if (!isOpen && wasOpenRef.current) handleClose();
57
131
  };
58
- const intervalId = window.setInterval(checkState, POLL_INTERVAL_MS);
59
- return () => window.clearInterval(intervalId);
60
- }, [
61
- suppressMerchantButton,
62
- enviveFloatingButton,
63
- onCXClose
64
- ]);
132
+ retryIntervalId = window.setInterval(attach, SHADOW_ATTACH_RETRY_MS);
133
+ attach();
134
+ return () => {
135
+ shadowObserver?.disconnect();
136
+ if (retryIntervalId) window.clearInterval(retryIntervalId);
137
+ if (pollIntervalId) window.clearInterval(pollIntervalId);
138
+ };
139
+ }, []);
65
140
  const toggle = () => {
66
141
  onSwitchToAgent();
67
- enviveFloatingButton.hide();
142
+ hideEnviveButton();
68
143
  wasOpenRef.current = true;
144
+ hasConfirmedOpenRef.current = false;
69
145
  restoreContainer(document.getElementById(GLADLY_CONTAINER_ID));
70
146
  const gladly = getGladly();
71
147
  if (gladly && typeof gladly.show === "function") {
@@ -1,12 +1,12 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_MessageContent = require('./MessageContent.cjs');
3
- let jotai = require("jotai");
4
- let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
5
3
  let react = require("react");
6
4
  react = require_rolldown_runtime.__toESM(react);
5
+ let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
7
6
  let react_jsx_runtime = require("react/jsx-runtime");
8
- let __envive_ai_react_toolkit_v3_PromptCarousel = require("@envive-ai/react-toolkit-v3/PromptCarousel");
9
7
  let __envive_ai_react_hooks_atoms_chat = require("@envive-ai/react-hooks/atoms/chat");
8
+ let jotai = require("jotai");
9
+ let __envive_ai_react_toolkit_v3_PromptCarousel = require("@envive-ai/react-toolkit-v3/PromptCarousel");
10
10
  let classnames = require("classnames");
11
11
  classnames = require_rolldown_runtime.__toESM(classnames);
12
12
 
@@ -1,10 +1,10 @@
1
1
  import { MessageContent } from "./MessageContent.js";
2
- import { useAtomValue } from "jotai";
3
- import { MessageType } from "@envive-ai/react-hooks/application/models";
4
2
  import React from "react";
3
+ import { MessageType } from "@envive-ai/react-hooks/application/models";
5
4
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import { PromptCarousel, PromptCarouselRows } from "@envive-ai/react-toolkit-v3/PromptCarousel";
7
5
  import { chatAtom } from "@envive-ai/react-hooks/atoms/chat";
6
+ import { useAtomValue } from "jotai";
7
+ import { PromptCarousel, PromptCarouselRows } from "@envive-ai/react-toolkit-v3/PromptCarousel";
8
8
  import classNames from "classnames";
9
9
 
10
10
  //#region src/debug/chatEmbed.tsx
@@ -3,18 +3,19 @@ const require_index = require('../node_modules/@spiffy-ai/commerce-api-client/di
3
3
  const require_IconCloseVariant = require('../packages/icons/dist/IconCloseVariant.cjs');
4
4
  const require_GenericSelect = require('./GenericSelect.cjs');
5
5
  const require_chatEmbed = require('./chatEmbed.cjs');
6
- let jotai = require("jotai");
7
- let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
8
6
  let react = require("react");
9
7
  let __envive_ai_react_hooks_application_logging = require("@envive-ai/react-hooks/application/logging");
10
8
  __envive_ai_react_hooks_application_logging = require_rolldown_runtime.__toESM(__envive_ai_react_hooks_application_logging);
9
+ let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
11
10
  let react_jsx_runtime = require("react/jsx-runtime");
12
11
  let __envive_ai_react_hooks_atoms_chat = require("@envive-ai/react-hooks/atoms/chat");
12
+ let jotai = require("jotai");
13
+ let __envive_ai_react_hooks_atoms_app = require("@envive-ai/react-hooks/atoms/app");
14
+ let react_dom = require("react-dom");
13
15
  let classnames = require("classnames");
14
16
  classnames = require_rolldown_runtime.__toESM(classnames);
15
17
  let __envive_ai_react_hooks_application_commerce_api = require("@envive-ai/react-hooks/application/commerce-api");
16
18
  __envive_ai_react_hooks_application_commerce_api = require_rolldown_runtime.__toESM(__envive_ai_react_hooks_application_commerce_api);
17
- let __envive_ai_react_hooks_atoms_app = require("@envive-ai/react-hooks/atoms/app");
18
19
  let __envive_ai_react_hooks_atoms_envive_enviveConfig = require("@envive-ai/react-hooks/atoms/envive/enviveConfig");
19
20
  let __envive_ai_react_hooks_application_utils = require("@envive-ai/react-hooks/application/utils");
20
21
 
@@ -333,10 +334,16 @@ const ReportFooter = ({ isReporting, errorMessage, reportedByIsInvalid, isReason
333
334
  })
334
335
  });
335
336
  };
336
- const Drawer = ({ isOpen, onClose, children, width = "md:envive-tw-w-[80%] lg:envive-tw-w-[67%]" }) => {
337
+ const getPortalTarget = (node) => {
338
+ const root = node?.getRootNode();
339
+ if (root instanceof ShadowRoot) return root;
340
+ if (root instanceof Document) return root.body;
341
+ return null;
342
+ };
343
+ const Drawer = ({ isOpen, onClose, children, width = "md:envive-tw-w-[80%] lg:envive-tw-w-[67%]", anchorNode }) => {
337
344
  if (!isOpen) return null;
338
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
339
- className: "envive-tw-fixed envive-tw-right-[0] envive-tw-top-[0] envive-tw-z-[9999] envive-tw-flex envive-tw-w-full envive-tw-flex-row envive-tw-justify-end",
345
+ const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
346
+ className: "envive-tw-fixed envive-tw-right-[0] envive-tw-top-[0] envive-tw-z-[2147483647] envive-tw-flex envive-tw-w-full envive-tw-flex-row envive-tw-justify-end",
340
347
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
341
348
  className: "envive-tw-bg envive-tw-flex-grow envive-tw-bg-black/40",
342
349
  onClick: onClose
@@ -348,8 +355,11 @@ const Drawer = ({ isOpen, onClose, children, width = "md:envive-tw-w-[80%] lg:en
348
355
  })
349
356
  })]
350
357
  });
358
+ const portalTarget = getPortalTarget(anchorNode);
359
+ return portalTarget ? (0, react_dom.createPortal)(content, portalTarget) : content;
351
360
  };
352
361
  const ReportIssue = () => {
362
+ const anchorRef = (0, react.useRef)(null);
353
363
  const { messages, suggestions, userEvents } = (0, jotai.useAtomValue)(__envive_ai_react_hooks_atoms_chat.chatAtom);
354
364
  const lastMessages = (0, jotai.useAtomValue)(__envive_ai_react_hooks_atoms_chat.lastAssistantMessageAtom);
355
365
  const [lastMessagesText, setLastMessagesText] = (0, react.useState)("");
@@ -474,6 +484,7 @@ const ReportIssue = () => {
474
484
  }));
475
485
  }, []);
476
486
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
487
+ ref: anchorRef,
477
488
  className: "envive-tw-mx-[16px] envive-tw-block envive-tw-h-[24px] envive-tw-w-full",
478
489
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
479
490
  type: "button",
@@ -497,6 +508,7 @@ const ReportIssue = () => {
497
508
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Drawer, {
498
509
  isOpen,
499
510
  onClose,
511
+ anchorNode: anchorRef.current,
500
512
  children: [
501
513
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReportHeader, { onClose }),
502
514
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1,16 +1,17 @@
1
1
  import { IconCloseVariant_default } from "../packages/icons/dist/IconCloseVariant.js";
2
2
  import { GenericSelect } from "./GenericSelect.js";
3
3
  import chatEmbed_default from "./chatEmbed.js";
4
- import { useAtomValue } from "jotai";
5
- import { MessageType } from "@envive-ai/react-hooks/application/models";
6
- import { useCallback, useEffect, useState } from "react";
4
+ import { useCallback, useEffect, useRef, useState } from "react";
7
5
  import Logger from "@envive-ai/react-hooks/application/logging";
6
+ import { MessageType } from "@envive-ai/react-hooks/application/models";
8
7
  import { jsx, jsxs } from "react/jsx-runtime";
9
8
  import { chatAtom, lastAssistantMessageAtom } from "@envive-ai/react-hooks/atoms/chat";
9
+ import { useAtomValue } from "jotai";
10
+ import { userIdAtom } from "@envive-ai/react-hooks/atoms/app";
10
11
  import { ReportSessionRequestReportPriorityEnum, ReportSessionRequestReportTypeEnum } from "@spiffy-ai/commerce-api-client";
12
+ import { createPortal } from "react-dom";
11
13
  import classNames from "classnames";
12
14
  import CommerceApiClient from "@envive-ai/react-hooks/application/commerce-api";
13
- import { userIdAtom } from "@envive-ai/react-hooks/atoms/app";
14
15
  import { orgShortNameAtom } from "@envive-ai/react-hooks/atoms/envive/enviveConfig";
15
16
  import { StringUtils, validateEmail } from "@envive-ai/react-hooks/application/utils";
16
17
 
@@ -328,10 +329,16 @@ const ReportFooter = ({ isReporting, errorMessage, reportedByIsInvalid, isReason
328
329
  })
329
330
  });
330
331
  };
331
- const Drawer = ({ isOpen, onClose, children, width = "md:envive-tw-w-[80%] lg:envive-tw-w-[67%]" }) => {
332
+ const getPortalTarget = (node) => {
333
+ const root = node?.getRootNode();
334
+ if (root instanceof ShadowRoot) return root;
335
+ if (root instanceof Document) return root.body;
336
+ return null;
337
+ };
338
+ const Drawer = ({ isOpen, onClose, children, width = "md:envive-tw-w-[80%] lg:envive-tw-w-[67%]", anchorNode }) => {
332
339
  if (!isOpen) return null;
333
- return /* @__PURE__ */ jsxs("div", {
334
- className: "envive-tw-fixed envive-tw-right-[0] envive-tw-top-[0] envive-tw-z-[9999] envive-tw-flex envive-tw-w-full envive-tw-flex-row envive-tw-justify-end",
340
+ const content = /* @__PURE__ */ jsxs("div", {
341
+ className: "envive-tw-fixed envive-tw-right-[0] envive-tw-top-[0] envive-tw-z-[2147483647] envive-tw-flex envive-tw-w-full envive-tw-flex-row envive-tw-justify-end",
335
342
  children: [/* @__PURE__ */ jsx("div", {
336
343
  className: "envive-tw-bg envive-tw-flex-grow envive-tw-bg-black/40",
337
344
  onClick: onClose
@@ -343,8 +350,11 @@ const Drawer = ({ isOpen, onClose, children, width = "md:envive-tw-w-[80%] lg:en
343
350
  })
344
351
  })]
345
352
  });
353
+ const portalTarget = getPortalTarget(anchorNode);
354
+ return portalTarget ? createPortal(content, portalTarget) : content;
346
355
  };
347
356
  const ReportIssue = () => {
357
+ const anchorRef = useRef(null);
348
358
  const { messages, suggestions, userEvents } = useAtomValue(chatAtom);
349
359
  const lastMessages = useAtomValue(lastAssistantMessageAtom);
350
360
  const [lastMessagesText, setLastMessagesText] = useState("");
@@ -469,6 +479,7 @@ const ReportIssue = () => {
469
479
  }));
470
480
  }, []);
471
481
  return /* @__PURE__ */ jsxs("div", {
482
+ ref: anchorRef,
472
483
  className: "envive-tw-mx-[16px] envive-tw-block envive-tw-h-[24px] envive-tw-w-full",
473
484
  children: [/* @__PURE__ */ jsx("button", {
474
485
  type: "button",
@@ -492,6 +503,7 @@ const ReportIssue = () => {
492
503
  }), /* @__PURE__ */ jsxs(Drawer, {
493
504
  isOpen,
494
505
  onClose,
506
+ anchorNode: anchorRef.current,
495
507
  children: [
496
508
  /* @__PURE__ */ jsx(ReportHeader, { onClose }),
497
509
  /* @__PURE__ */ jsx("div", {
@@ -1,6 +1,6 @@
1
- import { OrgUIConfigV3, WidgetConfigV3, WidgetTypeV3 } from "@envive-ai/react-hooks/contexts/typesV3";
2
1
  import { RefObject } from "react";
3
2
  import { HardcopyResponse } from "@envive-ai/react-hooks/contexts/hardcopyContext";
3
+ import { OrgUIConfigV3, WidgetConfigV3, WidgetTypeV3 } from "@envive-ai/react-hooks/contexts/typesV3";
4
4
 
5
5
  //#region src/hocs/withBaseWidget/types.d.ts
6
6
  interface BaseWidgetProps {
@@ -1,6 +1,4 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
- let __envive_ai_react_hooks_contexts_featureFlagServiceContext = require("@envive-ai/react-hooks/contexts/featureFlagServiceContext");
3
- let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
4
2
  let react = require("react");
5
3
  let __envive_ai_react_hooks_application_logging = require("@envive-ai/react-hooks/application/logging");
6
4
  __envive_ai_react_hooks_application_logging = require_rolldown_runtime.__toESM(__envive_ai_react_hooks_application_logging);
@@ -10,6 +8,8 @@ let __envive_ai_react_hooks_contexts_hardcopyContext = require("@envive-ai/react
10
8
  let __envive_ai_react_hooks_contexts_pageContext = require("@envive-ai/react-hooks/contexts/pageContext");
11
9
  let __envive_ai_react_hooks_contexts_widgetConfigContext = require("@envive-ai/react-hooks/contexts/widgetConfigContext");
12
10
  let __envive_ai_react_hooks_contexts_uiConfigContext = require("@envive-ai/react-hooks/contexts/uiConfigContext");
11
+ let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
12
+ let __envive_ai_react_hooks_contexts_featureFlagServiceContext = require("@envive-ai/react-hooks/contexts/featureFlagServiceContext");
13
13
  let __envive_ai_react_hooks_hooks_WidgetLoadDiagnostics = require("@envive-ai/react-hooks/hooks/WidgetLoadDiagnostics");
14
14
  let react_jsx_runtime = require("react/jsx-runtime");
15
15
 
@@ -1,9 +1,9 @@
1
1
  import { BaseWidgetProps, WithBaseWidgetOptions } from "./types.cjs";
2
- import * as react_jsx_runtime5 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime13 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/hocs/withBaseWidget/withBaseWidget.d.ts
5
5
  declare function withBaseWidget<P extends BaseWidgetProps>(Widget: React.ComponentType<P>, options?: WithBaseWidgetOptions): {
6
- (props: P): react_jsx_runtime5.JSX.Element;
6
+ (props: P): react_jsx_runtime13.JSX.Element;
7
7
  displayName: string;
8
8
  };
9
9
  //#endregion
@@ -1,9 +1,9 @@
1
1
  import { BaseWidgetProps, WithBaseWidgetOptions } from "./types.js";
2
- import * as react_jsx_runtime2 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime16 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/hocs/withBaseWidget/withBaseWidget.d.ts
5
5
  declare function withBaseWidget<P extends BaseWidgetProps>(Widget: React.ComponentType<P>, options?: WithBaseWidgetOptions): {
6
- (props: P): react_jsx_runtime2.JSX.Element;
6
+ (props: P): react_jsx_runtime16.JSX.Element;
7
7
  displayName: string;
8
8
  };
9
9
  //#endregion
@@ -1,5 +1,3 @@
1
- import { useFeatureFlagService } from "@envive-ai/react-hooks/contexts/featureFlagServiceContext";
2
- import { FeatureGates } from "@envive-ai/react-hooks/application/models";
3
1
  import { useEffect, useMemo, useRef, useState } from "react";
4
2
  import Logger from "@envive-ai/react-hooks/application/logging";
5
3
  import { useAmplitude } from "@envive-ai/react-hooks/contexts/amplitudeContext";
@@ -8,6 +6,8 @@ import { useHardcopy } from "@envive-ai/react-hooks/contexts/hardcopyContext";
8
6
  import { usePage } from "@envive-ai/react-hooks/contexts/pageContext";
9
7
  import { useWidgetConfig } from "@envive-ai/react-hooks/contexts/widgetConfigContext";
10
8
  import { useUiConfig } from "@envive-ai/react-hooks/contexts/uiConfigContext";
9
+ import { FeatureGates } from "@envive-ai/react-hooks/application/models";
10
+ import { useFeatureFlagService } from "@envive-ai/react-hooks/contexts/featureFlagServiceContext";
11
11
  import { useWidgetLoadDiagnostics } from "@envive-ai/react-hooks/hooks/WidgetLoadDiagnostics";
12
12
  import { jsx } from "react/jsx-runtime";
13
13