@gemx-dev/heatmap-react 3.5.44 → 3.5.46

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 (303) hide show
  1. package/dist/esm/components/Layout/ContentHeader.d.ts +4 -0
  2. package/dist/esm/components/Layout/ContentHeader.d.ts.map +1 -0
  3. package/dist/esm/components/Layout/VizMode.d.ts +2 -0
  4. package/dist/esm/components/Layout/VizMode.d.ts.map +1 -0
  5. package/dist/esm/components/Test.d.ts +121 -0
  6. package/dist/esm/components/Test.d.ts.map +1 -0
  7. package/dist/esm/components/VizDom/VizDomContainer.d.ts +6 -0
  8. package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +1 -0
  9. package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  10. package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts +17 -0
  11. package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts.map +1 -0
  12. package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
  13. package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts +12 -0
  14. package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts.map +1 -0
  15. package/dist/esm/components/VizElement/MissingElementMessage.d.ts +7 -0
  16. package/dist/esm/components/VizElement/MissingElementMessage.d.ts.map +1 -0
  17. package/dist/esm/components/VizElement/VizElements.d.ts.map +1 -1
  18. package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts +150 -0
  19. package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts.map +1 -0
  20. package/dist/esm/components/VizElement/temp/VizElementRank.d.ts +74 -0
  21. package/dist/esm/components/VizElement/temp/VizElementRank.d.ts.map +1 -0
  22. package/dist/esm/components/VizLive/VizLive.d.ts +2 -0
  23. package/dist/esm/components/VizLive/VizLive.d.ts.map +1 -0
  24. package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  25. package/dist/esm/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
  26. package/dist/esm/configs/style.d.ts +0 -2
  27. package/dist/esm/configs/style.d.ts.map +1 -1
  28. package/dist/esm/helpers/index.d.ts +2 -1
  29. package/dist/esm/helpers/index.d.ts.map +1 -1
  30. package/dist/esm/helpers/viewport-fixer.d.ts +13 -0
  31. package/dist/esm/helpers/viewport-fixer.d.ts.map +1 -0
  32. package/dist/esm/helpers/viewport-replacer.d.ts +26 -0
  33. package/dist/esm/helpers/viewport-replacer.d.ts.map +1 -0
  34. package/dist/esm/hooks/vix-elements/useHoveredElement.d.ts.map +1 -1
  35. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts +1 -3
  36. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  37. package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +1 -1
  38. package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -1
  39. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts +1 -3
  40. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  41. package/dist/esm/hooks/viz-live/index.d.ts +1 -1
  42. package/dist/esm/hooks/viz-live/{useVizLiveIframeMsg.d.ts → useIframeMessage.d.ts} +10 -2
  43. package/dist/esm/hooks/viz-live/useIframeMessage.d.ts.map +1 -0
  44. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  45. package/dist/esm/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
  46. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
  47. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  48. package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +10 -0
  49. package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts.map +1 -0
  50. package/dist/esm/index.d.ts +1 -1
  51. package/dist/esm/index.d.ts.map +1 -1
  52. package/dist/esm/index.js +203 -910
  53. package/dist/esm/index.mjs +203 -910
  54. package/dist/esm/stores/index.d.ts +0 -1
  55. package/dist/esm/stores/index.d.ts.map +1 -1
  56. package/dist/esm/stores/interaction.d.ts.map +1 -1
  57. package/dist/esm/stores/mode-live.d.ts +0 -4
  58. package/dist/esm/stores/mode-live.d.ts.map +1 -1
  59. package/dist/esm/stores/viz.d.ts +4 -0
  60. package/dist/esm/stores/viz.d.ts.map +1 -1
  61. package/dist/esm/types/index.d.ts +1 -1
  62. package/dist/esm/types/index.d.ts.map +1 -1
  63. package/dist/esm/types/viewport-fixer.d.ts +31 -0
  64. package/dist/esm/types/viewport-fixer.d.ts.map +1 -0
  65. package/dist/umd/components/Layout/ContentHeader.d.ts +4 -0
  66. package/dist/umd/components/Layout/ContentHeader.d.ts.map +1 -0
  67. package/dist/umd/components/Test.d.ts +121 -0
  68. package/dist/umd/components/Test.d.ts.map +1 -0
  69. package/dist/umd/components/VizDom/VizDomContainer.d.ts +2 -0
  70. package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +1 -0
  71. package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  72. package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts +17 -0
  73. package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts.map +1 -0
  74. package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
  75. package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts +12 -0
  76. package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts.map +1 -0
  77. package/dist/umd/components/VizElement/MissingElementMessage.d.ts +7 -0
  78. package/dist/umd/components/VizElement/MissingElementMessage.d.ts.map +1 -0
  79. package/dist/umd/components/VizElement/VizElements.d.ts.map +1 -1
  80. package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts +150 -0
  81. package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts.map +1 -0
  82. package/dist/umd/components/VizElement/temp/VizElementRank.d.ts +74 -0
  83. package/dist/umd/components/VizElement/temp/VizElementRank.d.ts.map +1 -0
  84. package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  85. package/dist/umd/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
  86. package/dist/umd/configs/style.d.ts +0 -2
  87. package/dist/umd/configs/style.d.ts.map +1 -1
  88. package/dist/umd/helpers/index.d.ts +2 -1
  89. package/dist/umd/helpers/index.d.ts.map +1 -1
  90. package/dist/umd/helpers/viewport-fixer.d.ts +13 -0
  91. package/dist/umd/helpers/viewport-fixer.d.ts.map +1 -0
  92. package/dist/umd/helpers/viewport-replacer.d.ts +26 -0
  93. package/dist/umd/helpers/viewport-replacer.d.ts.map +1 -0
  94. package/dist/umd/hooks/vix-elements/useHoveredElement.d.ts.map +1 -1
  95. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts +1 -3
  96. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  97. package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +1 -1
  98. package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -1
  99. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts +1 -3
  100. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  101. package/dist/umd/hooks/viz-live/index.d.ts +1 -1
  102. package/dist/umd/hooks/viz-live/{useVizLiveIframeMsg.d.ts → useIframeMessage.d.ts} +10 -2
  103. package/dist/umd/hooks/viz-live/useIframeMessage.d.ts.map +1 -0
  104. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  105. package/dist/umd/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
  106. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
  107. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  108. package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +10 -0
  109. package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts.map +1 -0
  110. package/dist/umd/index.d.ts +1 -1
  111. package/dist/umd/index.d.ts.map +1 -1
  112. package/dist/umd/index.js +2 -2
  113. package/dist/umd/stores/index.d.ts +0 -1
  114. package/dist/umd/stores/index.d.ts.map +1 -1
  115. package/dist/umd/stores/interaction.d.ts.map +1 -1
  116. package/dist/umd/stores/mode-live.d.ts +0 -4
  117. package/dist/umd/stores/mode-live.d.ts.map +1 -1
  118. package/dist/umd/stores/viz.d.ts +4 -0
  119. package/dist/umd/stores/viz.d.ts.map +1 -1
  120. package/dist/umd/types/index.d.ts +1 -1
  121. package/dist/umd/types/index.d.ts.map +1 -1
  122. package/dist/umd/types/viewport-fixer.d.ts +31 -0
  123. package/dist/umd/types/viewport-fixer.d.ts.map +1 -0
  124. package/package.json +13 -15
  125. package/src/components/GraphView.tsx +58 -0
  126. package/src/components/Layout/ContentMetricBar.tsx +23 -0
  127. package/src/components/Layout/ContentToolbar.tsx +22 -0
  128. package/src/components/Layout/ContentTopBar.tsx +24 -0
  129. package/src/components/Layout/ContentVizByMode.tsx +14 -0
  130. package/src/components/Layout/HeatmapLayout.tsx +60 -0
  131. package/src/components/Layout/LeftSidebar.tsx +44 -0
  132. package/src/components/Layout/WrapperLayout.tsx +12 -0
  133. package/src/components/Layout/WrapperPreview.tsx +24 -0
  134. package/src/components/Layout/index.ts +1 -0
  135. package/src/components/VizDom/ReplayControls.tsx +48 -0
  136. package/src/components/VizDom/VizContainer.tsx +40 -0
  137. package/src/components/VizDom/VizDomHeatmap.tsx +28 -0
  138. package/src/components/VizDom/VizDomRenderer.tsx +82 -0
  139. package/src/components/VizDom/VizLoading.tsx +8 -0
  140. package/src/components/VizDom/WrapperVisual.tsx +73 -0
  141. package/src/components/VizDom/index.ts +5 -0
  142. package/src/components/VizElement/DefaultRankBadges.tsx +36 -0
  143. package/src/components/VizElement/ElementCallout.tsx +82 -0
  144. package/src/components/VizElement/ElementMissing.tsx +35 -0
  145. package/src/components/VizElement/ElementOverlay.tsx +66 -0
  146. package/src/components/VizElement/HeatmapElements.tsx +127 -0
  147. package/src/components/VizElement/HeatmapExample.tsx +70 -0
  148. package/src/components/VizElement/RankBadge.tsx +25 -0
  149. package/src/components/VizElement/VizElements.tsx +57 -0
  150. package/src/components/VizElement/index.ts +1 -0
  151. package/src/components/VizLive/VizLiveHeatmap.tsx +27 -0
  152. package/src/components/VizLive/VizLiveRenderer.tsx +47 -0
  153. package/src/components/VizLive/index.ts +1 -0
  154. package/src/components/VizScrollmap/AverageFoldLine.tsx +57 -0
  155. package/src/components/VizScrollmap/HoverZones.tsx +58 -0
  156. package/src/components/VizScrollmap/MetricRow.tsx +0 -0
  157. package/src/components/VizScrollmap/ScrollMapMinimap.tsx +64 -0
  158. package/src/components/VizScrollmap/ScrollMapOverlay.tsx +79 -0
  159. package/src/components/VizScrollmap/ScrollZoneHoverArea.tsx +35 -0
  160. package/src/components/VizScrollmap/ScrollZoneTooltip.tsx +146 -0
  161. package/src/components/VizScrollmap/ScrollmapMarker.tsx +106 -0
  162. package/src/components/VizScrollmap/VizScrollMap.tsx +36 -0
  163. package/src/components/VizScrollmap/index.ts +1 -0
  164. package/src/components/VizScrollmapV2/ScrollmapOverlay.css +94 -0
  165. package/src/components/VizScrollmapV2/ScrollmapOverlayV2.tsx +130 -0
  166. package/src/components/VizScrollmapV2/index.ts +1 -0
  167. package/src/components/VizScrollmapV2/scrollmap.types.ts +21 -0
  168. package/src/components/VizScrollmapV2/useScrollmapOverlay.ts +187 -0
  169. package/src/components/index.tsx +2 -0
  170. package/src/configs/iframe.ts +15 -0
  171. package/src/configs/index.ts +2 -0
  172. package/src/configs/style.ts +21 -0
  173. package/src/constants/index.ts +4 -0
  174. package/src/global.d.ts +5 -0
  175. package/src/helpers/elm-callout.ts +347 -0
  176. package/src/helpers/elm-getter.ts +70 -0
  177. package/src/helpers/iframe-helper/fixer.ts +100 -0
  178. package/src/helpers/iframe-helper/index.ts +1 -0
  179. package/src/helpers/iframe-helper/init.ts +56 -0
  180. package/src/helpers/iframe-helper/navigation-blocker-v2.ts +371 -0
  181. package/src/helpers/iframe-helper/navigation-blocker.ts +367 -0
  182. package/src/helpers/iframe-helper/style-replacer.ts +231 -0
  183. package/src/helpers/iframe.ts +42 -0
  184. package/src/helpers/index.ts +8 -0
  185. package/src/helpers/viz-canvas/area-clustering.ts +234 -0
  186. package/src/helpers/viz-canvas/area-overlay-manager-v2.ts +176 -0
  187. package/src/helpers/viz-canvas/area-overlay-manager.ts +273 -0
  188. package/src/helpers/viz-canvas/hierarchical-area-clustering.ts +420 -0
  189. package/src/helpers/viz-canvas/index.ts +2 -0
  190. package/src/helpers/viz-elements.ts +43 -0
  191. package/src/hooks/index.ts +8 -0
  192. package/src/hooks/register/index.ts +4 -0
  193. package/src/hooks/register/useRegisterConfig.ts +17 -0
  194. package/src/hooks/register/useRegisterControl.ts +13 -0
  195. package/src/hooks/register/useRegisterData.ts +36 -0
  196. package/src/hooks/register/useRegisterHeatmap.ts +38 -0
  197. package/src/hooks/viz-area/useAreaHeatmap.ts +336 -0
  198. package/src/hooks/viz-area/useAreaHeatmapManager.ts +692 -0
  199. package/src/hooks/viz-canvas/index.ts +1 -0
  200. package/src/hooks/viz-canvas/useAreamap.ts +162 -0
  201. package/src/hooks/viz-canvas/useClickmap.ts +24 -0
  202. package/src/hooks/viz-canvas/useHeatmapCanvas.ts +27 -0
  203. package/src/hooks/viz-canvas/useScrollmap.ts +22 -0
  204. package/src/hooks/viz-elements/index.ts +5 -0
  205. package/src/hooks/viz-elements/useClickedElement.ts +86 -0
  206. package/src/hooks/viz-elements/useElementCalloutVisible.ts +45 -0
  207. package/src/hooks/viz-elements/useHeatmapEffects.ts +30 -0
  208. package/src/hooks/viz-elements/useHeatmapElementPosition.ts +60 -0
  209. package/src/hooks/viz-elements/useHeatmapMouseHandler.ts +255 -0
  210. package/src/hooks/viz-elements/useHoveredElement.ts +170 -0
  211. package/src/hooks/viz-live/index.ts +1 -0
  212. package/src/hooks/viz-live/useVizLiveIframeMsg.ts +88 -0
  213. package/src/hooks/viz-live/useVizLiveRender.ts +67 -0
  214. package/src/hooks/viz-render/index.ts +1 -0
  215. package/src/hooks/viz-render/useHeatmapRender.ts +71 -0
  216. package/src/hooks/viz-render/useHeatmapVizRender.ts +20 -0
  217. package/src/hooks/viz-render/useReplayRender.ts +160 -0
  218. package/src/hooks/viz-scale/index.ts +2 -0
  219. package/src/hooks/viz-scale/useContainerDimensions.ts +48 -0
  220. package/src/hooks/viz-scale/useContentDimensions.ts +25 -0
  221. package/src/hooks/viz-scale/useHeatmapScale.ts +52 -0
  222. package/src/hooks/viz-scale/useObserveIframeHeight.ts +162 -0
  223. package/src/hooks/viz-scale/useScaleCalculation.ts +31 -0
  224. package/src/hooks/viz-scale/useScrollSync.ts +36 -0
  225. package/src/hooks/viz-scale/useWrapperRefHeight.ts +91 -0
  226. package/src/hooks/viz-scrollmap/index.ts +2 -0
  227. package/src/hooks/viz-scrollmap/useScrollmapZones.ts +165 -0
  228. package/src/hooks/viz-scrollmap/useZonePositions.ts +38 -0
  229. package/src/index.ts +10 -0
  230. package/src/stores/comp.ts +31 -0
  231. package/src/stores/config.ts +37 -0
  232. package/src/stores/data.ts +30 -0
  233. package/src/stores/index.ts +10 -0
  234. package/src/stores/interaction.ts +32 -0
  235. package/src/stores/mode-live.ts +38 -0
  236. package/src/stores/mode-single.ts +18 -0
  237. package/src/stores/viz-scrollmap.ts +22 -0
  238. package/src/stores/viz.ts +17 -0
  239. package/src/styles/base.css +1 -0
  240. package/src/styles/style.css +137 -0
  241. package/src/types/clarity.ts +45 -0
  242. package/src/types/control.ts +10 -0
  243. package/src/types/elm-callout.ts +9 -0
  244. package/src/types/heatmap-info.ts +11 -0
  245. package/src/types/heatmap.ts +25 -0
  246. package/src/types/iframe-helper.ts +18 -0
  247. package/src/types/index.ts +12 -0
  248. package/src/types/viz-canvas.ts +20 -0
  249. package/src/types/viz-element.ts +34 -0
  250. package/src/types/viz-scrollmap.ts +28 -0
  251. package/src/ui/BoxStack/BoxStack.tsx +136 -0
  252. package/src/ui/BoxStack/index.ts +1 -0
  253. package/src/ui/index.ts +1 -0
  254. package/src/utils/debounce.ts +10 -0
  255. package/src/utils/device.ts +7 -0
  256. package/src/utils/retry.ts +20 -0
  257. package/src/utils/sort.ts +5 -0
  258. package/dist/esm/helpers/iframe-helper/fixer.d.ts +0 -18
  259. package/dist/esm/helpers/iframe-helper/fixer.d.ts.map +0 -1
  260. package/dist/esm/helpers/iframe-helper/index.d.ts +0 -2
  261. package/dist/esm/helpers/iframe-helper/index.d.ts.map +0 -1
  262. package/dist/esm/helpers/iframe-helper/init.d.ts +0 -5
  263. package/dist/esm/helpers/iframe-helper/init.d.ts.map +0 -1
  264. package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts +0 -28
  265. package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +0 -1
  266. package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts +0 -20
  267. package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts.map +0 -1
  268. package/dist/esm/helpers/iframe-helper/style-replacer.d.ts +0 -25
  269. package/dist/esm/helpers/iframe-helper/style-replacer.d.ts.map +0 -1
  270. package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts +0 -34
  271. package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts.map +0 -1
  272. package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +0 -1
  273. package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts +0 -4
  274. package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +0 -1
  275. package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -10
  276. package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +0 -1
  277. package/dist/esm/stores/mode-single.d.ts +0 -9
  278. package/dist/esm/stores/mode-single.d.ts.map +0 -1
  279. package/dist/esm/types/iframe-helper.d.ts +0 -20
  280. package/dist/esm/types/iframe-helper.d.ts.map +0 -1
  281. package/dist/umd/helpers/iframe-helper/fixer.d.ts +0 -18
  282. package/dist/umd/helpers/iframe-helper/fixer.d.ts.map +0 -1
  283. package/dist/umd/helpers/iframe-helper/index.d.ts +0 -2
  284. package/dist/umd/helpers/iframe-helper/index.d.ts.map +0 -1
  285. package/dist/umd/helpers/iframe-helper/init.d.ts +0 -5
  286. package/dist/umd/helpers/iframe-helper/init.d.ts.map +0 -1
  287. package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts +0 -28
  288. package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +0 -1
  289. package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts +0 -20
  290. package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts.map +0 -1
  291. package/dist/umd/helpers/iframe-helper/style-replacer.d.ts +0 -25
  292. package/dist/umd/helpers/iframe-helper/style-replacer.d.ts.map +0 -1
  293. package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts +0 -34
  294. package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts.map +0 -1
  295. package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +0 -1
  296. package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts +0 -4
  297. package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +0 -1
  298. package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -10
  299. package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +0 -1
  300. package/dist/umd/stores/mode-single.d.ts +0 -9
  301. package/dist/umd/stores/mode-single.d.ts.map +0 -1
  302. package/dist/umd/types/iframe-helper.d.ts +0 -20
  303. package/dist/umd/types/iframe-helper.d.ts.map +0 -1
@@ -0,0 +1,255 @@
1
+ import { useCallback } from 'react';
2
+ import { IHeatmapInfo } from '../../types';
3
+
4
+ // ===================== TYPES =====================
5
+ interface BoundingBox {
6
+ left: number;
7
+ top: number;
8
+ width: number;
9
+ height: number;
10
+ }
11
+
12
+ interface ElementData {
13
+ totalclicks: number;
14
+ selector: string;
15
+ }
16
+
17
+ interface HoveredElementInfo extends BoundingBox {
18
+ hash: string;
19
+ clicks: number;
20
+ rank: number;
21
+ selector: string;
22
+ }
23
+
24
+ interface UseHeatmapMouseHandlerProps {
25
+ heatmapWrapperRef: React.RefObject<HTMLElement>;
26
+ iframeRef: React.RefObject<HTMLIFrameElement>;
27
+ parentRef: React.RefObject<HTMLDivElement>;
28
+ heatmapInfo: IHeatmapInfo;
29
+ scaleRatio: number; // zoom/scale ratio
30
+ onElementHover: (info: HoveredElementInfo) => void;
31
+ }
32
+
33
+ // ===================== CONSTANTS =====================
34
+ const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha'; // Hoặc attribute bạn đang dùng
35
+
36
+ // ===================== UTILITY FUNCTIONS =====================
37
+
38
+ /**
39
+ * Lấy bounding box tuyệt đối của element (relative to document)
40
+ */
41
+ export function getBoundingBox(element: HTMLElement): BoundingBox | null {
42
+ if (typeof element.getBoundingClientRect !== 'function') {
43
+ return null;
44
+ }
45
+
46
+ const rect = element.getBoundingClientRect();
47
+
48
+ // Lấy scroll offset (hỗ trợ cả cách cũ và mới)
49
+ const scrollLeft =
50
+ 'pageXOffset' in window ? window.pageXOffset : document.documentElement.scrollLeft;
51
+
52
+ const scrollTop =
53
+ 'pageYOffset' in window ? window.pageYOffset : document.documentElement.scrollTop;
54
+
55
+ // Kiểm tra element có kích thước hợp lệ
56
+ if (!rect || (rect.height === 0 && rect.width === 0)) {
57
+ return null;
58
+ }
59
+
60
+ // Trả về vị trí tuyệt đối
61
+ return {
62
+ left: Math.floor(rect.left + scrollLeft),
63
+ top: Math.floor(rect.top + scrollTop),
64
+ width: Math.floor(rect.width),
65
+ height: Math.floor(rect.height),
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Lấy tất cả elements tại tọa độ (x, y), hỗ trợ Shadow DOM
71
+ */
72
+ export function getElementsAtPoint(
73
+ documentOrShadowRoot: Document | ShadowRoot,
74
+ x: number,
75
+ y: number,
76
+ filterFunction?: (element: Element) => boolean,
77
+ visitedShadowRoots: Set<ShadowRoot> = new Set(),
78
+ ): Element[] {
79
+ // Lấy tất cả elements tại vị trí
80
+ const elementsAtPoint = documentOrShadowRoot.elementsFromPoint(x, y);
81
+
82
+ if (!filterFunction) {
83
+ return elementsAtPoint;
84
+ }
85
+
86
+ // Tìm element đầu tiên match với filter
87
+ const matchedElement = elementsAtPoint.find(filterFunction);
88
+
89
+ // Nếu element có Shadow DOM và chưa visit -> đệ quy vào
90
+ if (matchedElement?.shadowRoot && !visitedShadowRoots.has(matchedElement.shadowRoot)) {
91
+ visitedShadowRoots.add(matchedElement.shadowRoot);
92
+
93
+ return getElementsAtPoint(matchedElement.shadowRoot, x, y, filterFunction, visitedShadowRoots);
94
+ }
95
+
96
+ return elementsAtPoint;
97
+ }
98
+
99
+ // ===================== MAIN HOOK =====================
100
+
101
+ export function useHeatmapMouseHandler(props: UseHeatmapMouseHandlerProps) {
102
+ const { heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover } =
103
+ props;
104
+
105
+ const handleMouseMove = useCallback(
106
+ (event: MouseEvent) => {
107
+ // Kiểm tra tất cả refs và data cần thiết
108
+ if (
109
+ !heatmapWrapperRef?.current ||
110
+ !iframeRef?.current ||
111
+ !iframeRef.current.contentDocument ||
112
+ !heatmapInfo?.elementMapInfo ||
113
+ !parentRef?.current
114
+ ) {
115
+ return;
116
+ }
117
+
118
+ try {
119
+ // Tính toán scroll position (đã scale)
120
+ const scrollTop = parentRef.current.scrollTop / scaleRatio;
121
+ console.log(`🚀 🐥 ~ useHeatmapMouseHandler ~ scrollTop:`, scrollTop);
122
+
123
+ // Lấy vị trí của heatmap wrapper
124
+ const wrapperRect = heatmapWrapperRef.current.getBoundingClientRect();
125
+
126
+ // Tính toán tọa độ chuột trong iframe (đã scale)
127
+ const mouseX = (event.clientX - wrapperRect.left) / scaleRatio;
128
+ const mouseY = (event.clientY - wrapperRect.top) / scaleRatio - scrollTop;
129
+
130
+ // Tìm elements tại vị trí chuột
131
+ const elementsAtPoint = getElementsAtPoint(
132
+ iframeRef.current.contentDocument,
133
+ Math.round(mouseX),
134
+ Math.round(mouseY),
135
+ // Filter: chỉ lấy elements có heatmap attribute
136
+ (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE),
137
+ );
138
+
139
+ if (!elementsAtPoint || elementsAtPoint.length === 0) {
140
+ return;
141
+ }
142
+
143
+ // Duyệt qua các elements tìm được
144
+ for (let i = 0; i < elementsAtPoint.length; i++) {
145
+ const element = elementsAtPoint[i] as HTMLElement;
146
+
147
+ // Lấy hash/id của element
148
+ const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
149
+
150
+ // Kiểm tra element có data trong heatmapInfo không
151
+ if (elementHash && heatmapInfo.elementMapInfo[elementHash]) {
152
+ const elementData = heatmapInfo.elementMapInfo[elementHash];
153
+
154
+ // Lấy bounding box của element
155
+ const boundingBox = getBoundingBox(element);
156
+
157
+ if (boundingBox) {
158
+ // Tính rank của element
159
+ const rank =
160
+ Array.isArray(heatmapInfo.sortedElements) && elementData
161
+ ? heatmapInfo.sortedElements.indexOf(elementData) + 1
162
+ : NaN;
163
+
164
+ // Callback với thông tin element
165
+ onElementHover({
166
+ ...boundingBox,
167
+
168
+ // Giới hạn width không vượt quá width của heatmap
169
+ width: Math.min(boundingBox.width, heatmapInfo.width || 0),
170
+
171
+ // Adjust top position với scroll
172
+ top: boundingBox.top + scrollTop,
173
+
174
+ // Metadata
175
+ hash: elementHash,
176
+ clicks: elementData.totalclicks,
177
+ rank: rank,
178
+ selector: elementData.selector || '',
179
+ });
180
+
181
+ // Dừng loop khi tìm thấy element hợp lệ đầu tiên
182
+ break;
183
+ }
184
+ }
185
+ }
186
+ } catch (error) {
187
+ console.warn('Error handling mouse move on heatmap:', error);
188
+ }
189
+ },
190
+ [heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover],
191
+ );
192
+
193
+ return { handleMouseMove };
194
+ }
195
+
196
+ // ===================== EXAMPLE USAGE =====================
197
+ /*
198
+ import { useRef, useState } from 'react';
199
+
200
+ function HeatmapComponent() {
201
+ const heatmapWrapperRef = useRef<HTMLDivElement>(null);
202
+ const iframeRef = useRef<HTMLIFrameElement>(null);
203
+ const parentRef = useRef<HTMLDivElement>(null);
204
+
205
+ const [hoveredElement, setHoveredElement] = useState<HoveredElementInfo | null>(null);
206
+
207
+ const heatmapInfo = {
208
+ width: 1920,
209
+ elementMapInfo: {
210
+ 'hash123': {
211
+ totalclicks: 45,
212
+ selector: 'button.submit'
213
+ }
214
+ },
215
+ sortedElements: [...]
216
+ };
217
+
218
+ const { handleMouseMove } = useHeatmapMouseHandler({
219
+ heatmapWrapperRef,
220
+ iframeRef,
221
+ parentRef,
222
+ heatmapInfo,
223
+ scaleRatio: 0.8, // 80% zoom
224
+ onElementHover: (info) => {
225
+ setHoveredElement(info);
226
+ console.log('Hovered element:', info);
227
+ }
228
+ });
229
+
230
+ return (
231
+ <div ref={parentRef}>
232
+ <div
233
+ ref={heatmapWrapperRef}
234
+ onMouseMove={handleMouseMove}
235
+ >
236
+ <iframe ref={iframeRef} />
237
+
238
+ {hoveredElement && (
239
+ <div className="tooltip" style={{
240
+ position: 'absolute',
241
+ left: hoveredElement.left,
242
+ top: hoveredElement.top
243
+ }}>
244
+ Clicks: {hoveredElement.clicks}
245
+ <br />
246
+ Rank: #{hoveredElement.rank}
247
+ <br />
248
+ Selector: {hoveredElement.selector}
249
+ </div>
250
+ )}
251
+ </div>
252
+ </div>
253
+ );
254
+ }
255
+ */
@@ -0,0 +1,170 @@
1
+ import { useCallback } from 'react';
2
+ import { buildElementInfo, getElementAtPoint, getElementHash } from '../../helpers';
3
+ import { useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapVizStore } from '../../stores';
4
+ import { IHeatmapInfo } from '../../types';
5
+ import { debounce } from '../../utils/debounce';
6
+ import { getBoundingBox, getElementsAtPoint } from './useHeatmapMouseHandler';
7
+
8
+ interface Params {
9
+ iframeRef: React.RefObject<HTMLIFrameElement>;
10
+ getRect: (el?: any) => any;
11
+ }
12
+ export const useHoveredElement = ({ iframeRef, getRect }: Params) => {
13
+ const hoveredElement = useHeatmapInteractionStore((state) => state.hoveredElement);
14
+ const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
15
+ const onSelect = useHeatmapInteractionStore((state) => state.setSelectedElement);
16
+ const widthScale = useHeatmapVizStore((state) => state.scale);
17
+ const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
18
+
19
+ const reset = useCallback(() => {
20
+ setHoveredElement(null);
21
+ }, [setHoveredElement]);
22
+ const handleMouseLeave = useCallback(() => {
23
+ reset();
24
+ }, [reset]);
25
+
26
+ const getHashFromEvent = useCallback(
27
+ (event: React.MouseEvent<HTMLDivElement>) => {
28
+ if (!heatmapInfo || !isIframeReady(iframeRef, heatmapInfo)) {
29
+ reset();
30
+ return;
31
+ }
32
+
33
+ const iframe = iframeRef.current!;
34
+ const doc = iframe.contentDocument!;
35
+ const iframeRect = iframe.getBoundingClientRect();
36
+ const { x, y } = convertViewportToIframeCoords(
37
+ event.clientX,
38
+ event.clientY,
39
+ iframeRect,
40
+ widthScale,
41
+ );
42
+
43
+ const targetElement = findTargetElement(doc, x, y, heatmapInfo);
44
+ if (!targetElement || !isValidElement(targetElement, heatmapInfo)) {
45
+ reset();
46
+ return;
47
+ }
48
+
49
+ const hash = getElementHash(targetElement);
50
+ if (!!hash) return hash;
51
+
52
+ reset();
53
+ return;
54
+ },
55
+ [heatmapInfo, iframeRef, getRect, widthScale, reset],
56
+ );
57
+
58
+ const handleMouseMove = useCallback(
59
+ debounce((event: React.MouseEvent<HTMLDivElement>) => {
60
+ if (!heatmapInfo) {
61
+ reset();
62
+ return;
63
+ }
64
+
65
+ const hash = getHashFromEvent(event);
66
+ if (!hash) {
67
+ reset();
68
+ return;
69
+ }
70
+
71
+ const selector = heatmapInfo?.elementMapInfo?.[hash];
72
+ const rect = getRect({ hash, selector });
73
+ const elementInfo = buildElementInfo(hash, rect, heatmapInfo);
74
+ if (!elementInfo) {
75
+ reset();
76
+ return;
77
+ }
78
+
79
+ setHoveredElement(elementInfo);
80
+ }, 16),
81
+ [heatmapInfo, getRect, reset, getHashFromEvent],
82
+ );
83
+
84
+ const handleClick = useCallback(() => {
85
+ if (!hoveredElement?.hash) return;
86
+
87
+ onSelect(hoveredElement.hash);
88
+ }, [hoveredElement?.hash]);
89
+
90
+ return {
91
+ hoveredElement,
92
+ handleMouseMove,
93
+ handleMouseLeave,
94
+ handleClick,
95
+ };
96
+ };
97
+
98
+ export const convertViewportToIframeCoords = (
99
+ clientX: number,
100
+ clientY: number,
101
+ iframeRect: DOMRect,
102
+ scale: number,
103
+ ): { x: number; y: number } => {
104
+ let x = clientX - iframeRect.left;
105
+ let y = clientY - iframeRect.top;
106
+
107
+ if (scale !== 1) {
108
+ x /= scale;
109
+ y /= scale;
110
+ }
111
+
112
+ return { x, y };
113
+ };
114
+
115
+ const findTargetElement = (
116
+ doc: Document,
117
+ x: number,
118
+ y: number,
119
+ heatmapInfo: IHeatmapInfo,
120
+ ): HTMLElement | null => {
121
+ const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha';
122
+ const elementsAtPoint = getElementsAtPoint(
123
+ doc,
124
+ Math.round(x),
125
+ Math.round(y),
126
+ (element: Element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE),
127
+ );
128
+
129
+ let dataElement = null;
130
+ for (let i = 0; i < elementsAtPoint.length; i++) {
131
+ const element = elementsAtPoint[i] as HTMLElement;
132
+ const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
133
+ if (elementHash && heatmapInfo.elementMapInfo?.[elementHash]) {
134
+ const elementData = heatmapInfo.elementMapInfo[elementHash];
135
+ const boundingBox = getBoundingBox(element);
136
+
137
+ if (boundingBox) {
138
+ dataElement = element;
139
+ break;
140
+ }
141
+ }
142
+ }
143
+ if (!!dataElement) {
144
+ return dataElement;
145
+ }
146
+
147
+ let targetElement = getElementAtPoint(doc, x, y);
148
+
149
+ if (!targetElement) {
150
+ targetElement = doc.elementFromPoint(x, y) as HTMLElement | null;
151
+ }
152
+
153
+ return targetElement;
154
+ };
155
+
156
+ const isIframeReady = (
157
+ iframeRef: React.RefObject<HTMLIFrameElement>,
158
+ heatmapInfo?: IHeatmapInfo,
159
+ ): boolean => {
160
+ return !!(iframeRef.current?.contentDocument && heatmapInfo?.elementMapInfo);
161
+ };
162
+
163
+ const isValidElement = (element: HTMLElement | null, heatmapInfo?: IHeatmapInfo): boolean => {
164
+ if (!element) return false;
165
+
166
+ const hash = getElementHash(element);
167
+ if (!hash) return false;
168
+
169
+ return !!heatmapInfo?.elementMapInfo?.[hash];
170
+ };
@@ -0,0 +1 @@
1
+ export * from './useVizLiveRender';
@@ -0,0 +1,88 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { decodePayloads } from '../../helpers';
3
+ import { useHeatmapLiveStore } from '../../stores';
4
+
5
+ export enum MessageType {
6
+ GX_DOM_TRACKING_PAYLOAD = 'GX_DOM_TRACKING_PAYLOAD',
7
+ CLARITY_READY = 'CLARITY_READY',
8
+ }
9
+
10
+ export interface ClarityMessage {
11
+ type: MessageType;
12
+ payload?: any;
13
+ timestamp?: number;
14
+ }
15
+
16
+ interface UseIframeMessageOptions {
17
+ trustedOrigins?: string[];
18
+ onMessage?: (message: ClarityMessage) => void;
19
+ }
20
+
21
+ export function useVizLiveIframeMsg(options: UseIframeMessageOptions = {}) {
22
+ const { trustedOrigins = [], onMessage } = options;
23
+
24
+ const addPayload = useHeatmapLiveStore((state) => state.addPayload);
25
+
26
+ const [isReady, setIsReady] = useState(false);
27
+
28
+ const iframeRef = useRef<HTMLIFrameElement>(null);
29
+
30
+ const isValidOrigin = useCallback(
31
+ (origin: string) => {
32
+ if (trustedOrigins.length === 0) return true;
33
+ return trustedOrigins.includes(origin);
34
+ },
35
+ [trustedOrigins],
36
+ );
37
+
38
+ const handleMessage = useCallback(
39
+ (event: MessageEvent<ClarityMessage>) => {
40
+ if (!isValidOrigin(event.origin)) {
41
+ console.warn('Message from untrusted origin:', event.origin);
42
+ return;
43
+ }
44
+
45
+ if (!event.data || typeof event.data !== 'object' || !event.data.type) {
46
+ return;
47
+ }
48
+
49
+ const message = event.data;
50
+
51
+ if (!Object.values(MessageType).includes(message.type)) {
52
+ return;
53
+ }
54
+
55
+ if (onMessage) {
56
+ onMessage(message);
57
+ }
58
+
59
+ switch (message.type) {
60
+ case MessageType.GX_DOM_TRACKING_PAYLOAD:
61
+ if (message.payload) {
62
+ const data = decodePayloads(message.payload);
63
+ if (data) {
64
+ addPayload(data);
65
+ }
66
+ }
67
+ break;
68
+
69
+ case MessageType.CLARITY_READY:
70
+ setIsReady(true);
71
+ break;
72
+ }
73
+ },
74
+ [isValidOrigin, onMessage],
75
+ );
76
+
77
+ useEffect(() => {
78
+ window.addEventListener('message', handleMessage);
79
+ return () => {
80
+ window.removeEventListener('message', handleMessage);
81
+ };
82
+ }, [handleMessage]);
83
+
84
+ return {
85
+ iframeRef,
86
+ isReady,
87
+ };
88
+ }
@@ -0,0 +1,67 @@
1
+ import { useEffect } from 'react';
2
+ import { initIframeHelperFixer } from '../../helpers';
3
+ import { useHeatmapConfigStore, useHeatmapLiveStore, useHeatmapVizStore } from '../../stores';
4
+ import { useVizLiveIframeMsg } from './useVizLiveIframeMsg';
5
+
6
+ export function useVizLiveRender() {
7
+ const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
8
+ const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
9
+ const contentWidth = useHeatmapConfigStore((state) => state.width);
10
+ const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
11
+ const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
12
+
13
+ const { iframeRef, isReady } = useVizLiveIframeMsg();
14
+
15
+ useEffect(() => {
16
+ if (!htmlContent || !iframeRef.current) return;
17
+
18
+ const iframe = iframeRef.current;
19
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
20
+
21
+ if (iframeDoc) {
22
+ iframeDoc.open();
23
+ iframeDoc.writeln(htmlContent);
24
+ iframeDoc.close();
25
+ }
26
+ }, [htmlContent]);
27
+
28
+ useEffect(() => {
29
+ if (!isReady) return;
30
+ if (!iframeRef.current) return;
31
+
32
+ const iframe = iframeRef.current;
33
+ if (!iframe || !htmlContent) return;
34
+
35
+ setIsRenderViz(false);
36
+ reset(iframe, { width: contentWidth, height: wrapperHeight }, (height) => {
37
+ height && setIframeHeight(height);
38
+ setIsRenderViz(true);
39
+ });
40
+ }, [isReady, contentWidth, wrapperHeight]);
41
+
42
+ return {
43
+ iframeRef,
44
+ };
45
+ }
46
+
47
+ function reset(
48
+ iframe: HTMLIFrameElement,
49
+ rect: {
50
+ width: number;
51
+ height: number;
52
+ },
53
+ onSuccess: (height: number) => void,
54
+ ) {
55
+ const fixer = initIframeHelperFixer({
56
+ targetWidth: rect.width,
57
+ targetHeight: rect.height,
58
+ iframe: iframe,
59
+ onSuccess: (data) => {
60
+ iframe.height = `${data.height}px`;
61
+ onSuccess(data.height);
62
+ },
63
+ });
64
+
65
+ // fixer.recalculate();
66
+ fixer.enableNavigationBlocking();
67
+ }
@@ -0,0 +1 @@
1
+ export * from './useHeatmapVizRender';
@@ -0,0 +1,71 @@
1
+ import { Visualizer } from '@gemx-dev/clarity-visualize';
2
+ import { useCallback, useEffect, useRef } from 'react';
3
+ import { findLastSizeOfDom, initIframeHelperFixer } from '../../helpers';
4
+ import { useHeatmapDataStore, useHeatmapSingleStore, useHeatmapVizStore } from '../../stores';
5
+ import { DecodedPayload } from '../../types';
6
+
7
+ interface IUseHeatmapRenderResult {
8
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
9
+ }
10
+
11
+ let visualizer: Visualizer = new Visualizer();
12
+ export const useHeatmapRender = (): IUseHeatmapRenderResult => {
13
+ const data = useHeatmapDataStore((state) => state.data);
14
+ const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
15
+ const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
16
+ const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
17
+
18
+ const iframeRef = useRef<HTMLIFrameElement | null>(null);
19
+
20
+ const renderHeatmap = useCallback(async (payloads: DecodedPayload[]) => {
21
+ if (!payloads || payloads.length === 0) return;
22
+
23
+ setIsRenderViz(false);
24
+ const iframe = iframeRef.current;
25
+ if (!iframe?.contentWindow) return;
26
+
27
+ await visualizer.html(payloads, iframe.contentWindow);
28
+
29
+ initIframe(iframe, payloads, (height: number) => {
30
+ height && setIframeHeight(height);
31
+ setIsRenderViz(true);
32
+ setVizRef(visualizer);
33
+ });
34
+ }, []);
35
+
36
+ useEffect(() => {
37
+ if (!data || data.length === 0) return;
38
+
39
+ renderHeatmap(data);
40
+ return () => {
41
+ setVizRef(null);
42
+ };
43
+ }, [data]);
44
+
45
+ return {
46
+ iframeRef,
47
+ };
48
+ };
49
+
50
+ function initIframe(
51
+ iframe: HTMLIFrameElement,
52
+ payloads: DecodedPayload[],
53
+ onSuccess: (height: number) => void,
54
+ ) {
55
+ const { size } = findLastSizeOfDom(payloads);
56
+
57
+ const docWidth = size.width ?? 0;
58
+ const docHeight = size.height ?? 0;
59
+
60
+ const fixer = initIframeHelperFixer({
61
+ targetWidth: docWidth,
62
+ targetHeight: docHeight,
63
+ iframe: iframe,
64
+ onSuccess: (data) => {
65
+ iframe.height = `${data.height}px`;
66
+ onSuccess(data.height);
67
+ },
68
+ });
69
+
70
+ // fixer.recalculate();
71
+ }
@@ -0,0 +1,20 @@
1
+ import { useMemo } from 'react';
2
+ import { useHeatmapRender } from './useHeatmapRender';
3
+ import { useReplayRender } from './useReplayRender';
4
+
5
+ interface IHeatmapVizRenderResult {
6
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
7
+ }
8
+
9
+ export const useHeatmapVizRender = (mode: 'heatmap' | 'replay'): IHeatmapVizRenderResult => {
10
+ const heatmapResult = useMemo(() => {
11
+ switch (mode) {
12
+ case 'heatmap':
13
+ return useHeatmapRender;
14
+ case 'replay':
15
+ return useReplayRender;
16
+ }
17
+ }, [mode]);
18
+
19
+ return heatmapResult();
20
+ };