@gemx-dev/heatmap-react 3.5.23 → 3.5.24

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 (223) hide show
  1. package/package.json +14 -11
  2. package/dist/esm/components/HeatmapLayout/ContentHeader.d.ts +0 -4
  3. package/dist/esm/components/HeatmapLayout/ContentHeader.d.ts.map +0 -1
  4. package/dist/esm/components/HeatmapLayout/HeatmapLayout.d.ts +0 -7
  5. package/dist/esm/components/HeatmapLayout/HeatmapLayout.d.ts.map +0 -1
  6. package/dist/esm/components/HeatmapLayout/LeftSidebar.d.ts +0 -4
  7. package/dist/esm/components/HeatmapLayout/LeftSidebar.d.ts.map +0 -1
  8. package/dist/esm/components/HeatmapLayout/ReplayControls.d.ts +0 -2
  9. package/dist/esm/components/HeatmapLayout/ReplayControls.d.ts.map +0 -1
  10. package/dist/esm/components/HeatmapLayout/VizDomContainer.d.ts +0 -2
  11. package/dist/esm/components/HeatmapLayout/VizDomContainer.d.ts.map +0 -1
  12. package/dist/esm/components/HeatmapLayout/VizDomRenderer.d.ts +0 -6
  13. package/dist/esm/components/HeatmapLayout/VizDomRenderer.d.ts.map +0 -1
  14. package/dist/esm/components/HeatmapLayout/WrapperLayout.d.ts +0 -7
  15. package/dist/esm/components/HeatmapLayout/WrapperLayout.d.ts.map +0 -1
  16. package/dist/esm/components/HeatmapLayout/WrapperPreview.d.ts +0 -4
  17. package/dist/esm/components/HeatmapLayout/WrapperPreview.d.ts.map +0 -1
  18. package/dist/esm/components/HeatmapLayout/index.d.ts +0 -2
  19. package/dist/esm/components/HeatmapLayout/index.d.ts.map +0 -1
  20. package/dist/esm/components/VizElement/ClarityVisualizer.d.ts +0 -150
  21. package/dist/esm/components/VizElement/ClarityVisualizer.d.ts.map +0 -1
  22. package/dist/esm/components/VizElement/HeatmapElementV2.d.ts +0 -45
  23. package/dist/esm/components/VizElement/HeatmapElementV2.d.ts.map +0 -1
  24. package/dist/esm/components/VizElement/PayloadProcessor.d.ts +0 -65
  25. package/dist/esm/components/VizElement/PayloadProcessor.d.ts.map +0 -1
  26. package/dist/esm/components/VizElement/VizElementRank.d.ts +0 -74
  27. package/dist/esm/components/VizElement/VizElementRank.d.ts.map +0 -1
  28. package/dist/esm/components/VizElement/constants.d.ts +0 -5
  29. package/dist/esm/components/VizElement/constants.d.ts.map +0 -1
  30. package/dist/esm/components/VizElement/helpers.d.ts +0 -20
  31. package/dist/esm/components/VizElement/helpers.d.ts.map +0 -1
  32. package/dist/esm/components/VizElement/types.d.ts +0 -13
  33. package/dist/esm/components/VizElement/types.d.ts.map +0 -1
  34. package/dist/esm/hooks/useHeatmapByMode.d.ts +0 -6
  35. package/dist/esm/hooks/useHeatmapByMode.d.ts.map +0 -1
  36. package/dist/esm/hooks/useHeatmapRender.d.ts +0 -6
  37. package/dist/esm/hooks/useHeatmapRender.d.ts.map +0 -1
  38. package/dist/esm/hooks/useHeatmapScale.d.ts +0 -28
  39. package/dist/esm/hooks/useHeatmapScale.d.ts.map +0 -1
  40. package/dist/esm/hooks/useReplayRender.d.ts +0 -9
  41. package/dist/esm/hooks/useReplayRender.d.ts.map +0 -1
  42. package/dist/esm/types/index.d.ts +0 -3
  43. package/dist/esm/types/index.d.ts.map +0 -1
  44. package/dist/umd/components/VizElement/VizElementRank.d.ts +0 -75
  45. package/dist/umd/components/VizElement/VizElementRank.d.ts.map +0 -1
  46. package/src/components/GraphView.tsx +0 -58
  47. package/src/components/Layout/ContentHeader.tsx +0 -15
  48. package/src/components/Layout/HeatmapLayout.tsx +0 -63
  49. package/src/components/Layout/LeftSidebar.tsx +0 -32
  50. package/src/components/Layout/WrapperLayout.tsx +0 -18
  51. package/src/components/Layout/WrapperPreview.tsx +0 -14
  52. package/src/components/Layout/index.ts +0 -1
  53. package/src/components/Test.tsx +0 -1106
  54. package/src/components/VizDom/ReplayControls.tsx +0 -48
  55. package/src/components/VizDom/VizDomContainer.tsx +0 -25
  56. package/src/components/VizDom/VizDomRenderer.tsx +0 -87
  57. package/src/components/VizDom/index.ts +0 -1
  58. package/src/components/VizElement/ClickedElementOverlay.tsx +0 -65
  59. package/src/components/VizElement/DefaultRankBadges.tsx +0 -33
  60. package/src/components/VizElement/ElementCallout.tsx +0 -337
  61. package/src/components/VizElement/HeatmapElements.tsx +0 -147
  62. package/src/components/VizElement/HoveredElementOverlay.tsx +0 -46
  63. package/src/components/VizElement/MissingElementMessage.tsx +0 -32
  64. package/src/components/VizElement/RankBadge.tsx +0 -25
  65. package/src/components/VizElement/VizElements.tsx +0 -80
  66. package/src/components/VizElement/index.ts +0 -1
  67. package/src/components/VizElement/temp/ClarityVisualizer.ts +0 -764
  68. package/src/components/VizElement/temp/VizElementRank.tsx +0 -579
  69. package/src/components/index.tsx +0 -4
  70. package/src/configs/iframe.ts +0 -15
  71. package/src/configs/index.ts +0 -2
  72. package/src/configs/style.ts +0 -9
  73. package/src/constants/index.ts +0 -4
  74. package/src/dist/components/GraphView.d.ts +0 -9
  75. package/src/dist/components/GraphView.d.ts.map +0 -1
  76. package/src/dist/components/Layout/ContentHeader.d.ts +0 -4
  77. package/src/dist/components/Layout/ContentHeader.d.ts.map +0 -1
  78. package/src/dist/components/Layout/HeatmapLayout.d.ts +0 -11
  79. package/src/dist/components/Layout/HeatmapLayout.d.ts.map +0 -1
  80. package/src/dist/components/Layout/LeftSidebar.d.ts +0 -4
  81. package/src/dist/components/Layout/LeftSidebar.d.ts.map +0 -1
  82. package/src/dist/components/Layout/WrapperLayout.d.ts +0 -8
  83. package/src/dist/components/Layout/WrapperLayout.d.ts.map +0 -1
  84. package/src/dist/components/Layout/WrapperPreview.d.ts +0 -4
  85. package/src/dist/components/Layout/WrapperPreview.d.ts.map +0 -1
  86. package/src/dist/components/Layout/index.d.ts +0 -2
  87. package/src/dist/components/Layout/index.d.ts.map +0 -1
  88. package/src/dist/components/Test.d.ts +0 -121
  89. package/src/dist/components/Test.d.ts.map +0 -1
  90. package/src/dist/components/VizDom/ReplayControls.d.ts +0 -2
  91. package/src/dist/components/VizDom/ReplayControls.d.ts.map +0 -1
  92. package/src/dist/components/VizDom/VizDomContainer.d.ts +0 -2
  93. package/src/dist/components/VizDom/VizDomContainer.d.ts.map +0 -1
  94. package/src/dist/components/VizDom/VizDomRenderer.d.ts +0 -6
  95. package/src/dist/components/VizDom/VizDomRenderer.d.ts.map +0 -1
  96. package/src/dist/components/VizDom/index.d.ts +0 -2
  97. package/src/dist/components/VizDom/index.d.ts.map +0 -1
  98. package/src/dist/components/VizElement/ClickedElementOverlay.d.ts +0 -17
  99. package/src/dist/components/VizElement/ClickedElementOverlay.d.ts.map +0 -1
  100. package/src/dist/components/VizElement/DefaultRankBadges.d.ts +0 -11
  101. package/src/dist/components/VizElement/DefaultRankBadges.d.ts.map +0 -1
  102. package/src/dist/components/VizElement/ElementCallout.d.ts +0 -17
  103. package/src/dist/components/VizElement/ElementCallout.d.ts.map +0 -1
  104. package/src/dist/components/VizElement/HeatmapElements.d.ts +0 -23
  105. package/src/dist/components/VizElement/HeatmapElements.d.ts.map +0 -1
  106. package/src/dist/components/VizElement/HoveredElementOverlay.d.ts +0 -12
  107. package/src/dist/components/VizElement/HoveredElementOverlay.d.ts.map +0 -1
  108. package/src/dist/components/VizElement/MissingElementMessage.d.ts +0 -7
  109. package/src/dist/components/VizElement/MissingElementMessage.d.ts.map +0 -1
  110. package/src/dist/components/VizElement/RankBadge.d.ts +0 -10
  111. package/src/dist/components/VizElement/RankBadge.d.ts.map +0 -1
  112. package/src/dist/components/VizElement/VizElements.d.ts +0 -10
  113. package/src/dist/components/VizElement/VizElements.d.ts.map +0 -1
  114. package/src/dist/components/VizElement/index.d.ts +0 -2
  115. package/src/dist/components/VizElement/index.d.ts.map +0 -1
  116. package/src/dist/components/VizElement/temp/ClarityVisualizer.d.ts +0 -150
  117. package/src/dist/components/VizElement/temp/ClarityVisualizer.d.ts.map +0 -1
  118. package/src/dist/components/VizElement/temp/VizElementRank.d.ts +0 -74
  119. package/src/dist/components/VizElement/temp/VizElementRank.d.ts.map +0 -1
  120. package/src/dist/components/index.d.ts +0 -4
  121. package/src/dist/components/index.d.ts.map +0 -1
  122. package/src/dist/configs/iframe.d.ts +0 -10
  123. package/src/dist/configs/iframe.d.ts.map +0 -1
  124. package/src/dist/configs/index.d.ts +0 -3
  125. package/src/dist/configs/index.d.ts.map +0 -1
  126. package/src/dist/configs/style.d.ts +0 -9
  127. package/src/dist/configs/style.d.ts.map +0 -1
  128. package/src/dist/constants/index.d.ts +0 -5
  129. package/src/dist/constants/index.d.ts.map +0 -1
  130. package/src/dist/helpers/iframe.d.ts +0 -3
  131. package/src/dist/helpers/iframe.d.ts.map +0 -1
  132. package/src/dist/helpers/index.d.ts +0 -2
  133. package/src/dist/helpers/index.d.ts.map +0 -1
  134. package/src/dist/helpers/viz-elements.d.ts +0 -10
  135. package/src/dist/helpers/viz-elements.d.ts.map +0 -1
  136. package/src/dist/hooks/index.d.ts +0 -4
  137. package/src/dist/hooks/index.d.ts.map +0 -1
  138. package/src/dist/hooks/vix-elements/index.d.ts +0 -5
  139. package/src/dist/hooks/vix-elements/index.d.ts.map +0 -1
  140. package/src/dist/hooks/vix-elements/useClickedElement.d.ts +0 -14
  141. package/src/dist/hooks/vix-elements/useClickedElement.d.ts.map +0 -1
  142. package/src/dist/hooks/vix-elements/useHeatmapEffects.d.ts +0 -8
  143. package/src/dist/hooks/vix-elements/useHeatmapEffects.d.ts.map +0 -1
  144. package/src/dist/hooks/vix-elements/useHeatmapElementPosition.d.ts +0 -13
  145. package/src/dist/hooks/vix-elements/useHeatmapElementPosition.d.ts.map +0 -1
  146. package/src/dist/hooks/vix-elements/useHoveredElement.d.ts +0 -17
  147. package/src/dist/hooks/vix-elements/useHoveredElement.d.ts.map +0 -1
  148. package/src/dist/hooks/viz-render/index.d.ts +0 -2
  149. package/src/dist/hooks/viz-render/index.d.ts.map +0 -1
  150. package/src/dist/hooks/viz-render/useHeatmapRender.d.ts +0 -8
  151. package/src/dist/hooks/viz-render/useHeatmapRender.d.ts.map +0 -1
  152. package/src/dist/hooks/viz-render/useHeatmapVizRender.d.ts +0 -8
  153. package/src/dist/hooks/viz-render/useHeatmapVizRender.d.ts.map +0 -1
  154. package/src/dist/hooks/viz-render/useReplayRender.d.ts +0 -11
  155. package/src/dist/hooks/viz-render/useReplayRender.d.ts.map +0 -1
  156. package/src/dist/hooks/viz-scale/index.d.ts +0 -2
  157. package/src/dist/hooks/viz-scale/index.d.ts.map +0 -1
  158. package/src/dist/hooks/viz-scale/useContainerDimensions.d.ts +0 -10
  159. package/src/dist/hooks/viz-scale/useContainerDimensions.d.ts.map +0 -1
  160. package/src/dist/hooks/viz-scale/useContentDimensions.d.ts +0 -11
  161. package/src/dist/hooks/viz-scale/useContentDimensions.d.ts.map +0 -1
  162. package/src/dist/hooks/viz-scale/useHeatmapScale.d.ts +0 -19
  163. package/src/dist/hooks/viz-scale/useHeatmapScale.d.ts.map +0 -1
  164. package/src/dist/hooks/viz-scale/useIframeHeight.d.ts +0 -10
  165. package/src/dist/hooks/viz-scale/useIframeHeight.d.ts.map +0 -1
  166. package/src/dist/hooks/viz-scale/useScaleCalculation.d.ts +0 -10
  167. package/src/dist/hooks/viz-scale/useScaleCalculation.d.ts.map +0 -1
  168. package/src/dist/hooks/viz-scale/useScrollSync.d.ts +0 -10
  169. package/src/dist/hooks/viz-scale/useScrollSync.d.ts.map +0 -1
  170. package/src/dist/index.d.ts +0 -4
  171. package/src/dist/index.d.ts.map +0 -1
  172. package/src/dist/stores/data.d.ts +0 -18
  173. package/src/dist/stores/data.d.ts.map +0 -1
  174. package/src/dist/stores/index.d.ts +0 -2
  175. package/src/dist/stores/index.d.ts.map +0 -1
  176. package/src/dist/ui/BoxStack/BoxStack.d.ts +0 -56
  177. package/src/dist/ui/BoxStack/BoxStack.d.ts.map +0 -1
  178. package/src/dist/ui/BoxStack/index.d.ts +0 -2
  179. package/src/dist/ui/BoxStack/index.d.ts.map +0 -1
  180. package/src/dist/ui/index.d.ts +0 -2
  181. package/src/dist/ui/index.d.ts.map +0 -1
  182. package/src/dist/utils/device.d.ts +0 -2
  183. package/src/dist/utils/device.d.ts.map +0 -1
  184. package/src/dist/utils/retry.d.ts +0 -2
  185. package/src/dist/utils/retry.d.ts.map +0 -1
  186. package/src/dist/utils/sort.d.ts +0 -3
  187. package/src/dist/utils/sort.d.ts.map +0 -1
  188. package/src/global.d.ts +0 -5
  189. package/src/helpers/iframe.ts +0 -33
  190. package/src/helpers/index.ts +0 -1
  191. package/src/helpers/viz-elements.ts +0 -34
  192. package/src/hooks/index.ts +0 -3
  193. package/src/hooks/vix-elements/index.ts +0 -4
  194. package/src/hooks/vix-elements/useClickedElement.ts +0 -62
  195. package/src/hooks/vix-elements/useHeatmapEffects.ts +0 -29
  196. package/src/hooks/vix-elements/useHeatmapElementPosition.ts +0 -66
  197. package/src/hooks/vix-elements/useHoveredElement.ts +0 -135
  198. package/src/hooks/viz-render/index.ts +0 -1
  199. package/src/hooks/viz-render/useHeatmapRender.ts +0 -98
  200. package/src/hooks/viz-render/useHeatmapVizRender.ts +0 -22
  201. package/src/hooks/viz-render/useReplayRender.ts +0 -162
  202. package/src/hooks/viz-scale/index.ts +0 -1
  203. package/src/hooks/viz-scale/useContainerDimensions.ts +0 -46
  204. package/src/hooks/viz-scale/useContentDimensions.ts +0 -29
  205. package/src/hooks/viz-scale/useHeatmapScale.ts +0 -53
  206. package/src/hooks/viz-scale/useIframeHeight.ts +0 -119
  207. package/src/hooks/viz-scale/useScaleCalculation.ts +0 -28
  208. package/src/hooks/viz-scale/useScrollSync.ts +0 -36
  209. package/src/index.ts +0 -5
  210. package/src/stores/data.ts +0 -34
  211. package/src/stores/index.ts +0 -1
  212. package/src/styles/base.css +0 -1
  213. package/src/styles/style.css +0 -30
  214. package/src/types/clarity.d.ts +0 -38
  215. package/src/types/heatmap.d.ts +0 -3
  216. package/src/types/index.d.ts +0 -3
  217. package/src/types/viz-element.d.ts +0 -39
  218. package/src/ui/BoxStack/BoxStack.tsx +0 -120
  219. package/src/ui/BoxStack/index.ts +0 -1
  220. package/src/ui/index.ts +0 -1
  221. package/src/utils/device.ts +0 -7
  222. package/src/utils/retry.ts +0 -20
  223. package/src/utils/sort.ts +0 -5
@@ -1,66 +0,0 @@
1
- import type { ElementRect, HeatmapElement, WebVisualizer } from '../../types';
2
-
3
- import { useCallback } from 'react';
4
- import { getElementLayout } from '../../helpers/viz-elements';
5
-
6
- interface Params {
7
- iframeRef: React.RefObject<HTMLIFrameElement>;
8
- parentRef: React.RefObject<HTMLElement>;
9
- visualizer?: WebVisualizer;
10
- heatmapWidth?: number;
11
- iframeHeight?: number;
12
- widthScale: number;
13
- projectId?: string;
14
- }
15
-
16
- export const useHeatmapElementPosition = ({
17
- iframeRef,
18
- parentRef,
19
- visualizer,
20
- heatmapWidth,
21
- iframeHeight,
22
- widthScale,
23
- projectId,
24
- }: Params) => {
25
- return useCallback(
26
- (element?: HeatmapElement): ElementRect | null => {
27
- const hash = element?.hash;
28
- if (!iframeRef.current?.contentDocument || !hash || !visualizer) return null;
29
-
30
- let domElement: HTMLElement | null = null;
31
- try {
32
- domElement = visualizer.get(hash);
33
- } catch (error) {
34
- console.error('Visualizer error:', { projectId, hash, error });
35
- return null;
36
- }
37
-
38
- if (!domElement) return null;
39
-
40
- const layout = getElementLayout(domElement);
41
- if (!layout) return null;
42
-
43
- const parentEl = parentRef.current;
44
- if (!parentEl) return null;
45
-
46
- const scrollOffset = parentEl.scrollTop / widthScale;
47
- const adjustedTop = layout.top + scrollOffset;
48
-
49
- const outOfBounds =
50
- adjustedTop < 0 ||
51
- adjustedTop > (iframeHeight || Infinity) ||
52
- layout.left < 0 ||
53
- (typeof heatmapWidth === 'number' && layout.left > heatmapWidth);
54
-
55
- if (outOfBounds) return null;
56
-
57
- return {
58
- left: layout.left,
59
- top: adjustedTop,
60
- width: Math.min(layout.width, heatmapWidth || layout.width),
61
- height: layout.height,
62
- };
63
- },
64
- [iframeRef, parentRef, visualizer, heatmapWidth, iframeHeight, widthScale, projectId],
65
- );
66
- };
@@ -1,135 +0,0 @@
1
- import type { ElementInfo, HeatmapInfo } from '../../types';
2
-
3
- import { useCallback, useState } from 'react';
4
-
5
- const debounce = <T extends (...args: any[]) => void>(
6
- fn: T,
7
- delay: number,
8
- ): ((...args: Parameters<T>) => void) => {
9
- let timeout: ReturnType<typeof setTimeout>;
10
- return (...args: Parameters<T>) => {
11
- clearTimeout(timeout);
12
- timeout = setTimeout(() => fn(...args), delay);
13
- };
14
- };
15
-
16
- interface Params {
17
- iframeRef: React.RefObject<HTMLIFrameElement>;
18
- heatmapInfo?: HeatmapInfo;
19
- widthScale: number;
20
- getRect: (el?: any) => any;
21
- onSelect?: (hash: string) => void;
22
- }
23
-
24
- export const useHoveredElement = ({
25
- iframeRef,
26
- heatmapInfo,
27
- widthScale,
28
- getRect,
29
- onSelect,
30
- }: Params) => {
31
- const [hoveredElement, setHoveredElement] = useState<ElementInfo | null>(null);
32
-
33
- const handleMouseMove = useCallback(
34
- debounce((event: React.MouseEvent<HTMLDivElement>) => {
35
- if (!iframeRef.current?.contentDocument || !heatmapInfo?.elementMapInfo) {
36
- setHoveredElement(null);
37
- return;
38
- }
39
-
40
- const iframe = iframeRef.current;
41
- const iframeRect = iframe.getBoundingClientRect();
42
-
43
- let x = event.clientX - iframeRect.left;
44
- console.log(`🚀 🐥 ~ useHoveredElement ~ iframeRect.left:`, iframeRect.left);
45
- console.log(`🚀 🐥 ~ useHoveredElement ~ event.clientX:`, event.clientX);
46
- let y = event.clientY - iframeRect.top;
47
-
48
- if (widthScale !== 1) {
49
- x /= widthScale;
50
- y /= widthScale;
51
- }
52
- const doc: Document | null = iframe.contentDocument;
53
- if (!doc) {
54
- setHoveredElement(null);
55
- return;
56
- }
57
-
58
- let targetElement: HTMLElement | null = null;
59
-
60
- // Best: dùng caretPositionFromPoint nếu có (Chrome, Safari)
61
- targetElement = getElementAtPoint(doc, x, y);
62
-
63
- if (!targetElement) {
64
- targetElement = doc.elementFromPoint(x, y) as HTMLElement | null;
65
- }
66
-
67
- if (!targetElement) {
68
- setHoveredElement(null);
69
- return;
70
- }
71
-
72
- // Lấy hash từ nhiều attribute khả dĩ
73
- const hash =
74
- targetElement.getAttribute('data-clarity-hash') ||
75
- targetElement.getAttribute('data-clarity-hashalpha') ||
76
- targetElement.getAttribute('data-clarity-hashbeta');
77
-
78
- if (!hash || !heatmapInfo.elementMapInfo[hash]) {
79
- setHoveredElement(null);
80
- return;
81
- }
82
-
83
- const info = heatmapInfo.elementMapInfo[hash];
84
- const position = getRect({ hash, selector: info.selector });
85
-
86
- if (position && heatmapInfo.sortedElements) {
87
- const rank = heatmapInfo.sortedElements.findIndex((e) => e.hash === hash) + 1;
88
-
89
- setHoveredElement({
90
- ...position,
91
- hash,
92
- clicks: info.totalclicks ?? 0,
93
- rank,
94
- selector: info.selector ?? '',
95
- });
96
- } else {
97
- setHoveredElement(null);
98
- }
99
- }, 16), // ~60fps
100
- [iframeRef, heatmapInfo, getRect],
101
- );
102
-
103
- const handleMouseLeave = useCallback(() => {
104
- setHoveredElement(null);
105
- }, []);
106
-
107
- const handleClick = useCallback(() => {
108
- if (hoveredElement?.hash && onSelect) {
109
- onSelect(hoveredElement.hash);
110
- }
111
- }, [hoveredElement, onSelect]);
112
-
113
- return {
114
- hoveredElement,
115
- handleMouseMove,
116
- handleMouseLeave,
117
- handleClick,
118
- };
119
- };
120
-
121
- export const getElementAtPoint = (doc: Document, x: number, y: number): HTMLElement | null => {
122
- let el: Node | null = null;
123
-
124
- if ('caretPositionFromPoint' in doc) {
125
- el = doc.caretPositionFromPoint(x, y)?.offsetNode ?? null;
126
- }
127
-
128
- el = el ?? doc.elementFromPoint(x, y);
129
-
130
- let element = el as HTMLElement | null;
131
- while (element && element.nodeType === Node.TEXT_NODE) {
132
- element = element.parentElement;
133
- }
134
- return element;
135
- };
@@ -1 +0,0 @@
1
- export * from './useHeatmapVizRender';
@@ -1,98 +0,0 @@
1
- import { Data } from '@gemx-dev/clarity-decode';
2
- import { Visualizer } from '@gemx-dev/clarity-visualize';
3
- import { useCallback, useEffect, useRef } from 'react';
4
- import { recreateIframe } from '../../helpers';
5
- import { useHeatmapDataStore } from '../../stores';
6
- import { DecodedPayload } from '../../types';
7
- import { isMobileDevice } from '../../utils/device';
8
-
9
- interface IUseHeatmapRenderResult {
10
- iframeRef: React.RefObject<HTMLIFrameElement | null>;
11
- clarityVisualizer: Visualizer | null;
12
- }
13
-
14
- export const useHeatmapRender = (): IUseHeatmapRenderResult => {
15
- const data = useHeatmapDataStore((state) => state.data);
16
- const config = useHeatmapDataStore((state) => state.config);
17
- const setConfig = useHeatmapDataStore((state) => state.setConfig);
18
- const clickmap = useHeatmapDataStore((state) => state.clickmap);
19
-
20
- const visualizerRef = useRef<Visualizer | null>(null);
21
- const iframeRef = useRef<HTMLIFrameElement | null>(null);
22
-
23
- const initializeVisualizer = useCallback((envelope: Data.Envelope, userAgent: string) => {
24
- const iframe = iframeRef.current;
25
- if (!iframe?.contentWindow) return null;
26
-
27
- const visualizer = new Visualizer();
28
- const mobile = isMobileDevice(userAgent);
29
- visualizer.setup(iframe.contentWindow, {
30
- version: envelope.version,
31
- onresize: (width: number) => {
32
- setConfig({ width });
33
- },
34
- mobile,
35
- vNext: true,
36
- locale: 'en-us',
37
- });
38
-
39
- return visualizer;
40
- }, []);
41
-
42
- // Process and render heatmap HTML
43
- const renderHeatmap = useCallback(
44
- async (payloads: DecodedPayload[]) => {
45
- if (!payloads || payloads.length === 0) return;
46
-
47
- let visualizer = new Visualizer();
48
- const iframe = recreateIframe(iframeRef, config);
49
- // const merged = visualizer.merge(payloads);
50
- // setIframeHeight(Number(iframeRef.current?.height || 0));
51
- // for (const decoded of payloads) {
52
- // // Initialize on first sequence
53
- // if (decoded.envelope.sequence === 1) {
54
- // const userAgent = (decoded.dimension?.[0]?.data[0]?.[0] as string) || '';
55
- // visualizer = initializeVisualizer(decoded.envelope as any, userAgent);
56
-
57
- // if (!visualizer) return;
58
- // visualizerRef.current = visualizer;
59
- // }
60
-
61
- // if (!visualizer) continue;
62
-
63
- // // Merge and process DOM
64
- // const merged = visualizer.merge([decoded]);
65
- // visualizer.dom(merged.dom);
66
- // }
67
-
68
- // Render static HTML
69
- if (visualizer && iframe?.contentWindow) {
70
- await visualizer.html(payloads, iframe.contentWindow);
71
- visualizerRef.current = visualizer;
72
- }
73
- },
74
- [initializeVisualizer],
75
- );
76
-
77
- useEffect(() => {
78
- if (!data || data.length === 0) return;
79
-
80
- renderHeatmap(data);
81
-
82
- return () => {
83
- visualizerRef.current = null;
84
- };
85
- }, [config, data, renderHeatmap]);
86
-
87
- useEffect(() => {
88
- if (!visualizerRef.current || !clickmap || clickmap.length === 0) return;
89
-
90
- visualizerRef.current.clearmap();
91
- visualizerRef.current?.clickmap(clickmap);
92
- }, [clickmap]);
93
-
94
- return {
95
- iframeRef,
96
- clarityVisualizer: visualizerRef.current,
97
- };
98
- };
@@ -1,22 +0,0 @@
1
- import { useMemo } from 'react';
2
- import { useHeatmapRender } from './useHeatmapRender';
3
- import { useReplayRender } from './useReplayRender';
4
- import { Visualizer } from '@gemx-dev/clarity-visualize';
5
-
6
- interface IHeatmapVizRenderResult {
7
- iframeRef: React.RefObject<HTMLIFrameElement | null>;
8
- clarityVisualizer: Visualizer | null;
9
- }
10
-
11
- export const useHeatmapVizRender = (mode: 'heatmap' | 'replay'): IHeatmapVizRenderResult => {
12
- const heatmapResult = useMemo(() => {
13
- switch (mode) {
14
- case 'heatmap':
15
- return useHeatmapRender;
16
- case 'replay':
17
- return useReplayRender;
18
- }
19
- }, [mode]);
20
-
21
- return heatmapResult();
22
- };
@@ -1,162 +0,0 @@
1
- import { Data } from '@gemx-dev/clarity-decode';
2
- import { Visualizer } from '@gemx-dev/clarity-visualize';
3
- import { useCallback, useEffect, useRef } from 'react';
4
- import { useHeatmapDataStore } from '../../stores';
5
- import { DecodedEvents, DecodedPayload } from '../../types';
6
- import { isMobileDevice } from '../../utils/device';
7
- import { sortEvents } from '../../utils/sort';
8
-
9
- interface IUseReplayRenderResult {
10
- iframeRef: React.RefObject<HTMLIFrameElement | null>;
11
- isPlaying: boolean;
12
- clarityVisualizer: Visualizer | null;
13
- play: () => void;
14
- pause: () => void;
15
- }
16
-
17
- export const useReplayRender = (): IUseReplayRenderResult => {
18
- const data = useHeatmapDataStore((state) => state.data);
19
- const setConfig = useHeatmapDataStore((state) => state.setConfig);
20
-
21
- const visualizerRef = useRef<Visualizer | null>(null);
22
- const iframeRef = useRef<HTMLIFrameElement | null>(null);
23
- const eventsRef = useRef<DecodedEvents>([]);
24
- const animationFrameRef = useRef<number | null>(null);
25
- const isPlayingRef = useRef<boolean>(false);
26
-
27
- // Initialize visualizer for replay
28
- const initializeVisualizer = useCallback(
29
- (envelope: Data.Envelope, userAgent: string) => {
30
- const iframe = iframeRef.current;
31
- if (!iframe?.contentWindow) return null;
32
-
33
- // Clear previous events
34
- eventsRef.current = [];
35
-
36
- const visualizer = new Visualizer();
37
- const mobile = isMobileDevice(userAgent);
38
-
39
- visualizer.setup(iframe.contentWindow, {
40
- version: envelope.version,
41
- onresize: (width: number) => {
42
- setConfig({ width });
43
- },
44
- mobile,
45
- vNext: true,
46
- locale: 'en-us',
47
- });
48
-
49
- return visualizer;
50
- },
51
- [setConfig],
52
- );
53
-
54
- // Animation loop for replay
55
- const replayLoop = useCallback(() => {
56
- if (!isPlayingRef.current) return;
57
-
58
- const events = eventsRef.current;
59
- const visualizer = visualizerRef.current;
60
-
61
- if (!visualizer || events.length === 0) {
62
- animationFrameRef.current = requestAnimationFrame(replayLoop);
63
- return;
64
- }
65
-
66
- const event = events[0];
67
- const end = event.time + 16; // 60FPS => 16ms per frame
68
- let index = 0;
69
-
70
- // Get events within current frame
71
- while (events[index] && events[index].time < end) {
72
- index++;
73
- }
74
-
75
- // Render events for this frame
76
- if (index > 0) {
77
- visualizer.render(events.splice(0, index) as any);
78
- }
79
-
80
- animationFrameRef.current = requestAnimationFrame(replayLoop);
81
- }, []);
82
-
83
- // Start replay
84
- const startReplay = useCallback(
85
- async (payloads: DecodedPayload[]) => {
86
- if (!payloads || payloads.length === 0) return;
87
-
88
- let visualizer = visualizerRef.current;
89
-
90
- for (const decoded of payloads) {
91
- // Initialize on first sequence
92
- if (decoded.envelope.sequence === 1) {
93
- const userAgent = (decoded.dimension?.[0]?.data[0]?.[0] as string) || '';
94
- visualizer = initializeVisualizer(decoded.envelope as any, userAgent);
95
-
96
- if (!visualizer) return;
97
- visualizerRef.current = visualizer;
98
- }
99
-
100
- if (!visualizer) continue;
101
-
102
- // Merge events and DOM
103
- const merged = visualizer.merge([decoded]);
104
- eventsRef.current = eventsRef.current.concat(merged.events).sort(sortEvents);
105
- visualizer.dom(merged.dom);
106
- }
107
-
108
- // Render HTML
109
- if (visualizer && iframeRef.current?.contentWindow) {
110
- await visualizer.html(payloads, iframeRef.current.contentWindow);
111
- }
112
-
113
- // Auto-start replay
114
- isPlayingRef.current = true;
115
- animationFrameRef.current = requestAnimationFrame(replayLoop);
116
- },
117
- [initializeVisualizer, replayLoop],
118
- );
119
-
120
- // Play control
121
- const play = useCallback(() => {
122
- if (!isPlayingRef.current) {
123
- isPlayingRef.current = true;
124
- animationFrameRef.current = requestAnimationFrame(replayLoop);
125
- }
126
- }, [replayLoop]);
127
-
128
- // Pause control
129
- const pause = useCallback(() => {
130
- isPlayingRef.current = false;
131
- if (animationFrameRef.current) {
132
- cancelAnimationFrame(animationFrameRef.current);
133
- animationFrameRef.current = null;
134
- }
135
- }, []);
136
-
137
- // Main effect: Start replay when data changes
138
- useEffect(() => {
139
- if (!data || data.length === 0) return;
140
-
141
- startReplay(data);
142
-
143
- // Cleanup
144
- return () => {
145
- isPlayingRef.current = false;
146
- if (animationFrameRef.current) {
147
- cancelAnimationFrame(animationFrameRef.current);
148
- animationFrameRef.current = null;
149
- }
150
- eventsRef.current = [];
151
- visualizerRef.current = null;
152
- };
153
- }, [data, startReplay]);
154
-
155
- return {
156
- iframeRef,
157
- isPlaying: isPlayingRef.current,
158
- clarityVisualizer: visualizerRef.current,
159
- play,
160
- pause,
161
- };
162
- };
@@ -1 +0,0 @@
1
- export * from './useHeatmapScale';
@@ -1,46 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
-
3
- interface IUseContainerDimensionsProps {
4
- wrapperRef: React.RefObject<HTMLDivElement | null>;
5
- }
6
-
7
- interface IUseContainerDimensionsResult {
8
- containerWidth: number;
9
- containerHeight: number;
10
- }
11
-
12
- export const useContainerDimensions = (
13
- props: IUseContainerDimensionsProps,
14
- ): IUseContainerDimensionsResult => {
15
- const { wrapperRef } = props;
16
- const [containerWidth, setContainerWidth] = useState(0);
17
- const [containerHeight, setContainerHeight] = useState(0);
18
- const resizeObserverRef = useRef<ResizeObserver | null>(null);
19
-
20
- const updateDimensions = useCallback(() => {
21
- const scrollContainer = wrapperRef.current?.parentElement?.parentElement;
22
- if (scrollContainer) {
23
- setContainerWidth(scrollContainer.clientWidth);
24
- setContainerHeight(scrollContainer.clientHeight);
25
- }
26
- }, [wrapperRef]);
27
-
28
- useEffect(() => {
29
- const scrollContainer = wrapperRef.current?.parentElement?.parentElement;
30
- if (!scrollContainer || typeof window.ResizeObserver === 'undefined') {
31
- return;
32
- }
33
-
34
- resizeObserverRef.current = new ResizeObserver(updateDimensions);
35
- resizeObserverRef.current.observe(scrollContainer);
36
- updateDimensions();
37
-
38
- return () => {
39
- if (resizeObserverRef.current && scrollContainer) {
40
- resizeObserverRef.current.unobserve(scrollContainer);
41
- }
42
- };
43
- }, [wrapperRef, updateDimensions]);
44
-
45
- return { containerWidth, containerHeight };
46
- };
@@ -1,29 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { IHeatmapConfig } from '../../types';
3
-
4
- interface IUseContentDimensionsProps {
5
- iframeRef: React.RefObject<HTMLIFrameElement | null>;
6
- config?: IHeatmapConfig;
7
- }
8
-
9
- interface IUseContentDimensionsResult {
10
- contentWidth: number;
11
- }
12
-
13
- export const useContentDimensions = (
14
- props: IUseContentDimensionsProps,
15
- ): IUseContentDimensionsResult => {
16
- const { iframeRef, config } = props;
17
- const [contentWidth, setContentWidth] = useState(0);
18
-
19
- useEffect(() => {
20
- if (config?.width) {
21
- if (iframeRef.current) {
22
- iframeRef.current.width = `${config.width}px`;
23
- }
24
- setContentWidth(config.width);
25
- }
26
- }, [config?.width, iframeRef]);
27
-
28
- return { contentWidth };
29
- };
@@ -1,53 +0,0 @@
1
- import { IHeatmapConfig } from '../../types';
2
- import { useContainerDimensions } from './useContainerDimensions';
3
- import { useContentDimensions } from './useContentDimensions';
4
- import { useIframeHeight } from './useIframeHeight';
5
- import { useScaleCalculation } from './useScaleCalculation';
6
- import { useScrollSync } from './useScrollSync';
7
-
8
- interface IHeatmapScaleProps {
9
- wrapperRef: React.RefObject<HTMLDivElement | null>;
10
- iframeRef: React.RefObject<HTMLIFrameElement | null>;
11
- config?: IHeatmapConfig;
12
- }
13
-
14
- interface IUseHeatmapScaleResult {
15
- containerWidth: number;
16
- containerHeight: number;
17
- contentWidth: number;
18
- scaledWidth: number;
19
- scaledHeight: number;
20
- iframeHeight: number;
21
- scale: number;
22
- handleScroll: (scrollTop: number) => void;
23
- }
24
-
25
- export const useHeatmapScale = (props: IHeatmapScaleProps): IUseHeatmapScaleResult => {
26
- const { wrapperRef, iframeRef, config } = props;
27
-
28
- // 1. Observe container dimensions
29
- const { containerWidth, containerHeight } = useContainerDimensions({ wrapperRef });
30
-
31
- // 2. Get content dimensions from config
32
- const { contentWidth } = useContentDimensions({ iframeRef, config });
33
-
34
- // 3. Observe iframe height (now reacts to width changes)
35
- const { iframeHeight } = useIframeHeight({ iframeRef, contentWidth });
36
-
37
- // 4. Calculate scale
38
- const { scale } = useScaleCalculation({ containerWidth, contentWidth });
39
-
40
- // 5. Setup scroll sync
41
- const { handleScroll } = useScrollSync({ iframeRef, scale });
42
-
43
- return {
44
- containerWidth,
45
- containerHeight,
46
- contentWidth,
47
- iframeHeight,
48
- scale,
49
- scaledWidth: contentWidth * scale,
50
- scaledHeight: iframeHeight * scale,
51
- handleScroll,
52
- };
53
- };