@gemx-dev/heatmap-react 3.5.46 → 3.5.48

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 (499) hide show
  1. package/dist/esm/components/Layout/ContentToolbar.d.ts.map +1 -1
  2. package/dist/esm/components/Layout/HeatmapLayout.d.ts +3 -2
  3. package/dist/esm/components/Layout/HeatmapLayout.d.ts.map +1 -1
  4. package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  5. package/dist/esm/components/VizElement/HeatmapElements.d.ts +2 -2
  6. package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
  7. package/dist/esm/components/VizElement/HeatmapExample.d.ts +2 -0
  8. package/dist/esm/components/VizElement/HeatmapExample.d.ts.map +1 -0
  9. package/dist/esm/components/VizElement/VizElements.d.ts.map +1 -1
  10. package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  11. package/dist/esm/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
  12. package/dist/esm/components/VizScrollmap/AverageFoldLine.d.ts +8 -0
  13. package/dist/esm/components/VizScrollmap/AverageFoldLine.d.ts.map +1 -0
  14. package/dist/esm/components/VizScrollmap/HoverZones.d.ts +10 -0
  15. package/dist/esm/components/VizScrollmap/HoverZones.d.ts.map +1 -0
  16. package/dist/esm/components/VizScrollmap/MetricRow.d.ts +1 -0
  17. package/dist/esm/components/VizScrollmap/MetricRow.d.ts.map +1 -0
  18. package/dist/esm/components/VizScrollmap/ScrollMapMinimap.d.ts +8 -0
  19. package/dist/esm/components/VizScrollmap/ScrollMapMinimap.d.ts.map +1 -0
  20. package/dist/esm/components/VizScrollmap/ScrollMapOverlay.d.ts +7 -0
  21. package/dist/esm/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -0
  22. package/dist/esm/components/VizScrollmap/ScrollZoneHoverArea.d.ts +14 -0
  23. package/dist/esm/components/VizScrollmap/ScrollZoneHoverArea.d.ts.map +1 -0
  24. package/dist/esm/components/VizScrollmap/ScrollZoneTooltip.d.ts +10 -0
  25. package/dist/esm/components/VizScrollmap/ScrollZoneTooltip.d.ts.map +1 -0
  26. package/dist/esm/components/VizScrollmap/ScrollmapMarker.d.ts +7 -0
  27. package/dist/esm/components/VizScrollmap/ScrollmapMarker.d.ts.map +1 -0
  28. package/dist/esm/components/VizScrollmap/VizScrollMap.d.ts +7 -0
  29. package/dist/esm/components/VizScrollmap/VizScrollMap.d.ts.map +1 -0
  30. package/{src/components/VizScrollmap/index.ts → dist/esm/components/VizScrollmap/index.d.ts} +1 -0
  31. package/dist/esm/components/VizScrollmap/index.d.ts.map +1 -0
  32. package/dist/esm/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts +5 -0
  33. package/dist/esm/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts.map +1 -0
  34. package/{src/components/VizScrollmapV2/index.ts → dist/esm/components/VizScrollmapV2/index.d.ts} +1 -0
  35. package/dist/esm/components/VizScrollmapV2/index.d.ts.map +1 -0
  36. package/dist/esm/components/VizScrollmapV2/scrollmap.types.d.ts +18 -0
  37. package/dist/esm/components/VizScrollmapV2/scrollmap.types.d.ts.map +1 -0
  38. package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts +16 -0
  39. package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -0
  40. package/dist/esm/configs/style.d.ts +2 -0
  41. package/dist/esm/configs/style.d.ts.map +1 -1
  42. package/dist/esm/helpers/elm-getter.d.ts +2 -2
  43. package/dist/esm/helpers/elm-getter.d.ts.map +1 -1
  44. package/dist/esm/helpers/iframe-helper/fixer.d.ts +18 -0
  45. package/dist/esm/helpers/iframe-helper/fixer.d.ts.map +1 -0
  46. package/dist/esm/helpers/iframe-helper/index.d.ts +2 -0
  47. package/dist/esm/helpers/iframe-helper/index.d.ts.map +1 -0
  48. package/dist/esm/helpers/iframe-helper/init.d.ts +5 -0
  49. package/dist/esm/helpers/iframe-helper/init.d.ts.map +1 -0
  50. package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts +28 -0
  51. package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +1 -0
  52. package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts +20 -0
  53. package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts.map +1 -0
  54. package/dist/esm/helpers/iframe-helper/style-replacer.d.ts +25 -0
  55. package/dist/esm/helpers/iframe-helper/style-replacer.d.ts.map +1 -0
  56. package/dist/esm/helpers/index.d.ts +2 -2
  57. package/dist/esm/helpers/index.d.ts.map +1 -1
  58. package/dist/esm/helpers/viz-canvas/area-clustering.d.ts +44 -0
  59. package/dist/esm/helpers/viz-canvas/area-clustering.d.ts.map +1 -0
  60. package/dist/esm/helpers/viz-canvas/area-overlay-manager-v2.d.ts +17 -0
  61. package/dist/esm/helpers/viz-canvas/area-overlay-manager-v2.d.ts.map +1 -0
  62. package/dist/esm/helpers/viz-canvas/area-overlay-manager.d.ts +51 -0
  63. package/dist/esm/helpers/viz-canvas/area-overlay-manager.d.ts.map +1 -0
  64. package/dist/esm/helpers/viz-canvas/hierarchical-area-clustering.d.ts +73 -0
  65. package/dist/esm/helpers/viz-canvas/hierarchical-area-clustering.d.ts.map +1 -0
  66. package/{src/helpers/viz-canvas/index.ts → dist/esm/helpers/viz-canvas/index.d.ts} +1 -0
  67. package/dist/esm/helpers/viz-canvas/index.d.ts.map +1 -0
  68. package/dist/esm/hooks/index.d.ts +2 -1
  69. package/dist/esm/hooks/index.d.ts.map +1 -1
  70. package/dist/esm/hooks/register/useRegisterData.d.ts +2 -2
  71. package/dist/esm/hooks/register/useRegisterData.d.ts.map +1 -1
  72. package/dist/esm/hooks/register/useRegisterHeatmap.d.ts +7 -2
  73. package/dist/esm/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
  74. package/dist/esm/hooks/viz-area/useAreaHeatmap.d.ts +59 -0
  75. package/dist/esm/hooks/viz-area/useAreaHeatmap.d.ts.map +1 -0
  76. package/dist/esm/hooks/viz-area/useAreaHeatmapManager.d.ts +77 -0
  77. package/dist/esm/hooks/viz-area/useAreaHeatmapManager.d.ts.map +1 -0
  78. package/dist/esm/hooks/viz-canvas/index.d.ts +1 -1
  79. package/dist/esm/hooks/viz-canvas/index.d.ts.map +1 -1
  80. package/dist/esm/hooks/viz-canvas/useAreamap.d.ts +14 -0
  81. package/dist/esm/hooks/viz-canvas/useAreamap.d.ts.map +1 -0
  82. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts +3 -1
  83. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  84. package/dist/esm/hooks/viz-canvas/useHeatmapCanvas.d.ts +4 -0
  85. package/dist/esm/hooks/viz-canvas/useHeatmapCanvas.d.ts.map +1 -0
  86. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts +3 -1
  87. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  88. package/dist/esm/hooks/{vix-elements → viz-elements}/index.d.ts.map +1 -1
  89. package/dist/esm/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts.map +1 -1
  90. package/dist/esm/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts.map +1 -1
  91. package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts.map +1 -1
  92. package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts.map +1 -1
  93. package/dist/esm/hooks/viz-elements/useHeatmapMouseHandler.d.ts +34 -0
  94. package/dist/esm/hooks/viz-elements/useHeatmapMouseHandler.d.ts.map +1 -0
  95. package/dist/esm/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts +4 -0
  96. package/dist/esm/hooks/viz-elements/useHoveredElement.d.ts.map +1 -0
  97. package/dist/esm/hooks/viz-live/index.d.ts +1 -1
  98. package/dist/{umd/hooks/viz-live/useIframeMessage.d.ts → esm/hooks/viz-live/useVizLiveIframeMsg.d.ts} +2 -10
  99. package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -0
  100. package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts +4 -0
  101. package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -0
  102. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  103. package/dist/esm/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
  104. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
  105. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  106. package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +10 -0
  107. package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -0
  108. package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts +4 -0
  109. package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
  110. package/{src/hooks/viz-scrollmap/index.ts → dist/esm/hooks/viz-scrollmap/index.d.ts} +1 -0
  111. package/dist/esm/hooks/viz-scrollmap/index.d.ts.map +1 -0
  112. package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts +29 -0
  113. package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -0
  114. package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts +12 -0
  115. package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -0
  116. package/dist/esm/index.d.ts +1 -1
  117. package/dist/esm/index.d.ts.map +1 -1
  118. package/dist/esm/index.js +1237 -220
  119. package/dist/esm/index.mjs +1237 -220
  120. package/dist/esm/stores/config.d.ts +5 -1
  121. package/dist/esm/stores/config.d.ts.map +1 -1
  122. package/dist/esm/stores/data.d.ts +5 -3
  123. package/dist/esm/stores/data.d.ts.map +1 -1
  124. package/dist/esm/stores/index.d.ts +2 -0
  125. package/dist/esm/stores/index.d.ts.map +1 -1
  126. package/dist/esm/stores/interaction.d.ts.map +1 -1
  127. package/dist/esm/stores/mode-live.d.ts +4 -0
  128. package/dist/esm/stores/mode-live.d.ts.map +1 -1
  129. package/dist/esm/stores/mode-single.d.ts +9 -0
  130. package/dist/esm/stores/mode-single.d.ts.map +1 -0
  131. package/dist/esm/stores/viz-scrollmap.d.ts +11 -0
  132. package/dist/esm/stores/viz-scrollmap.d.ts.map +1 -0
  133. package/dist/esm/stores/viz.d.ts +6 -4
  134. package/dist/esm/stores/viz.d.ts.map +1 -1
  135. package/dist/esm/types/clarity.d.ts +5 -0
  136. package/dist/esm/types/clarity.d.ts.map +1 -1
  137. package/dist/esm/types/heatmap-info.d.ts +11 -0
  138. package/dist/esm/types/heatmap-info.d.ts.map +1 -0
  139. package/dist/esm/types/heatmap.d.ts +13 -0
  140. package/dist/esm/types/heatmap.d.ts.map +1 -1
  141. package/dist/esm/types/iframe-helper.d.ts +20 -0
  142. package/dist/esm/types/iframe-helper.d.ts.map +1 -0
  143. package/dist/esm/types/index.d.ts +4 -1
  144. package/dist/esm/types/index.d.ts.map +1 -1
  145. package/dist/esm/types/viz-canvas.d.ts +23 -0
  146. package/dist/esm/types/viz-canvas.d.ts.map +1 -0
  147. package/dist/esm/types/viz-element.d.ts +0 -6
  148. package/dist/esm/types/viz-element.d.ts.map +1 -1
  149. package/dist/esm/types/viz-scrollmap.d.ts +27 -0
  150. package/dist/esm/types/viz-scrollmap.d.ts.map +1 -0
  151. package/dist/umd/components/Layout/ContentToolbar.d.ts.map +1 -1
  152. package/dist/umd/components/Layout/HeatmapLayout.d.ts +3 -2
  153. package/dist/umd/components/Layout/HeatmapLayout.d.ts.map +1 -1
  154. package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  155. package/dist/umd/components/VizElement/HeatmapElements.d.ts +2 -2
  156. package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
  157. package/dist/umd/components/VizElement/HeatmapExample.d.ts +2 -0
  158. package/dist/umd/components/VizElement/HeatmapExample.d.ts.map +1 -0
  159. package/dist/umd/components/VizElement/VizElements.d.ts.map +1 -1
  160. package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  161. package/dist/umd/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
  162. package/dist/umd/components/VizScrollmap/AverageFoldLine.d.ts +8 -0
  163. package/dist/umd/components/VizScrollmap/AverageFoldLine.d.ts.map +1 -0
  164. package/dist/umd/components/VizScrollmap/HoverZones.d.ts +10 -0
  165. package/dist/umd/components/VizScrollmap/HoverZones.d.ts.map +1 -0
  166. package/dist/umd/components/VizScrollmap/MetricRow.d.ts +1 -0
  167. package/dist/umd/components/VizScrollmap/MetricRow.d.ts.map +1 -0
  168. package/dist/umd/components/VizScrollmap/ScrollMapMinimap.d.ts +8 -0
  169. package/dist/umd/components/VizScrollmap/ScrollMapMinimap.d.ts.map +1 -0
  170. package/dist/umd/components/VizScrollmap/ScrollMapOverlay.d.ts +7 -0
  171. package/dist/umd/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -0
  172. package/dist/umd/components/VizScrollmap/ScrollZoneHoverArea.d.ts +14 -0
  173. package/dist/umd/components/VizScrollmap/ScrollZoneHoverArea.d.ts.map +1 -0
  174. package/dist/umd/components/VizScrollmap/ScrollZoneTooltip.d.ts +10 -0
  175. package/dist/umd/components/VizScrollmap/ScrollZoneTooltip.d.ts.map +1 -0
  176. package/dist/umd/components/VizScrollmap/ScrollmapMarker.d.ts +7 -0
  177. package/dist/umd/components/VizScrollmap/ScrollmapMarker.d.ts.map +1 -0
  178. package/dist/umd/components/VizScrollmap/VizScrollMap.d.ts +7 -0
  179. package/dist/umd/components/VizScrollmap/VizScrollMap.d.ts.map +1 -0
  180. package/dist/umd/components/VizScrollmap/index.d.ts +2 -0
  181. package/dist/umd/components/VizScrollmap/index.d.ts.map +1 -0
  182. package/dist/umd/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts +5 -0
  183. package/dist/umd/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts.map +1 -0
  184. package/dist/umd/components/VizScrollmapV2/index.d.ts +2 -0
  185. package/dist/umd/components/VizScrollmapV2/index.d.ts.map +1 -0
  186. package/dist/umd/components/VizScrollmapV2/scrollmap.types.d.ts +18 -0
  187. package/dist/umd/components/VizScrollmapV2/scrollmap.types.d.ts.map +1 -0
  188. package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts +16 -0
  189. package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -0
  190. package/dist/umd/configs/style.d.ts +2 -0
  191. package/dist/umd/configs/style.d.ts.map +1 -1
  192. package/dist/umd/helpers/elm-getter.d.ts +2 -2
  193. package/dist/umd/helpers/elm-getter.d.ts.map +1 -1
  194. package/dist/umd/helpers/iframe-helper/fixer.d.ts +18 -0
  195. package/dist/umd/helpers/iframe-helper/fixer.d.ts.map +1 -0
  196. package/dist/umd/helpers/iframe-helper/index.d.ts +2 -0
  197. package/dist/umd/helpers/iframe-helper/index.d.ts.map +1 -0
  198. package/dist/umd/helpers/iframe-helper/init.d.ts +5 -0
  199. package/dist/umd/helpers/iframe-helper/init.d.ts.map +1 -0
  200. package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts +28 -0
  201. package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +1 -0
  202. package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts +20 -0
  203. package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts.map +1 -0
  204. package/dist/umd/helpers/iframe-helper/style-replacer.d.ts +25 -0
  205. package/dist/umd/helpers/iframe-helper/style-replacer.d.ts.map +1 -0
  206. package/dist/umd/helpers/index.d.ts +2 -2
  207. package/dist/umd/helpers/index.d.ts.map +1 -1
  208. package/dist/umd/helpers/viz-canvas/area-clustering.d.ts +44 -0
  209. package/dist/umd/helpers/viz-canvas/area-clustering.d.ts.map +1 -0
  210. package/dist/umd/helpers/viz-canvas/area-overlay-manager-v2.d.ts +17 -0
  211. package/dist/umd/helpers/viz-canvas/area-overlay-manager-v2.d.ts.map +1 -0
  212. package/dist/umd/helpers/viz-canvas/area-overlay-manager.d.ts +51 -0
  213. package/dist/umd/helpers/viz-canvas/area-overlay-manager.d.ts.map +1 -0
  214. package/dist/umd/helpers/viz-canvas/hierarchical-area-clustering.d.ts +73 -0
  215. package/dist/umd/helpers/viz-canvas/hierarchical-area-clustering.d.ts.map +1 -0
  216. package/dist/umd/helpers/viz-canvas/index.d.ts +3 -0
  217. package/dist/umd/helpers/viz-canvas/index.d.ts.map +1 -0
  218. package/dist/umd/hooks/index.d.ts +2 -1
  219. package/dist/umd/hooks/index.d.ts.map +1 -1
  220. package/dist/umd/hooks/register/useRegisterData.d.ts +2 -2
  221. package/dist/umd/hooks/register/useRegisterData.d.ts.map +1 -1
  222. package/dist/umd/hooks/register/useRegisterHeatmap.d.ts +7 -2
  223. package/dist/umd/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
  224. package/dist/umd/hooks/viz-area/useAreaHeatmap.d.ts +59 -0
  225. package/dist/umd/hooks/viz-area/useAreaHeatmap.d.ts.map +1 -0
  226. package/dist/umd/hooks/viz-area/useAreaHeatmapManager.d.ts +77 -0
  227. package/dist/umd/hooks/viz-area/useAreaHeatmapManager.d.ts.map +1 -0
  228. package/dist/umd/hooks/viz-canvas/index.d.ts +1 -1
  229. package/dist/umd/hooks/viz-canvas/index.d.ts.map +1 -1
  230. package/dist/umd/hooks/viz-canvas/useAreamap.d.ts +14 -0
  231. package/dist/umd/hooks/viz-canvas/useAreamap.d.ts.map +1 -0
  232. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts +3 -1
  233. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  234. package/dist/umd/hooks/viz-canvas/useHeatmapCanvas.d.ts +4 -0
  235. package/dist/umd/hooks/viz-canvas/useHeatmapCanvas.d.ts.map +1 -0
  236. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts +3 -1
  237. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  238. package/dist/umd/hooks/{vix-elements → viz-elements}/index.d.ts.map +1 -1
  239. package/dist/umd/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts.map +1 -1
  240. package/dist/umd/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts.map +1 -1
  241. package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts.map +1 -1
  242. package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts.map +1 -1
  243. package/dist/umd/hooks/viz-elements/useHeatmapMouseHandler.d.ts +34 -0
  244. package/dist/umd/hooks/viz-elements/useHeatmapMouseHandler.d.ts.map +1 -0
  245. package/dist/umd/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts +4 -0
  246. package/dist/umd/hooks/viz-elements/useHoveredElement.d.ts.map +1 -0
  247. package/dist/umd/hooks/viz-live/index.d.ts +1 -1
  248. package/dist/{esm/hooks/viz-live/useIframeMessage.d.ts → umd/hooks/viz-live/useVizLiveIframeMsg.d.ts} +2 -10
  249. package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -0
  250. package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts +4 -0
  251. package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -0
  252. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  253. package/dist/umd/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
  254. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
  255. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  256. package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +10 -0
  257. package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -0
  258. package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts +4 -0
  259. package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
  260. package/dist/umd/hooks/viz-scrollmap/index.d.ts +3 -0
  261. package/dist/umd/hooks/viz-scrollmap/index.d.ts.map +1 -0
  262. package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts +29 -0
  263. package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -0
  264. package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts +12 -0
  265. package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -0
  266. package/dist/umd/index.d.ts +1 -1
  267. package/dist/umd/index.d.ts.map +1 -1
  268. package/dist/umd/index.js +2 -2
  269. package/dist/umd/stores/config.d.ts +5 -1
  270. package/dist/umd/stores/config.d.ts.map +1 -1
  271. package/dist/umd/stores/data.d.ts +5 -3
  272. package/dist/umd/stores/data.d.ts.map +1 -1
  273. package/dist/umd/stores/index.d.ts +2 -0
  274. package/dist/umd/stores/index.d.ts.map +1 -1
  275. package/dist/umd/stores/interaction.d.ts.map +1 -1
  276. package/dist/umd/stores/mode-live.d.ts +4 -0
  277. package/dist/umd/stores/mode-live.d.ts.map +1 -1
  278. package/dist/umd/stores/mode-single.d.ts +9 -0
  279. package/dist/umd/stores/mode-single.d.ts.map +1 -0
  280. package/dist/umd/stores/viz-scrollmap.d.ts +11 -0
  281. package/dist/umd/stores/viz-scrollmap.d.ts.map +1 -0
  282. package/dist/umd/stores/viz.d.ts +6 -4
  283. package/dist/umd/stores/viz.d.ts.map +1 -1
  284. package/dist/umd/types/clarity.d.ts +5 -0
  285. package/dist/umd/types/clarity.d.ts.map +1 -1
  286. package/dist/umd/types/heatmap-info.d.ts +11 -0
  287. package/dist/umd/types/heatmap-info.d.ts.map +1 -0
  288. package/dist/umd/types/heatmap.d.ts +13 -0
  289. package/dist/umd/types/heatmap.d.ts.map +1 -1
  290. package/dist/umd/types/iframe-helper.d.ts +20 -0
  291. package/dist/umd/types/iframe-helper.d.ts.map +1 -0
  292. package/dist/umd/types/index.d.ts +4 -1
  293. package/dist/umd/types/index.d.ts.map +1 -1
  294. package/dist/umd/types/viz-canvas.d.ts +23 -0
  295. package/dist/umd/types/viz-canvas.d.ts.map +1 -0
  296. package/dist/umd/types/viz-element.d.ts +0 -6
  297. package/dist/umd/types/viz-element.d.ts.map +1 -1
  298. package/dist/umd/types/viz-scrollmap.d.ts +27 -0
  299. package/dist/umd/types/viz-scrollmap.d.ts.map +1 -0
  300. package/package.json +14 -11
  301. package/dist/esm/components/Layout/ContentHeader.d.ts +0 -4
  302. package/dist/esm/components/Layout/ContentHeader.d.ts.map +0 -1
  303. package/dist/esm/components/Layout/VizMode.d.ts +0 -2
  304. package/dist/esm/components/Layout/VizMode.d.ts.map +0 -1
  305. package/dist/esm/components/Test.d.ts +0 -121
  306. package/dist/esm/components/Test.d.ts.map +0 -1
  307. package/dist/esm/components/VizDom/VizDomContainer.d.ts +0 -6
  308. package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +0 -1
  309. package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts +0 -17
  310. package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts.map +0 -1
  311. package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts +0 -12
  312. package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts.map +0 -1
  313. package/dist/esm/components/VizElement/MissingElementMessage.d.ts +0 -7
  314. package/dist/esm/components/VizElement/MissingElementMessage.d.ts.map +0 -1
  315. package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts +0 -150
  316. package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts.map +0 -1
  317. package/dist/esm/components/VizElement/temp/VizElementRank.d.ts +0 -74
  318. package/dist/esm/components/VizElement/temp/VizElementRank.d.ts.map +0 -1
  319. package/dist/esm/components/VizLive/VizLive.d.ts +0 -2
  320. package/dist/esm/components/VizLive/VizLive.d.ts.map +0 -1
  321. package/dist/esm/helpers/viewport-fixer.d.ts +0 -13
  322. package/dist/esm/helpers/viewport-fixer.d.ts.map +0 -1
  323. package/dist/esm/helpers/viewport-replacer.d.ts +0 -26
  324. package/dist/esm/helpers/viewport-replacer.d.ts.map +0 -1
  325. package/dist/esm/hooks/vix-elements/useHoveredElement.d.ts.map +0 -1
  326. package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +0 -2
  327. package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +0 -1
  328. package/dist/esm/hooks/viz-live/useIframeMessage.d.ts.map +0 -1
  329. package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +0 -10
  330. package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts.map +0 -1
  331. package/dist/esm/types/viewport-fixer.d.ts +0 -31
  332. package/dist/esm/types/viewport-fixer.d.ts.map +0 -1
  333. package/dist/umd/components/Layout/ContentHeader.d.ts +0 -4
  334. package/dist/umd/components/Layout/ContentHeader.d.ts.map +0 -1
  335. package/dist/umd/components/Test.d.ts +0 -121
  336. package/dist/umd/components/Test.d.ts.map +0 -1
  337. package/dist/umd/components/VizDom/VizDomContainer.d.ts +0 -2
  338. package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +0 -1
  339. package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts +0 -17
  340. package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts.map +0 -1
  341. package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts +0 -12
  342. package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts.map +0 -1
  343. package/dist/umd/components/VizElement/MissingElementMessage.d.ts +0 -7
  344. package/dist/umd/components/VizElement/MissingElementMessage.d.ts.map +0 -1
  345. package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts +0 -150
  346. package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts.map +0 -1
  347. package/dist/umd/components/VizElement/temp/VizElementRank.d.ts +0 -74
  348. package/dist/umd/components/VizElement/temp/VizElementRank.d.ts.map +0 -1
  349. package/dist/umd/helpers/viewport-fixer.d.ts +0 -13
  350. package/dist/umd/helpers/viewport-fixer.d.ts.map +0 -1
  351. package/dist/umd/helpers/viewport-replacer.d.ts +0 -26
  352. package/dist/umd/helpers/viewport-replacer.d.ts.map +0 -1
  353. package/dist/umd/hooks/vix-elements/useHoveredElement.d.ts.map +0 -1
  354. package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +0 -2
  355. package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +0 -1
  356. package/dist/umd/hooks/viz-live/useIframeMessage.d.ts.map +0 -1
  357. package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +0 -10
  358. package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts.map +0 -1
  359. package/dist/umd/types/viewport-fixer.d.ts +0 -31
  360. package/dist/umd/types/viewport-fixer.d.ts.map +0 -1
  361. package/src/components/GraphView.tsx +0 -58
  362. package/src/components/Layout/ContentMetricBar.tsx +0 -23
  363. package/src/components/Layout/ContentToolbar.tsx +0 -22
  364. package/src/components/Layout/ContentTopBar.tsx +0 -24
  365. package/src/components/Layout/ContentVizByMode.tsx +0 -14
  366. package/src/components/Layout/HeatmapLayout.tsx +0 -60
  367. package/src/components/Layout/LeftSidebar.tsx +0 -44
  368. package/src/components/Layout/WrapperLayout.tsx +0 -12
  369. package/src/components/Layout/WrapperPreview.tsx +0 -24
  370. package/src/components/Layout/index.ts +0 -1
  371. package/src/components/VizDom/ReplayControls.tsx +0 -48
  372. package/src/components/VizDom/VizContainer.tsx +0 -40
  373. package/src/components/VizDom/VizDomHeatmap.tsx +0 -28
  374. package/src/components/VizDom/VizDomRenderer.tsx +0 -82
  375. package/src/components/VizDom/VizLoading.tsx +0 -8
  376. package/src/components/VizDom/WrapperVisual.tsx +0 -73
  377. package/src/components/VizDom/index.ts +0 -5
  378. package/src/components/VizElement/DefaultRankBadges.tsx +0 -36
  379. package/src/components/VizElement/ElementCallout.tsx +0 -82
  380. package/src/components/VizElement/ElementMissing.tsx +0 -35
  381. package/src/components/VizElement/ElementOverlay.tsx +0 -66
  382. package/src/components/VizElement/HeatmapElements.tsx +0 -127
  383. package/src/components/VizElement/HeatmapExample.tsx +0 -70
  384. package/src/components/VizElement/RankBadge.tsx +0 -25
  385. package/src/components/VizElement/VizElements.tsx +0 -57
  386. package/src/components/VizElement/index.ts +0 -1
  387. package/src/components/VizLive/VizLiveHeatmap.tsx +0 -27
  388. package/src/components/VizLive/VizLiveRenderer.tsx +0 -47
  389. package/src/components/VizLive/index.ts +0 -1
  390. package/src/components/VizScrollmap/AverageFoldLine.tsx +0 -57
  391. package/src/components/VizScrollmap/HoverZones.tsx +0 -58
  392. package/src/components/VizScrollmap/MetricRow.tsx +0 -0
  393. package/src/components/VizScrollmap/ScrollMapMinimap.tsx +0 -64
  394. package/src/components/VizScrollmap/ScrollMapOverlay.tsx +0 -79
  395. package/src/components/VizScrollmap/ScrollZoneHoverArea.tsx +0 -35
  396. package/src/components/VizScrollmap/ScrollZoneTooltip.tsx +0 -146
  397. package/src/components/VizScrollmap/ScrollmapMarker.tsx +0 -106
  398. package/src/components/VizScrollmap/VizScrollMap.tsx +0 -36
  399. package/src/components/VizScrollmapV2/ScrollmapOverlay.css +0 -94
  400. package/src/components/VizScrollmapV2/ScrollmapOverlayV2.tsx +0 -130
  401. package/src/components/VizScrollmapV2/scrollmap.types.ts +0 -21
  402. package/src/components/VizScrollmapV2/useScrollmapOverlay.ts +0 -187
  403. package/src/components/index.tsx +0 -2
  404. package/src/configs/iframe.ts +0 -15
  405. package/src/configs/index.ts +0 -2
  406. package/src/configs/style.ts +0 -21
  407. package/src/constants/index.ts +0 -4
  408. package/src/global.d.ts +0 -5
  409. package/src/helpers/elm-callout.ts +0 -347
  410. package/src/helpers/elm-getter.ts +0 -70
  411. package/src/helpers/iframe-helper/fixer.ts +0 -100
  412. package/src/helpers/iframe-helper/index.ts +0 -1
  413. package/src/helpers/iframe-helper/init.ts +0 -56
  414. package/src/helpers/iframe-helper/navigation-blocker-v2.ts +0 -371
  415. package/src/helpers/iframe-helper/navigation-blocker.ts +0 -367
  416. package/src/helpers/iframe-helper/style-replacer.ts +0 -231
  417. package/src/helpers/iframe.ts +0 -42
  418. package/src/helpers/index.ts +0 -8
  419. package/src/helpers/viz-canvas/area-clustering.ts +0 -234
  420. package/src/helpers/viz-canvas/area-overlay-manager-v2.ts +0 -176
  421. package/src/helpers/viz-canvas/area-overlay-manager.ts +0 -273
  422. package/src/helpers/viz-canvas/hierarchical-area-clustering.ts +0 -420
  423. package/src/helpers/viz-elements.ts +0 -43
  424. package/src/hooks/index.ts +0 -8
  425. package/src/hooks/register/index.ts +0 -4
  426. package/src/hooks/register/useRegisterConfig.ts +0 -17
  427. package/src/hooks/register/useRegisterControl.ts +0 -13
  428. package/src/hooks/register/useRegisterData.ts +0 -36
  429. package/src/hooks/register/useRegisterHeatmap.ts +0 -38
  430. package/src/hooks/viz-area/useAreaHeatmap.ts +0 -336
  431. package/src/hooks/viz-area/useAreaHeatmapManager.ts +0 -692
  432. package/src/hooks/viz-canvas/index.ts +0 -1
  433. package/src/hooks/viz-canvas/useAreamap.ts +0 -162
  434. package/src/hooks/viz-canvas/useClickmap.ts +0 -24
  435. package/src/hooks/viz-canvas/useHeatmapCanvas.ts +0 -27
  436. package/src/hooks/viz-canvas/useScrollmap.ts +0 -22
  437. package/src/hooks/viz-elements/index.ts +0 -5
  438. package/src/hooks/viz-elements/useClickedElement.ts +0 -86
  439. package/src/hooks/viz-elements/useElementCalloutVisible.ts +0 -45
  440. package/src/hooks/viz-elements/useHeatmapEffects.ts +0 -30
  441. package/src/hooks/viz-elements/useHeatmapElementPosition.ts +0 -60
  442. package/src/hooks/viz-elements/useHeatmapMouseHandler.ts +0 -255
  443. package/src/hooks/viz-elements/useHoveredElement.ts +0 -170
  444. package/src/hooks/viz-live/index.ts +0 -1
  445. package/src/hooks/viz-live/useVizLiveIframeMsg.ts +0 -88
  446. package/src/hooks/viz-live/useVizLiveRender.ts +0 -67
  447. package/src/hooks/viz-render/index.ts +0 -1
  448. package/src/hooks/viz-render/useHeatmapRender.ts +0 -71
  449. package/src/hooks/viz-render/useHeatmapVizRender.ts +0 -20
  450. package/src/hooks/viz-render/useReplayRender.ts +0 -160
  451. package/src/hooks/viz-scale/index.ts +0 -2
  452. package/src/hooks/viz-scale/useContainerDimensions.ts +0 -48
  453. package/src/hooks/viz-scale/useContentDimensions.ts +0 -25
  454. package/src/hooks/viz-scale/useHeatmapScale.ts +0 -52
  455. package/src/hooks/viz-scale/useObserveIframeHeight.ts +0 -162
  456. package/src/hooks/viz-scale/useScaleCalculation.ts +0 -31
  457. package/src/hooks/viz-scale/useScrollSync.ts +0 -36
  458. package/src/hooks/viz-scale/useWrapperRefHeight.ts +0 -91
  459. package/src/hooks/viz-scrollmap/useScrollmapZones.ts +0 -165
  460. package/src/hooks/viz-scrollmap/useZonePositions.ts +0 -38
  461. package/src/index.ts +0 -10
  462. package/src/stores/comp.ts +0 -31
  463. package/src/stores/config.ts +0 -37
  464. package/src/stores/data.ts +0 -30
  465. package/src/stores/index.ts +0 -10
  466. package/src/stores/interaction.ts +0 -32
  467. package/src/stores/mode-live.ts +0 -38
  468. package/src/stores/mode-single.ts +0 -18
  469. package/src/stores/viz-scrollmap.ts +0 -22
  470. package/src/stores/viz.ts +0 -17
  471. package/src/styles/base.css +0 -1
  472. package/src/styles/style.css +0 -137
  473. package/src/types/clarity.ts +0 -45
  474. package/src/types/control.ts +0 -10
  475. package/src/types/elm-callout.ts +0 -9
  476. package/src/types/heatmap-info.ts +0 -11
  477. package/src/types/heatmap.ts +0 -25
  478. package/src/types/iframe-helper.ts +0 -18
  479. package/src/types/index.ts +0 -12
  480. package/src/types/viz-canvas.ts +0 -20
  481. package/src/types/viz-element.ts +0 -34
  482. package/src/types/viz-scrollmap.ts +0 -28
  483. package/src/ui/BoxStack/BoxStack.tsx +0 -136
  484. package/src/ui/BoxStack/index.ts +0 -1
  485. package/src/ui/index.ts +0 -1
  486. package/src/utils/debounce.ts +0 -10
  487. package/src/utils/device.ts +0 -7
  488. package/src/utils/retry.ts +0 -20
  489. package/src/utils/sort.ts +0 -5
  490. /package/dist/esm/hooks/{vix-elements → viz-elements}/index.d.ts +0 -0
  491. /package/dist/esm/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts +0 -0
  492. /package/dist/esm/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts +0 -0
  493. /package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts +0 -0
  494. /package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts +0 -0
  495. /package/dist/umd/hooks/{vix-elements → viz-elements}/index.d.ts +0 -0
  496. /package/dist/umd/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts +0 -0
  497. /package/dist/umd/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts +0 -0
  498. /package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts +0 -0
  499. /package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts +0 -0
@@ -61,6 +61,8 @@ const HEATMAP_STYLE = {
61
61
  },
62
62
  wrapper: {
63
63
  padding: `${HEATMAP_CONFIG.padding}px 0`,
64
+ paddingBlock: `${HEATMAP_CONFIG.padding}px`,
65
+ paddingInline: `${HEATMAP_CONFIG.padding}px`,
64
66
  },
65
67
  };
66
68
  const DEFAULT_SIDEBAR_WIDTH = 260;
@@ -91,18 +93,37 @@ var IHeatmapType;
91
93
  IHeatmapType["Click"] = "click";
92
94
  IHeatmapType["Scroll"] = "scroll";
93
95
  })(IHeatmapType || (IHeatmapType = {}));
96
+ var IClickType;
97
+ (function (IClickType) {
98
+ IClickType["Total"] = "total-clicks";
99
+ IClickType["Rage"] = "rage-clicks";
100
+ IClickType["Dead"] = "dead-clicks";
101
+ IClickType["Error"] = "error-clicks";
102
+ IClickType["First"] = "first-clicks";
103
+ IClickType["Last"] = "last-clicks";
104
+ })(IClickType || (IClickType = {}));
105
+ var IScrollType;
106
+ (function (IScrollType) {
107
+ IScrollType["Depth"] = "scroll-depth";
108
+ IScrollType["Attention"] = "attention-scroll";
109
+ IScrollType["Revenue"] = "revenue-scroll";
110
+ })(IScrollType || (IScrollType = {}));
94
111
 
95
112
  const useHeatmapConfigStore = create()((set, get) => {
96
113
  return {
97
114
  mode: 'single',
98
115
  width: 1440,
99
116
  sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
100
- heatmapType: IHeatmapType.Click,
117
+ heatmapType: IHeatmapType.Scroll,
118
+ clickType: IClickType.Total,
119
+ scrollType: IScrollType.Depth,
101
120
  setMode: (mode) => set({ mode }),
102
121
  resetMode: () => set({ mode: 'single' }),
103
122
  setWidth: (width) => set({ width }),
104
123
  setSidebarWidth: (sidebarWidth) => set({ sidebarWidth }),
105
124
  setHeatmapType: (heatmapType) => set({ heatmapType }),
125
+ setClickType: (clickType) => set({ clickType }),
126
+ setScrollType: (scrollType) => set({ scrollType }),
106
127
  };
107
128
  });
108
129
 
@@ -111,11 +132,13 @@ const useHeatmapDataStore = create()((set, get) => {
111
132
  data: undefined,
112
133
  clickmap: undefined,
113
134
  dataInfo: undefined,
135
+ scrollmap: undefined,
114
136
  isRendering: true,
115
137
  setIsRendering: (isRendering) => set({ isRendering }),
116
138
  setDataInfo: (dataInfo) => set({ dataInfo }),
117
139
  setData: (data) => set({ data }),
118
140
  setClickmap: (clickmap) => set({ clickmap }),
141
+ setScrollmap: (scrollmap) => set({ scrollmap }),
119
142
  };
120
143
  });
121
144
 
@@ -138,16 +161,30 @@ const useHeatmapVizStore = create()((set, get) => {
138
161
  return {
139
162
  isRenderViz: false,
140
163
  setIsRenderViz: (isRenderViz) => set({ isRenderViz }),
164
+ zoomRatio: 100,
165
+ minZoomRatio: 10,
166
+ setMinZoomRatio: (minZoomRatio) => set({ minZoomRatio }),
167
+ setZoomRatio: (zoomRatio) => set({ zoomRatio }),
141
168
  scale: 1,
142
- vizRef: undefined,
143
- iframeHeight: 0,
144
169
  setScale: (scale) => set({ scale }),
145
- setVizRef: (vizRef) => set({ vizRef }),
146
- setIframeHeight: (iframeHeight) => set({ iframeHeight }),
170
+ isScaledToFit: false,
171
+ setIsScaledToFit: (isScaledToFit) => set({ isScaledToFit }),
172
+ };
173
+ });
174
+
175
+ const useHeatmapVizScrollmapStore = create()((set, get) => {
176
+ return {
177
+ zones: [],
178
+ hoveredZone: null,
179
+ showMinimap: true,
180
+ setZones: (zones) => set({ zones }),
181
+ setHoveredZone: (hoveredZone) => set({ hoveredZone }),
182
+ setShowMinimap: (showMinimap) => set({ showMinimap }),
147
183
  };
148
184
  });
149
185
 
150
186
  const initialState = {
187
+ payloads: [],
151
188
  htmlContent: '',
152
189
  wrapperHeight: 0,
153
190
  iframeHeight: 0,
@@ -156,12 +193,23 @@ const useHeatmapLiveStore = create()((set, get) => {
156
193
  return {
157
194
  ...initialState,
158
195
  reset: () => set(initialState),
196
+ setPayloads: (payloads) => set({ payloads }),
197
+ addPayload: (payload) => set((state) => ({ payloads: [...state.payloads, payload] })),
159
198
  setHtmlContent: (htmlContent) => set({ htmlContent }),
160
199
  setWrapperHeight: (wrapperHeight) => set({ wrapperHeight }),
161
200
  setIframeHeight: (iframeHeight) => set({ iframeHeight }),
162
201
  };
163
202
  });
164
203
 
204
+ const useHeatmapSingleStore = create()((set, get) => {
205
+ return {
206
+ vizRef: null,
207
+ iframeHeight: 0,
208
+ setVizRef: (vizRef) => set({ vizRef }),
209
+ setIframeHeight: (iframeHeight) => set({ iframeHeight }),
210
+ };
211
+ });
212
+
165
213
  const useRegisterConfig = () => {
166
214
  const mode = useHeatmapConfigStore((state) => state.mode);
167
215
  const width = useHeatmapConfigStore((state) => state.width);
@@ -209,16 +257,25 @@ const useRegisterData = (data, dataInfo) => {
209
257
  }, [dataInfo]);
210
258
  };
211
259
 
212
- const useRegisterHeatmap = (clickmap) => {
260
+ const useRegisterHeatmap = ({ clickmap, scrollmap }) => {
213
261
  const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
262
+ const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
214
263
  const handleSetClickmap = useCallback((clickmap) => {
215
264
  if (!clickmap)
216
265
  return;
217
266
  setClickmap(clickmap);
218
267
  }, [clickmap]);
268
+ const handleSetScrollmap = useCallback((scrollmap) => {
269
+ if (!scrollmap)
270
+ return;
271
+ setScrollmap(scrollmap);
272
+ }, [scrollmap]);
219
273
  useEffect(() => {
220
274
  handleSetClickmap(clickmap);
221
275
  }, [clickmap]);
276
+ useEffect(() => {
277
+ handleSetScrollmap(scrollmap);
278
+ }, [scrollmap]);
222
279
  };
223
280
 
224
281
  const PADDING = 0;
@@ -501,91 +558,311 @@ function isElementInViewport(elementRect, visualRef, scale) {
501
558
  return elementBottom > viewportTop && elementTop < viewportBottom;
502
559
  }
503
560
 
504
- const getScriptInjectCode = async () => {
505
- const moduleResult = (await Promise.resolve().then(function () { return viewportReplacer; }));
506
- const ActualClass = moduleResult.default;
507
- const classCode = ActualClass.toString();
508
- const classInstantiateCode = ActualClass.name;
509
- const scriptCode = `
510
- (function() {
511
- 'use strict';
512
- ${classCode}
513
- new ${classInstantiateCode}()
514
- })();
515
- `;
516
- return scriptCode;
517
- };
518
- class ViewportUnitsFixer {
519
- iframe = null;
520
- config;
521
- constructor(config) {
522
- this.config = config;
523
- this.iframe = config.iframe;
561
+ class IframeNavigationBlockerV2 {
562
+ doc;
563
+ win;
564
+ isEnabled = false;
565
+ showMessage = false;
566
+ originalWindowOpen;
567
+ observers = [];
568
+ constructor(iframe) {
569
+ if (!iframe.contentDocument || !iframe.contentWindow) {
570
+ throw new Error('Iframe document or window not accessible');
571
+ }
572
+ this.doc = iframe.contentDocument;
573
+ this.win = iframe.contentWindow;
574
+ this.originalWindowOpen = this.win.open.bind(this.win);
524
575
  this.init();
525
576
  }
526
- async init() {
527
- if (!this.iframe) {
528
- console.error('[Parent] Required elements not found');
529
- return;
530
- }
531
- // this.injectScriptContent = await generateIframeInjectScript();
532
- window.addEventListener('message', this.handleMessage.bind(this));
533
- if (this.iframe.contentDocument?.readyState === 'complete') {
534
- await this.injectScript();
577
+ init() {
578
+ console.log('[NavigationBlocker] Initializing...');
579
+ try {
580
+ // Chặn navigation qua links
581
+ this.blockLinkNavigation();
582
+ // Chặn form submissions
583
+ this.blockFormSubmissions();
584
+ // Chặn window.open (này an toàn)
585
+ this.blockWindowOpen();
586
+ // Chặn beforeunload để prevent navigation
587
+ this.blockBeforeUnload();
588
+ // Monitor DOM changes để block dynamic links
589
+ this.monitorDOMChanges();
590
+ // Inject CSP nếu có thể
591
+ this.injectCSP();
535
592
  }
536
- else {
537
- this.iframe.addEventListener('load', () => this.injectScript());
593
+ catch (error) {
594
+ console.error('[NavigationBlocker] Init error:', error);
538
595
  }
539
596
  }
540
- async injectScript() {
541
- if (!this.iframe?.contentWindow || !this.iframe.contentDocument)
542
- return;
543
- const win = this.iframe.contentWindow;
544
- const doc = this.iframe.contentDocument;
545
- win.__viewportConfig = this.config;
546
- const script = doc.createElement('script');
547
- const codeInject = await getScriptInjectCode();
548
- script.textContent = codeInject;
549
- script.type = 'text/javascript';
550
- script.id = 'viewport-replacer';
551
- script.onload = () => console.log('[Parent] Viewport replacer module loaded');
552
- script.onerror = () => {
553
- this.config.onSuccess?.({
554
- height: 1000,
597
+ blockLinkNavigation() {
598
+ // Sử dụng capture phase để chặn sớm nhất
599
+ this.doc.addEventListener('click', (e) => {
600
+ if (!this.isEnabled)
601
+ return;
602
+ const target = e.target;
603
+ const link = target.closest('a');
604
+ if (link) {
605
+ const href = link.getAttribute('href');
606
+ // Cho phép hash links và empty links
607
+ if (!href || href === '' || href === '#' || href.startsWith('#')) {
608
+ console.log('[NavigationBlocker] Allowed hash navigation:', href);
609
+ return;
610
+ }
611
+ // Chặn tất cả các loại navigation
612
+ console.log('[NavigationBlocker] Blocked link navigation to:', href);
613
+ e.preventDefault();
614
+ e.stopPropagation();
615
+ e.stopImmediatePropagation();
616
+ this.notifyBlockedNavigation(href);
617
+ }
618
+ }, true);
619
+ // Chặn cả middle click và right click "open in new tab"
620
+ this.doc.addEventListener('auxclick', (e) => {
621
+ if (!this.isEnabled)
622
+ return;
623
+ const target = e.target;
624
+ const link = target.closest('a');
625
+ if (link) {
626
+ const href = link.getAttribute('href');
627
+ if (href && !href.startsWith('#')) {
628
+ console.log('[NavigationBlocker] Blocked auxclick navigation');
629
+ e.preventDefault();
630
+ e.stopPropagation();
631
+ e.stopImmediatePropagation();
632
+ }
633
+ }
634
+ }, true);
635
+ // Disable tất cả links ngay từ đầu
636
+ this.disableAllLinks();
637
+ }
638
+ disableAllLinks() {
639
+ this.doc.querySelectorAll('a[href]').forEach((link) => {
640
+ const href = link.getAttribute('href');
641
+ if (href && !href.startsWith('#')) {
642
+ // Thêm pointer-events: none và cursor
643
+ link.style.cursor = 'not-allowed';
644
+ link.setAttribute('data-navigation-blocked', 'true');
645
+ // Remove href để browser không hiện preview
646
+ link.setAttribute('data-original-href', href);
647
+ link.removeAttribute('href');
648
+ // Hoặc giữ href nhưng disable
649
+ // link.setAttribute('onclick', 'return false');
650
+ }
651
+ });
652
+ }
653
+ blockFormSubmissions() {
654
+ this.doc.addEventListener('submit', (e) => {
655
+ if (!this.isEnabled)
656
+ return;
657
+ const form = e.target;
658
+ const action = form.getAttribute('action');
659
+ // Cho phép forms không có action
660
+ if (!action || action === '' || action === '#') {
661
+ console.log('[NavigationBlocker] Allowed same-page form');
662
+ e.preventDefault();
663
+ this.handleFormSubmit(form);
664
+ return;
665
+ }
666
+ // Chặn tất cả external submissions
667
+ console.log('[NavigationBlocker] Blocked form submission to:', action);
668
+ e.preventDefault();
669
+ e.stopPropagation();
670
+ e.stopImmediatePropagation();
671
+ this.notifyBlockedNavigation(action);
672
+ }, true);
673
+ }
674
+ blockWindowOpen() {
675
+ // Override window.open - đây là safe
676
+ this.win.open = ((...args) => {
677
+ if (!this.isEnabled) {
678
+ return this.originalWindowOpen(...args);
679
+ }
680
+ const url = args[0]?.toString() || 'popup';
681
+ console.log('[NavigationBlocker] Blocked window.open:', url);
682
+ this.notifyBlockedNavigation(url);
683
+ return null;
684
+ });
685
+ }
686
+ blockBeforeUnload() {
687
+ // Chặn unload
688
+ this.win.addEventListener('beforeunload', (e) => {
689
+ if (!this.isEnabled)
690
+ return;
691
+ console.log('[NavigationBlocker] Blocked beforeunload');
692
+ e.preventDefault();
693
+ e.returnValue = '';
694
+ return '';
695
+ }, true);
696
+ // Chặn unload
697
+ this.win.addEventListener('unload', (e) => {
698
+ if (!this.isEnabled)
699
+ return;
700
+ console.log('[NavigationBlocker] Blocked unload');
701
+ e.preventDefault();
702
+ e.stopPropagation();
703
+ }, true);
704
+ // Monitor popstate
705
+ this.win.addEventListener('popstate', (e) => {
706
+ if (!this.isEnabled)
707
+ return;
708
+ console.log('[NavigationBlocker] Blocked popstate');
709
+ e.preventDefault();
710
+ e.stopPropagation();
711
+ }, true);
712
+ }
713
+ monitorDOMChanges() {
714
+ // Monitor khi có links mới được thêm vào
715
+ const observer = new MutationObserver((mutations) => {
716
+ if (!this.isEnabled)
717
+ return;
718
+ mutations.forEach((mutation) => {
719
+ mutation.addedNodes.forEach((node) => {
720
+ if (node.nodeType === Node.ELEMENT_NODE) {
721
+ const element = node;
722
+ // Nếu là link
723
+ if (element.tagName === 'A') {
724
+ const href = element.getAttribute('href');
725
+ if (href && !href.startsWith('#')) {
726
+ element.style.cursor = 'not-allowed';
727
+ element.setAttribute('data-navigation-blocked', 'true');
728
+ element.setAttribute('data-original-href', href);
729
+ element.removeAttribute('href');
730
+ }
731
+ }
732
+ // Tìm links trong subtree
733
+ element.querySelectorAll('a[href]').forEach((link) => {
734
+ const href = link.getAttribute('href');
735
+ if (href && !href.startsWith('#')) {
736
+ link.style.cursor = 'not-allowed';
737
+ link.setAttribute('data-navigation-blocked', 'true');
738
+ link.setAttribute('data-original-href', href);
739
+ link.removeAttribute('href');
740
+ }
741
+ });
742
+ }
743
+ });
555
744
  });
556
- };
557
- doc.head.appendChild(script);
745
+ });
746
+ observer.observe(this.doc.body, {
747
+ childList: true,
748
+ subtree: true,
749
+ });
750
+ this.observers.push(observer);
751
+ }
752
+ injectCSP() {
753
+ // Thêm CSP meta tag nếu chưa có (optional)
754
+ try {
755
+ const existingCSP = this.doc.querySelector('meta[http-equiv="Content-Security-Policy"]');
756
+ if (!existingCSP) {
757
+ const meta = this.doc.createElement('meta');
758
+ meta.httpEquiv = 'Content-Security-Policy';
759
+ meta.content = "navigate-to 'none'"; // Chặn tất cả navigation
760
+ this.doc.head.appendChild(meta);
761
+ console.log('[NavigationBlocker] Injected CSP');
762
+ }
763
+ }
764
+ catch (error) {
765
+ console.warn('[NavigationBlocker] Could not inject CSP:', error);
766
+ }
767
+ }
768
+ handleFormSubmit(form) {
769
+ const formData = new FormData(form);
770
+ const data = {};
771
+ formData.forEach((value, key) => {
772
+ data[key] = value;
773
+ });
774
+ console.log('[NavigationBlocker] Handling form data:', data);
775
+ window.dispatchEvent(new CustomEvent('iframe-form-submit', {
776
+ detail: { form, data },
777
+ }));
778
+ }
779
+ notifyBlockedNavigation(url) {
780
+ console.warn('[NavigationBlocker] Navigation blocked to:', url);
781
+ window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', {
782
+ detail: { url, timestamp: Date.now() },
783
+ }));
784
+ if (this.shouldShowMessage(url)) {
785
+ this.showBlockedMessage(url);
786
+ }
787
+ }
788
+ shouldShowMessage(url) {
789
+ return !url.startsWith('#') && url !== 'reload' && url !== 'popup';
558
790
  }
559
- handleMessage(event) {
560
- const data = event.data;
561
- if (!data || data.type !== 'IFRAME_HEIGHT_CALCULATED')
791
+ showBlockedMessage(url) {
792
+ if (!this.showMessage)
562
793
  return;
563
- this.config.onSuccess?.(data);
794
+ const message = this.doc.createElement('div');
795
+ message.style.cssText = `
796
+ position: fixed;
797
+ top: 20px;
798
+ right: 20px;
799
+ background: #ff6b6b;
800
+ color: white;
801
+ padding: 12px 20px;
802
+ border-radius: 8px;
803
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
804
+ z-index: 999999;
805
+ font-family: system-ui, -apple-system, sans-serif;
806
+ font-size: 14px;
807
+ max-width: 300px;
808
+ word-break: break-word;
809
+ pointer-events: none;
810
+ `;
811
+ const shortUrl = url.length > 50 ? url.substring(0, 47) + '...' : url;
812
+ message.innerHTML = `
813
+ <div style="font-weight: 600; margin-bottom: 4px;">🚫 Navigation Blocked</div>
814
+ <div style="font-size: 12px; opacity: 0.9;">${this.escapeHtml(shortUrl)}</div>
815
+ `;
816
+ this.doc.body.appendChild(message);
817
+ setTimeout(() => {
818
+ message.style.opacity = '0';
819
+ message.style.transition = 'opacity 0.3s';
820
+ setTimeout(() => message.remove(), 300);
821
+ }, 3000);
564
822
  }
565
- recalculate() {
566
- this.injectScript();
823
+ escapeHtml(text) {
824
+ const div = this.doc.createElement('div');
825
+ div.textContent = text;
826
+ return div.innerHTML;
827
+ }
828
+ enable() {
829
+ this.isEnabled = true;
830
+ console.log('[NavigationBlocker] Enabled');
831
+ }
832
+ enableMessage() {
833
+ this.showMessage = true;
834
+ console.log('[NavigationBlocker] Enabled message');
835
+ }
836
+ disable() {
837
+ this.isEnabled = false;
838
+ console.log('[NavigationBlocker] Disabled');
839
+ }
840
+ disableMessage() {
841
+ this.showMessage = false;
842
+ console.log('[NavigationBlocker] Disabled message');
843
+ }
844
+ destroy() {
845
+ this.isEnabled = false;
846
+ this.showMessage = false;
847
+ // Cleanup observers
848
+ this.observers.forEach((observer) => observer.disconnect());
849
+ this.observers = [];
850
+ console.log('[NavigationBlocker] Destroyed');
567
851
  }
568
- }
569
- function initViewportFixer(config) {
570
- const fixer = new ViewportUnitsFixer(config);
571
- window.viewportFixer = fixer;
572
- window.addEventListener('iframe-dimensions-applied', ((e) => {
573
- const ev = e;
574
- console.log('Iframe dimensions finalized:', ev.detail);
575
- }));
576
- return fixer;
577
852
  }
578
853
 
579
- class ViewportUnitsReplacer {
854
+ class IframeStyleReplacer {
855
+ doc;
856
+ win;
580
857
  config;
581
858
  regex = /([-.\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
582
- constructor() {
583
- if (!window.__viewportConfig) {
584
- throw new Error('[Iframe] Do not have viewport config');
859
+ constructor(iframe, config) {
860
+ if (!iframe.contentDocument || !iframe.contentWindow) {
861
+ throw new Error('Iframe document or window not accessible');
585
862
  }
586
- this.config = window.__viewportConfig;
587
- console.log('[Iframe] ViewportUnitsReplacer started with config:', this.config);
588
- this.init();
863
+ this.doc = iframe.contentDocument;
864
+ this.win = iframe.contentWindow;
865
+ this.config = config;
589
866
  }
590
867
  px(value) {
591
868
  return `${value.toFixed(2)}px`;
@@ -611,26 +888,28 @@ class ViewportUnitsReplacer {
611
888
  }
612
889
  processInlineStyles() {
613
890
  let count = 0;
614
- document.querySelectorAll('[style]').forEach((el) => {
891
+ this.doc.querySelectorAll('[style]').forEach((el) => {
615
892
  const style = el.getAttribute('style');
616
893
  if (style && this.regex.test(style)) {
894
+ this.regex.lastIndex = 0;
617
895
  el.setAttribute('style', this.replaceInText(style));
618
896
  count++;
619
897
  }
620
898
  });
621
- console.log(`[Iframe] Replaced ${count} inline style elements`);
899
+ console.log(`[IframeStyleReplacer] Replaced ${count} inline style elements`);
622
900
  return count;
623
901
  }
624
902
  processStyleTags() {
625
903
  let count = 0;
626
- document.querySelectorAll('style').forEach((tag) => {
904
+ this.doc.querySelectorAll('style').forEach((tag) => {
627
905
  const css = tag.textContent || '';
628
906
  if (this.regex.test(css)) {
907
+ this.regex.lastIndex = 0;
629
908
  tag.textContent = this.replaceInText(css);
630
909
  count++;
631
910
  }
632
911
  });
633
- console.log(`[Iframe] Replaced ${count} <style> tags`);
912
+ console.log(`[IframeStyleReplacer] Replaced ${count} <style> tags`);
634
913
  return count;
635
914
  }
636
915
  processRule(rule) {
@@ -641,6 +920,7 @@ class ViewportUnitsReplacer {
641
920
  const prop = style[i];
642
921
  const value = style.getPropertyValue(prop);
643
922
  if (value && this.regex.test(value)) {
923
+ this.regex.lastIndex = 0;
644
924
  style.setProperty(prop, this.replaceInText(value), style.getPropertyPriority(prop));
645
925
  count++;
646
926
  }
@@ -656,11 +936,11 @@ class ViewportUnitsReplacer {
656
936
  }
657
937
  processStylesheets() {
658
938
  let total = 0;
659
- Array.from(document.styleSheets).forEach((sheet) => {
939
+ Array.from(this.doc.styleSheets).forEach((sheet) => {
660
940
  try {
661
941
  // Bỏ qua external CSS (cross-origin)
662
- if (sheet.href && !sheet.href.startsWith(location.origin)) {
663
- console.log('[Iframe] Skipping external CSS:', sheet.href);
942
+ if (sheet.href && !sheet.href.startsWith(this.win.location.origin)) {
943
+ console.log('[IframeStyleReplacer] Skipping external CSS:', sheet.href);
664
944
  return;
665
945
  }
666
946
  const rules = sheet.cssRules || sheet.rules;
@@ -671,26 +951,27 @@ class ViewportUnitsReplacer {
671
951
  }
672
952
  }
673
953
  catch (e) {
674
- console.warn('[Iframe] Cannot read stylesheet (CORS?):', e.message);
954
+ console.warn('[IframeStyleReplacer] Cannot read stylesheet (CORS?):', e.message);
675
955
  }
676
956
  });
677
- console.log(`[Iframe] Replaced ${total} rules in stylesheets`);
957
+ console.log(`[IframeStyleReplacer] Replaced ${total} rules in stylesheets`);
678
958
  return total;
679
959
  }
680
960
  async processLinkedStylesheets() {
681
- const links = document.querySelectorAll('link[rel="stylesheet"]');
961
+ const links = this.doc.querySelectorAll('link[rel="stylesheet"]');
682
962
  let count = 0;
683
963
  for (const link of Array.from(links)) {
684
- if (!link.href.startsWith(location.origin)) {
685
- console.log('[Iframe] Skipping external CSS:', link.href);
964
+ if (!link.href.startsWith(this.win.location.origin)) {
965
+ console.log('[IframeStyleReplacer] Skipping external CSS:', link.href);
686
966
  continue;
687
967
  }
688
968
  try {
689
969
  const res = await fetch(link.href);
690
970
  let css = await res.text();
691
971
  if (this.regex.test(css)) {
972
+ this.regex.lastIndex = 0;
692
973
  css = this.replaceInText(css);
693
- const style = document.createElement('style');
974
+ const style = this.doc.createElement('style');
694
975
  style.textContent = css;
695
976
  style.dataset.originalHref = link.href;
696
977
  link.parentNode?.insertBefore(style, link);
@@ -699,30 +980,25 @@ class ViewportUnitsReplacer {
699
980
  }
700
981
  }
701
982
  catch (e) {
702
- console.warn('[Iframe] Cannot load CSS:', link.href, e);
983
+ console.warn('[IframeStyleReplacer] Cannot load CSS:', link.href, e);
703
984
  }
704
985
  }
705
- console.log(`[Iframe] Replaced ${count} linked CSS files`);
986
+ console.log(`[IframeStyleReplacer] Replaced ${count} linked CSS files`);
706
987
  return count;
707
988
  }
708
989
  getFinalHeight() {
709
990
  // Trigger reflow
710
- void document.body.offsetHeight;
711
- return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight, document.documentElement.clientHeight);
991
+ void this.doc.body.offsetHeight;
992
+ return Math.max(this.doc.body.scrollHeight, this.doc.body.offsetHeight, this.doc.documentElement.scrollHeight, this.doc.documentElement.offsetHeight, this.doc.documentElement.clientHeight);
712
993
  }
713
- notifyParent(height) {
714
- window.parent.postMessage({
715
- type: 'IFRAME_HEIGHT_CALCULATED',
716
- height,
717
- width: document.body.scrollWidth,
718
- }, '*');
719
- console.log('[Iframe] Sent height to parent:', height);
994
+ getFinalWidth() {
995
+ return Math.max(this.doc.body.scrollWidth, this.doc.body.offsetWidth, this.doc.documentElement.scrollWidth, this.doc.documentElement.offsetWidth, this.doc.documentElement.clientWidth);
720
996
  }
721
997
  async waitForResources() {
722
- if ('fonts' in document) {
723
- await document.fonts.ready;
998
+ if ('fonts' in this.doc) {
999
+ await this.doc.fonts.ready;
724
1000
  }
725
- const images = Array.from(document.images).filter((img) => !img.complete);
1001
+ const images = Array.from(this.doc.images).filter((img) => !img.complete);
726
1002
  if (images.length > 0) {
727
1003
  await Promise.all(images.map((img) => new Promise((resolve) => {
728
1004
  img.onload = img.onerror = resolve;
@@ -731,35 +1007,131 @@ class ViewportUnitsReplacer {
731
1007
  }
732
1008
  async run() {
733
1009
  try {
1010
+ console.log('[IframeStyleReplacer] Starting viewport units replacement...');
734
1011
  this.processInlineStyles();
735
1012
  this.processStyleTags();
736
1013
  this.processStylesheets();
737
1014
  await this.processLinkedStylesheets();
738
1015
  // await this.waitForResources();
739
- requestAnimationFrame(() => {
740
- const height = this.getFinalHeight();
741
- this.notifyParent(height);
1016
+ return await new Promise((resolve) => {
1017
+ requestAnimationFrame(() => {
1018
+ const height = this.getFinalHeight();
1019
+ const width = this.getFinalWidth();
1020
+ console.log('[IframeStyleReplacer] Calculated dimensions:', { height, width });
1021
+ resolve({ height, width });
1022
+ });
742
1023
  });
743
1024
  }
744
1025
  catch (err) {
745
- console.error('[Iframe] Critical error:', err);
746
- this.notifyParent(document.body.scrollHeight || 1000);
1026
+ console.error('[IframeStyleReplacer] Critical error:', err);
1027
+ return {
1028
+ height: this.doc.body.scrollHeight || 1000,
1029
+ width: this.doc.body.scrollWidth || 1000,
1030
+ };
747
1031
  }
748
1032
  }
749
- init() {
750
- if (document.readyState === 'loading') {
751
- document.addEventListener('DOMContentLoaded', () => this.run());
1033
+ updateConfig(config) {
1034
+ this.config = { ...this.config, ...config };
1035
+ }
1036
+ }
1037
+
1038
+ class IframeHelperFixer {
1039
+ iframe;
1040
+ config;
1041
+ replacer = null;
1042
+ navigationBlocker = null;
1043
+ constructor(config) {
1044
+ this.config = config;
1045
+ this.iframe = config.iframe;
1046
+ this.init();
1047
+ }
1048
+ async init() {
1049
+ if (!this.iframe) {
1050
+ console.error('[IframeHelper] iframe not found');
1051
+ this.config.onError?.(new Error('iframe not found'));
1052
+ return;
1053
+ }
1054
+ // Wait for iframe to load completely
1055
+ if (this.iframe.contentDocument?.readyState === 'complete') {
1056
+ await this.process();
752
1057
  }
753
1058
  else {
754
- this.run();
1059
+ this.iframe.addEventListener('load', () => this.process());
1060
+ }
1061
+ }
1062
+ async process() {
1063
+ if (!this.iframe.contentDocument || !this.iframe.contentWindow) {
1064
+ console.error('[IframeHelper] Cannot access iframe document');
1065
+ this.config.onError?.(new Error('Cannot access iframe document'));
1066
+ return;
1067
+ }
1068
+ try {
1069
+ console.log('[IframeHelper] Processing viewport units...');
1070
+ // Create replacer instance
1071
+ this.replacer = new IframeStyleReplacer(this.iframe, this.config);
1072
+ // Create navigation blocker
1073
+ this.navigationBlocker = new IframeNavigationBlockerV2(this.iframe);
1074
+ // Run replacement
1075
+ const result = await this.replacer.run();
1076
+ console.log('[IframeHelper] Process completed:', result);
1077
+ // Trigger success callback
1078
+ this.config.onSuccess?.(result);
1079
+ // Dispatch custom event
1080
+ window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', {
1081
+ detail: result,
1082
+ }));
1083
+ }
1084
+ catch (error) {
1085
+ console.error('[IframeHelper] Failed to process:', error);
1086
+ this.config.onError?.(error);
755
1087
  }
756
1088
  }
1089
+ async recalculate() {
1090
+ console.log('[IframeHelper] Recalculating...');
1091
+ await this.process();
1092
+ }
1093
+ updateConfig(config) {
1094
+ this.config = { ...this.config, ...config };
1095
+ if (this.replacer) {
1096
+ this.replacer.updateConfig(config);
1097
+ }
1098
+ }
1099
+ enableNavigationBlocking() {
1100
+ this.navigationBlocker?.enable();
1101
+ }
1102
+ enableNavigationBlockingMessage() {
1103
+ this.navigationBlocker?.enableMessage();
1104
+ }
1105
+ disableNavigationBlocking() {
1106
+ this.navigationBlocker?.disable();
1107
+ }
1108
+ disableNavigationBlockingMessage() {
1109
+ this.navigationBlocker?.disableMessage();
1110
+ }
1111
+ destroy() {
1112
+ this.replacer = null;
1113
+ this.navigationBlocker?.destroy();
1114
+ this.navigationBlocker = null;
1115
+ console.log('[IframeHelper] Destroyed');
1116
+ }
757
1117
  }
758
1118
 
759
- var viewportReplacer = /*#__PURE__*/Object.freeze({
760
- __proto__: null,
761
- default: ViewportUnitsReplacer
762
- });
1119
+ function initIframeHelperFixer(config) {
1120
+ const fixer = new IframeHelperFixer(config);
1121
+ window.addEventListener('iframe-dimensions-applied', ((e) => {
1122
+ const ev = e;
1123
+ console.log('[IframeHelper] Iframe dimensions finalized:', ev.detail);
1124
+ }));
1125
+ window.addEventListener('iframe-navigation-blocked', ((e) => {
1126
+ const ev = e;
1127
+ console.warn('[IframeHelper] Iframe tried to navigate to:', ev.detail.url);
1128
+ }));
1129
+ window.addEventListener('iframe-form-submit', ((e) => {
1130
+ const ev = e;
1131
+ console.log('[IframeHelper] Iframe form submitted:', ev.detail.data);
1132
+ }));
1133
+ return fixer;
1134
+ }
763
1135
 
764
1136
  const scrollToElementIfNeeded = (visualRef, rect, scale) => {
765
1137
  if (!visualRef.current)
@@ -873,7 +1245,7 @@ const useHeatmapEffects = ({ isVisible, isElementSidebarOpen, setShouldShowCallo
873
1245
 
874
1246
  const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
875
1247
  const widthScale = useHeatmapVizStore((state) => state.scale);
876
- const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
1248
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
877
1249
  const heatmapWidth = useHeatmapConfigStore((state) => state.width);
878
1250
  return useCallback((element) => {
879
1251
  const hash = element?.hash;
@@ -921,6 +1293,109 @@ const debounce = (fn, delay) => {
921
1293
  };
922
1294
  };
923
1295
 
1296
+ // ===================== UTILITY FUNCTIONS =====================
1297
+ /**
1298
+ * Lấy bounding box tuyệt đối của element (relative to document)
1299
+ */
1300
+ function getBoundingBox(element) {
1301
+ if (typeof element.getBoundingClientRect !== 'function') {
1302
+ return null;
1303
+ }
1304
+ const rect = element.getBoundingClientRect();
1305
+ // Lấy scroll offset (hỗ trợ cả cách cũ và mới)
1306
+ const scrollLeft = 'pageXOffset' in window ? window.pageXOffset : document.documentElement.scrollLeft;
1307
+ const scrollTop = 'pageYOffset' in window ? window.pageYOffset : document.documentElement.scrollTop;
1308
+ // Kiểm tra element có kích thước hợp lệ
1309
+ if (!rect || (rect.height === 0 && rect.width === 0)) {
1310
+ return null;
1311
+ }
1312
+ // Trả về vị trí tuyệt đối
1313
+ return {
1314
+ left: Math.floor(rect.left + scrollLeft),
1315
+ top: Math.floor(rect.top + scrollTop),
1316
+ width: Math.floor(rect.width),
1317
+ height: Math.floor(rect.height),
1318
+ };
1319
+ }
1320
+ /**
1321
+ * Lấy tất cả elements tại tọa độ (x, y), hỗ trợ Shadow DOM
1322
+ */
1323
+ function getElementsAtPoint(documentOrShadowRoot, x, y, filterFunction, visitedShadowRoots = new Set()) {
1324
+ // Lấy tất cả elements tại vị trí
1325
+ const elementsAtPoint = documentOrShadowRoot.elementsFromPoint(x, y);
1326
+ if (!filterFunction) {
1327
+ return elementsAtPoint;
1328
+ }
1329
+ // Tìm element đầu tiên match với filter
1330
+ const matchedElement = elementsAtPoint.find(filterFunction);
1331
+ // Nếu element có Shadow DOM và chưa visit -> đệ quy vào
1332
+ if (matchedElement?.shadowRoot && !visitedShadowRoots.has(matchedElement.shadowRoot)) {
1333
+ visitedShadowRoots.add(matchedElement.shadowRoot);
1334
+ return getElementsAtPoint(matchedElement.shadowRoot, x, y, filterFunction, visitedShadowRoots);
1335
+ }
1336
+ return elementsAtPoint;
1337
+ }
1338
+ // ===================== EXAMPLE USAGE =====================
1339
+ /*
1340
+ import { useRef, useState } from 'react';
1341
+
1342
+ function HeatmapComponent() {
1343
+ const heatmapWrapperRef = useRef<HTMLDivElement>(null);
1344
+ const iframeRef = useRef<HTMLIFrameElement>(null);
1345
+ const parentRef = useRef<HTMLDivElement>(null);
1346
+
1347
+ const [hoveredElement, setHoveredElement] = useState<HoveredElementInfo | null>(null);
1348
+
1349
+ const heatmapInfo = {
1350
+ width: 1920,
1351
+ elementMapInfo: {
1352
+ 'hash123': {
1353
+ totalclicks: 45,
1354
+ selector: 'button.submit'
1355
+ }
1356
+ },
1357
+ sortedElements: [...]
1358
+ };
1359
+
1360
+ const { handleMouseMove } = useHeatmapMouseHandler({
1361
+ heatmapWrapperRef,
1362
+ iframeRef,
1363
+ parentRef,
1364
+ heatmapInfo,
1365
+ scaleRatio: 0.8, // 80% zoom
1366
+ onElementHover: (info) => {
1367
+ setHoveredElement(info);
1368
+ console.log('Hovered element:', info);
1369
+ }
1370
+ });
1371
+
1372
+ return (
1373
+ <div ref={parentRef}>
1374
+ <div
1375
+ ref={heatmapWrapperRef}
1376
+ onMouseMove={handleMouseMove}
1377
+ >
1378
+ <iframe ref={iframeRef} />
1379
+
1380
+ {hoveredElement && (
1381
+ <div className="tooltip" style={{
1382
+ position: 'absolute',
1383
+ left: hoveredElement.left,
1384
+ top: hoveredElement.top
1385
+ }}>
1386
+ Clicks: {hoveredElement.clicks}
1387
+ <br />
1388
+ Rank: #{hoveredElement.rank}
1389
+ <br />
1390
+ Selector: {hoveredElement.selector}
1391
+ </div>
1392
+ )}
1393
+ </div>
1394
+ </div>
1395
+ );
1396
+ }
1397
+ */
1398
+
924
1399
  const useHoveredElement = ({ iframeRef, getRect }) => {
925
1400
  const hoveredElement = useHeatmapInteractionStore((state) => state.hoveredElement);
926
1401
  const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
@@ -942,7 +1417,7 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
942
1417
  const doc = iframe.contentDocument;
943
1418
  const iframeRect = iframe.getBoundingClientRect();
944
1419
  const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
945
- const targetElement = findTargetElement(doc, x, y);
1420
+ const targetElement = findTargetElement(doc, x, y, heatmapInfo);
946
1421
  if (!targetElement || !isValidElement(targetElement, heatmapInfo)) {
947
1422
  reset();
948
1423
  return;
@@ -993,7 +1468,25 @@ const convertViewportToIframeCoords = (clientX, clientY, iframeRect, scale) => {
993
1468
  }
994
1469
  return { x, y };
995
1470
  };
996
- const findTargetElement = (doc, x, y) => {
1471
+ const findTargetElement = (doc, x, y, heatmapInfo) => {
1472
+ const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha';
1473
+ const elementsAtPoint = getElementsAtPoint(doc, Math.round(x), Math.round(y), (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
1474
+ let dataElement = null;
1475
+ for (let i = 0; i < elementsAtPoint.length; i++) {
1476
+ const element = elementsAtPoint[i];
1477
+ const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
1478
+ if (elementHash && heatmapInfo.elementMapInfo?.[elementHash]) {
1479
+ heatmapInfo.elementMapInfo[elementHash];
1480
+ const boundingBox = getBoundingBox(element);
1481
+ if (boundingBox) {
1482
+ dataElement = element;
1483
+ break;
1484
+ }
1485
+ }
1486
+ }
1487
+ if (!!dataElement) {
1488
+ return dataElement;
1489
+ }
997
1490
  let targetElement = getElementAtPoint(doc, x, y);
998
1491
  if (!targetElement) {
999
1492
  targetElement = doc.elementFromPoint(x, y);
@@ -1017,9 +1510,9 @@ var MessageType;
1017
1510
  MessageType["GX_DOM_TRACKING_PAYLOAD"] = "GX_DOM_TRACKING_PAYLOAD";
1018
1511
  MessageType["CLARITY_READY"] = "CLARITY_READY";
1019
1512
  })(MessageType || (MessageType = {}));
1020
- function useIframeMessage(options = {}) {
1513
+ function useVizLiveIframeMsg(options = {}) {
1021
1514
  const { trustedOrigins = [], onMessage } = options;
1022
- const [payloads, setPayloads] = useState([]);
1515
+ const addPayload = useHeatmapLiveStore((state) => state.addPayload);
1023
1516
  const [isReady, setIsReady] = useState(false);
1024
1517
  const iframeRef = useRef(null);
1025
1518
  const isValidOrigin = useCallback((origin) => {
@@ -1045,9 +1538,9 @@ function useIframeMessage(options = {}) {
1045
1538
  switch (message.type) {
1046
1539
  case MessageType.GX_DOM_TRACKING_PAYLOAD:
1047
1540
  if (message.payload) {
1048
- const decodedPayloads = decodePayloads(message.payload);
1049
- if (decodedPayloads) {
1050
- setPayloads((prev) => [...prev, decodedPayloads]);
1541
+ const data = decodePayloads(message.payload);
1542
+ if (data) {
1543
+ addPayload(data);
1051
1544
  }
1052
1545
  }
1053
1546
  break;
@@ -1062,27 +1555,19 @@ function useIframeMessage(options = {}) {
1062
1555
  window.removeEventListener('message', handleMessage);
1063
1556
  };
1064
1557
  }, [handleMessage]);
1065
- const clearPayloads = useCallback(() => {
1066
- setPayloads([]);
1067
- }, []);
1068
- const reset = useCallback(() => {
1069
- setPayloads([]);
1070
- setIsReady(false);
1071
- }, []);
1072
1558
  return {
1073
1559
  iframeRef,
1074
- payloads,
1075
1560
  isReady,
1076
- clearPayloads,
1077
- reset,
1078
1561
  };
1079
1562
  }
1080
- function useIframeRender() {
1563
+
1564
+ function useVizLiveRender() {
1081
1565
  const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
1566
+ const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
1082
1567
  const contentWidth = useHeatmapConfigStore((state) => state.width);
1083
- const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
1084
1568
  const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
1085
- const { iframeRef, payloads, isReady } = useIframeMessage();
1569
+ const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
1570
+ const { iframeRef, isReady } = useVizLiveIframeMsg();
1086
1571
  useEffect(() => {
1087
1572
  if (!htmlContent || !iframeRef.current)
1088
1573
  return;
@@ -1102,50 +1587,50 @@ function useIframeRender() {
1102
1587
  const iframe = iframeRef.current;
1103
1588
  if (!iframe || !htmlContent)
1104
1589
  return;
1105
- reset$1(iframe, { width: contentWidth, height: wrapperHeight }, (height) => {
1106
- setIframeHeight(height);
1590
+ setIsRenderViz(false);
1591
+ reset(iframe, { width: contentWidth, height: wrapperHeight }, (height) => {
1592
+ height && setIframeHeight(height);
1593
+ setIsRenderViz(true);
1107
1594
  });
1108
1595
  }, [isReady, contentWidth, wrapperHeight]);
1109
1596
  return {
1110
1597
  iframeRef,
1111
- payloads,
1112
- isReady,
1113
1598
  };
1114
1599
  }
1115
- function reset$1(iframe, payloads, onSuccess) {
1116
- const viewportFixer = initViewportFixer({
1117
- targetWidth: payloads.width,
1118
- targetHeight: payloads.height,
1600
+ function reset(iframe, rect, onSuccess) {
1601
+ const fixer = initIframeHelperFixer({
1602
+ targetWidth: rect.width,
1603
+ targetHeight: rect.height,
1119
1604
  iframe: iframe,
1120
1605
  onSuccess: (data) => {
1121
- onSuccess(data.height);
1122
1606
  iframe.height = `${data.height}px`;
1607
+ onSuccess(data.height);
1123
1608
  },
1124
1609
  });
1125
- viewportFixer.recalculate();
1126
- return iframe;
1610
+ // fixer.recalculate();
1611
+ fixer.enableNavigationBlocking();
1127
1612
  }
1128
1613
 
1614
+ let visualizer = new Visualizer();
1129
1615
  const useHeatmapRender = () => {
1130
1616
  const data = useHeatmapDataStore((state) => state.data);
1131
- const setVizRef = useHeatmapVizStore((state) => state.setVizRef);
1617
+ const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
1132
1618
  const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
1133
- const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
1619
+ const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
1134
1620
  const iframeRef = useRef(null);
1135
1621
  const renderHeatmap = useCallback(async (payloads) => {
1136
1622
  if (!payloads || payloads.length === 0)
1137
1623
  return;
1138
1624
  setIsRenderViz(false);
1139
- const visualizer = new Visualizer();
1140
1625
  const iframe = iframeRef.current;
1141
1626
  if (!iframe?.contentWindow)
1142
1627
  return;
1143
1628
  await visualizer.html(payloads, iframe.contentWindow);
1144
- reset(iframe, payloads, (height) => {
1629
+ initIframe(iframe, payloads, (height) => {
1145
1630
  height && setIframeHeight(height);
1146
1631
  setIsRenderViz(true);
1632
+ setVizRef(visualizer);
1147
1633
  });
1148
- setVizRef(visualizer);
1149
1634
  }, []);
1150
1635
  useEffect(() => {
1151
1636
  if (!data || data.length === 0)
@@ -1159,21 +1644,20 @@ const useHeatmapRender = () => {
1159
1644
  iframeRef,
1160
1645
  };
1161
1646
  };
1162
- function reset(iframe, payloads, onSuccess) {
1647
+ function initIframe(iframe, payloads, onSuccess) {
1163
1648
  const { size } = findLastSizeOfDom(payloads);
1164
1649
  const docWidth = size.width ?? 0;
1165
1650
  const docHeight = size.height ?? 0;
1166
- const viewportFixer = initViewportFixer({
1651
+ initIframeHelperFixer({
1167
1652
  targetWidth: docWidth,
1168
1653
  targetHeight: docHeight,
1169
1654
  iframe: iframe,
1170
1655
  onSuccess: (data) => {
1171
- onSuccess(data.height);
1172
1656
  iframe.height = `${data.height}px`;
1657
+ onSuccess(data.height);
1173
1658
  },
1174
1659
  });
1175
- viewportFixer.recalculate();
1176
- return iframe;
1660
+ // fixer.recalculate();
1177
1661
  }
1178
1662
 
1179
1663
  function isMobileDevice(userAgent) {
@@ -1358,30 +1842,64 @@ const useContentDimensions = ({ iframeRef, }) => {
1358
1842
  return { contentWidth };
1359
1843
  };
1360
1844
 
1361
- const useIframeHeight = (props) => {
1845
+ const useObserveIframeHeight = (props) => {
1362
1846
  const { iframeRef, setIframeHeight } = props;
1363
1847
  const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
1364
1848
  const resizeObserverRef = useRef(null);
1365
1849
  const mutationObserverRef = useRef(null);
1850
+ const debounceTimerRef = useRef(null);
1851
+ const lastHeightRef = useRef(0);
1852
+ const animationFrameRef = useRef(null);
1366
1853
  const updateIframeHeight = useCallback(() => {
1367
1854
  const iframe = iframeRef.current;
1368
- if (!iframe)
1855
+ if (!iframe || !setIframeHeight)
1369
1856
  return;
1370
1857
  try {
1371
1858
  const iframeDocument = iframe.contentDocument;
1372
1859
  const iframeBody = iframeDocument?.body;
1373
- if (!iframeBody)
1860
+ const iframeDocumentElement = iframeDocument?.documentElement;
1861
+ if (!iframeBody || !iframeDocumentElement)
1374
1862
  return;
1375
- const bodyHeight = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight, iframeBody.clientHeight);
1376
- if (bodyHeight > 0) {
1377
- iframe.height = `${bodyHeight}px`;
1378
- setIframeHeight(bodyHeight);
1379
- }
1863
+ iframe.style.height = 'auto';
1864
+ requestAnimationFrame(() => {
1865
+ const bodyHeight = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight, iframeBody.clientHeight);
1866
+ const documentHeight = Math.max(iframeDocumentElement.scrollHeight, iframeDocumentElement.offsetHeight, iframeDocumentElement.clientHeight);
1867
+ const actualHeight = Math.max(bodyHeight, documentHeight);
1868
+ if (actualHeight > 0) {
1869
+ lastHeightRef.current = actualHeight;
1870
+ iframe.height = `${actualHeight}px`;
1871
+ iframe.style.height = `${actualHeight}px`;
1872
+ setIframeHeight(actualHeight);
1873
+ }
1874
+ });
1380
1875
  }
1381
1876
  catch (error) {
1382
1877
  console.warn('Cannot measure iframe content:', error);
1383
1878
  }
1384
1879
  }, [iframeRef, setIframeHeight]);
1880
+ const debouncedUpdate = useCallback(() => {
1881
+ // Cancel pending updates
1882
+ if (debounceTimerRef.current) {
1883
+ clearTimeout(debounceTimerRef.current);
1884
+ }
1885
+ if (animationFrameRef.current) {
1886
+ cancelAnimationFrame(animationFrameRef.current);
1887
+ }
1888
+ debounceTimerRef.current = setTimeout(() => {
1889
+ animationFrameRef.current = requestAnimationFrame(() => {
1890
+ updateIframeHeight();
1891
+ });
1892
+ }, 50);
1893
+ }, [updateIframeHeight]);
1894
+ // Immediate update không debounce (cho ResizeObserver)
1895
+ const immediateUpdate = useCallback(() => {
1896
+ if (animationFrameRef.current) {
1897
+ cancelAnimationFrame(animationFrameRef.current);
1898
+ }
1899
+ animationFrameRef.current = requestAnimationFrame(() => {
1900
+ updateIframeHeight();
1901
+ });
1902
+ }, [updateIframeHeight]);
1385
1903
  useEffect(() => {
1386
1904
  const iframe = iframeRef.current;
1387
1905
  if (!iframe || !isRenderViz)
@@ -1399,22 +1917,24 @@ const useIframeHeight = (props) => {
1399
1917
  if (mutationObserverRef.current) {
1400
1918
  mutationObserverRef.current.disconnect();
1401
1919
  }
1402
- // ResizeObserver for size changes
1403
1920
  if (typeof window.ResizeObserver !== 'undefined') {
1404
- resizeObserverRef.current = new ResizeObserver(updateIframeHeight);
1921
+ resizeObserverRef.current = new ResizeObserver(immediateUpdate);
1405
1922
  resizeObserverRef.current.observe(iframeBody);
1923
+ const iframeDocumentElement = iframeDocument?.documentElement;
1924
+ if (iframeDocumentElement) {
1925
+ resizeObserverRef.current.observe(iframeDocumentElement);
1926
+ }
1406
1927
  }
1407
- // MutationObserver for DOM changes
1408
1928
  if (typeof window.MutationObserver !== 'undefined') {
1409
- mutationObserverRef.current = new MutationObserver(updateIframeHeight);
1929
+ mutationObserverRef.current = new MutationObserver(immediateUpdate);
1410
1930
  mutationObserverRef.current.observe(iframeBody, {
1411
1931
  childList: true,
1412
1932
  subtree: true,
1413
1933
  attributes: true,
1414
- characterData: true,
1934
+ attributeFilter: ['style', 'class'],
1935
+ characterData: false,
1415
1936
  });
1416
1937
  }
1417
- // Initial measurement
1418
1938
  updateIframeHeight();
1419
1939
  }
1420
1940
  catch (error) {
@@ -1428,30 +1948,74 @@ const useIframeHeight = (props) => {
1428
1948
  iframe.addEventListener('load', setupObservers, { once: true });
1429
1949
  }
1430
1950
  return () => {
1951
+ // Cleanup observers
1431
1952
  if (resizeObserverRef.current) {
1432
1953
  resizeObserverRef.current.disconnect();
1433
1954
  }
1434
1955
  if (mutationObserverRef.current) {
1435
1956
  mutationObserverRef.current.disconnect();
1436
1957
  }
1958
+ // Cleanup timers
1959
+ if (debounceTimerRef.current) {
1960
+ clearTimeout(debounceTimerRef.current);
1961
+ }
1962
+ if (animationFrameRef.current) {
1963
+ cancelAnimationFrame(animationFrameRef.current);
1964
+ }
1437
1965
  iframe.removeEventListener('load', setupObservers);
1438
1966
  };
1439
- }, [iframeRef, isRenderViz, updateIframeHeight]);
1967
+ }, [iframeRef, isRenderViz, updateIframeHeight, debouncedUpdate, immediateUpdate]);
1440
1968
  return {};
1441
1969
  };
1442
1970
 
1443
1971
  const useScaleCalculation = (props) => {
1444
1972
  const scale = useHeatmapVizStore((state) => state.scale);
1973
+ const zoomRatio = useHeatmapVizStore((state) => state.zoomRatio);
1445
1974
  const setScale = useHeatmapVizStore((state) => state.setScale);
1446
- const { containerWidth, contentWidth } = props;
1447
- useEffect(() => {
1448
- if (containerWidth > 0 && contentWidth > 0) {
1975
+ const isScaledToFit = useHeatmapVizStore((state) => state.isScaledToFit);
1976
+ const setIsScaledToFit = useHeatmapVizStore((state) => state.setIsScaledToFit);
1977
+ const minZoomRatio = useHeatmapVizStore((state) => state.minZoomRatio);
1978
+ const setMinZoomRatio = useHeatmapVizStore((state) => state.setMinZoomRatio);
1979
+ const { containerWidth, containerHeight, contentWidth, contentHeight } = props;
1980
+ const calculateScaleResult = useCallback(() => {
1981
+ if (containerWidth > 0 && contentWidth > 0 && containerHeight > 0 && contentHeight > 0) {
1982
+ // 1. Calculate widthScale (base scale from width)
1449
1983
  const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
1450
- const calculatedScale = Math.min(availableWidth / contentWidth, 1);
1451
- setScale(calculatedScale);
1984
+ const widthScale = Math.min(availableWidth / contentWidth, 1);
1985
+ // 2. Calculate available height
1986
+ const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] ;
1987
+ const paddingTotal = HEATMAP_CONFIG['padding'] * 2;
1988
+ const availableHeight = containerHeight - toolbarHeight - paddingTotal; // 10px buffer to avoid scroll bar
1989
+ // 3. Calculate minZoomRatio (zoom ratio minimum to fit iframe in container)
1990
+ const roundedMinZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100;
1991
+ // Limit minZoomRatio to a reasonable range (10-100)
1992
+ const finalMinZoomRatio = Math.max(10, Math.min(roundedMinZoomRatio, 100));
1993
+ // 4. Apply zoom ratio (cannot be less than minZoomRatio)
1994
+ const clampedZoomRatio = Math.max(zoomRatio, finalMinZoomRatio);
1995
+ const zoomMultiplier = clampedZoomRatio / 100;
1996
+ // 5. Calculate finalScale
1997
+ const finalScale = widthScale * zoomMultiplier;
1998
+ // 6. Check if it is currently fitted
1999
+ const isCurrentlyFitted = zoomRatio <= finalMinZoomRatio;
2000
+ // 7. Update store
2001
+ setScale(finalScale);
2002
+ setIsScaledToFit(isCurrentlyFitted);
2003
+ setMinZoomRatio(finalMinZoomRatio);
1452
2004
  }
1453
- }, [containerWidth, contentWidth]);
1454
- return { scale };
2005
+ }, [
2006
+ containerWidth,
2007
+ containerHeight,
2008
+ contentWidth,
2009
+ contentHeight,
2010
+ zoomRatio,
2011
+ setScale,
2012
+ setIsScaledToFit,
2013
+ setMinZoomRatio,
2014
+ ]);
2015
+ useEffect(() => {
2016
+ calculateScaleResult();
2017
+ }, [calculateScaleResult]);
2018
+ return { scale, isScaledToFit, minZoomRatio };
1455
2019
  };
1456
2020
 
1457
2021
  const useScrollSync = ({ iframeRef }) => {
@@ -1482,16 +2046,23 @@ const useHeatmapScale = (props) => {
1482
2046
  // 2. Get content dimensions from config
1483
2047
  const { contentWidth } = useContentDimensions({ iframeRef });
1484
2048
  // 3. Observe iframe height (now reacts to width changes)
1485
- useIframeHeight({ iframeRef, setIframeHeight });
2049
+ useObserveIframeHeight({ iframeRef, setIframeHeight });
1486
2050
  // 4. Calculate scale
1487
- const { scale } = useScaleCalculation({ containerWidth, contentWidth });
2051
+ const { scale } = useScaleCalculation({
2052
+ containerWidth,
2053
+ containerHeight,
2054
+ contentWidth,
2055
+ contentHeight: iframeHeight,
2056
+ });
1488
2057
  // 5. Setup scroll sync
1489
2058
  const { handleScroll } = useScrollSync({ iframeRef });
2059
+ const scaledHeight = iframeHeight * scale;
2060
+ const scaledWidth = contentWidth * scale;
1490
2061
  return {
1491
2062
  containerWidth,
1492
2063
  containerHeight,
1493
- scaledWidth: contentWidth * scale,
1494
- scaledHeight: iframeHeight * scale,
2064
+ scaledWidth,
2065
+ scaledHeight,
1495
2066
  handleScroll,
1496
2067
  };
1497
2068
  };
@@ -1565,6 +2136,135 @@ const useWrapperRefHeight = (props) => {
1565
2136
  return {};
1566
2137
  };
1567
2138
 
2139
+ const useZonePositions = (options) => {
2140
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2141
+ const getZonePosition = useCallback((zone) => {
2142
+ if (!iframeHeight) {
2143
+ return null;
2144
+ }
2145
+ const startYPx = (zone.startY / 100) * iframeHeight;
2146
+ const heightPx = ((zone.endY - zone.startY) / 100) * iframeHeight;
2147
+ return {
2148
+ top: startYPx,
2149
+ height: heightPx,
2150
+ };
2151
+ }, [iframeHeight]);
2152
+ return {
2153
+ getZonePosition,
2154
+ };
2155
+ };
2156
+
2157
+ const SCROLL_GRADIENT_COLORS = [
2158
+ [255, 0, 0], // Red
2159
+ [255, 255, 0], // Yellow
2160
+ [0, 255, 0], // Green
2161
+ ];
2162
+ const useScrollmapZones = (options) => {
2163
+ const { mode = 'basic', enabled = true, iframeRef, wrapperRef } = options;
2164
+ const [isReady, setIsReady] = useState(false);
2165
+ const [zones, setZones] = useState([]);
2166
+ const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2167
+ const scrollMapInfo = useHeatmapDataStore((state) => state.dataInfo?.scrollMapInfo);
2168
+ const { getZonePosition } = useZonePositions();
2169
+ const maxUsers = useMemo(() => {
2170
+ if (!scrollmap || scrollmap.length === 0)
2171
+ return 100;
2172
+ return Math.max(...scrollmap.map((d) => d.percUsers));
2173
+ }, [scrollmap]);
2174
+ const createZones = useCallback((data) => {
2175
+ if (mode === 'basic') {
2176
+ const breakpoints = [0, 25, 50, 75, 100];
2177
+ const zones = [];
2178
+ for (let i = 0; i < breakpoints.length - 1; i++) {
2179
+ const startY = breakpoints[i];
2180
+ const endY = breakpoints[i + 1];
2181
+ const pointsInRange = data.filter((d) => d.scrollReachY >= startY && d.scrollReachY < endY);
2182
+ const avgUsers = pointsInRange.length > 0
2183
+ ? pointsInRange.reduce((sum, p) => sum + p.percUsers, 0) / pointsInRange.length
2184
+ : 0;
2185
+ zones.push({
2186
+ id: `zone_${startY}_${endY}`,
2187
+ startY,
2188
+ endY,
2189
+ percUsers: avgUsers,
2190
+ label: `${startY}% - ${endY}%`,
2191
+ });
2192
+ }
2193
+ return zones;
2194
+ }
2195
+ else {
2196
+ // Metrics mode: 20 zones (5% intervals)
2197
+ const zones = [];
2198
+ const interval = 5;
2199
+ // Prepare metrics map
2200
+ let metricsMap;
2201
+ if (scrollMapInfo && Object.keys(scrollMapInfo).length > 0) {
2202
+ metricsMap = new Map();
2203
+ Object.entries(scrollMapInfo).forEach(([key, value]) => {
2204
+ metricsMap.set(Number(key), value);
2205
+ });
2206
+ }
2207
+ for (let i = 0; i < 100; i += interval) {
2208
+ const startY = i;
2209
+ const endY = i + interval;
2210
+ const point = data.find((d) => d.scrollReachY === startY) || {
2211
+ scrollReachY: startY,
2212
+ cumulativeSum: 0,
2213
+ percUsers: 0,
2214
+ };
2215
+ const metrics = metricsMap?.get(startY);
2216
+ zones.push({
2217
+ id: `zone_${startY}_${endY}`,
2218
+ startY,
2219
+ endY,
2220
+ percUsers: point.percUsers,
2221
+ metrics,
2222
+ label: `${startY}% - ${endY}%`,
2223
+ });
2224
+ }
2225
+ return zones;
2226
+ }
2227
+ }, [mode, scrollMapInfo]);
2228
+ /**
2229
+ * Initialize zones
2230
+ */
2231
+ useEffect(() => {
2232
+ if (!enabled || !scrollmap || scrollmap.length === 0) {
2233
+ setIsReady(false);
2234
+ return;
2235
+ }
2236
+ try {
2237
+ const newZones = createZones(scrollmap);
2238
+ setZones(newZones);
2239
+ setIsReady(true);
2240
+ console.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
2241
+ }
2242
+ catch (error) {
2243
+ console.error('[useScrollmap] Error:', error);
2244
+ setIsReady(false);
2245
+ }
2246
+ }, [enabled, scrollmap, mode, createZones]);
2247
+ return {
2248
+ zones,
2249
+ isReady,
2250
+ maxUsers,
2251
+ getZonePosition,
2252
+ };
2253
+ };
2254
+ /**
2255
+ * Get scroll gradient color for minimap
2256
+ */
2257
+ const getScrollGradientColor = (normalized) => {
2258
+ const idx = Math.min(Math.floor(normalized * 2), 1);
2259
+ const [r1, g1, b1] = SCROLL_GRADIENT_COLORS[idx];
2260
+ const [r2, g2, b2] = SCROLL_GRADIENT_COLORS[idx + 1];
2261
+ const localPercent = (normalized * 2) % 1;
2262
+ const r = Math.round(r1 + (r2 - r1) * localPercent);
2263
+ const g = Math.round(g1 + (g2 - g1) * localPercent);
2264
+ const b = Math.round(b1 + (b2 - b1) * localPercent);
2265
+ return `rgb(${r}, ${g}, ${b})`;
2266
+ };
2267
+
1568
2268
  const BoxStack = forwardRef(({ children, ...props }, ref) => {
1569
2269
  const id = props.id;
1570
2270
  const flexDirection = props.flexDirection;
@@ -1626,7 +2326,6 @@ const ContentMetricBar = () => {
1626
2326
  const ContentToolbar = () => {
1627
2327
  const controls = useHeatmapControlStore((state) => state.controls);
1628
2328
  return (jsx("div", { id: "gx-hm-content-toolbar", style: {
1629
- zIndex: 2,
1630
2329
  position: 'absolute',
1631
2330
  bottom: 0,
1632
2331
  left: '8px',
@@ -1651,35 +2350,57 @@ const VizContainer = ({ children, setWrapperHeight }) => {
1651
2350
  const useClickmap = () => {
1652
2351
  const [isInitialized, setIsInitialized] = useState(false);
1653
2352
  const clickmap = useHeatmapDataStore((state) => state.clickmap);
1654
- const vizRef = useHeatmapVizStore((state) => state.vizRef);
1655
- useEffect(() => {
2353
+ const vizRef = useHeatmapSingleStore((state) => state.vizRef);
2354
+ const start = useCallback(() => {
1656
2355
  if (isInitialized)
1657
2356
  return;
1658
2357
  if (!vizRef || !clickmap || clickmap.length === 0)
1659
2358
  return;
1660
- vizRef.clearmap();
1661
- vizRef?.clickmap(clickmap);
1662
- setIsInitialized(true);
2359
+ try {
2360
+ vizRef?.clearmap?.();
2361
+ vizRef?.clickmap?.(clickmap);
2362
+ setIsInitialized(true);
2363
+ }
2364
+ catch (error) {
2365
+ console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
2366
+ }
1663
2367
  }, [vizRef, clickmap]);
1664
- return {};
2368
+ return { start };
1665
2369
  };
1666
2370
 
1667
2371
  const useScrollmap = () => {
1668
- useHeatmapDataStore((state) => state.clickmap);
1669
- return {};
2372
+ const vizRef = useHeatmapSingleStore((state) => state.vizRef);
2373
+ const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2374
+ const start = useCallback(() => {
2375
+ // if (isInitialized) return;
2376
+ if (!vizRef || !scrollmap || scrollmap.length === 0)
2377
+ return;
2378
+ try {
2379
+ vizRef?.clearmap?.();
2380
+ vizRef?.scrollmap?.(scrollmap);
2381
+ // setIsInitialized(true);
2382
+ }
2383
+ catch (error) {
2384
+ console.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
2385
+ }
2386
+ }, [vizRef, scrollmap]);
2387
+ return { start };
1670
2388
  };
1671
2389
 
1672
- const useHeatmapVizCanvas = () => {
2390
+ const useHeatmapCanvas = ({ iframeRef, }) => {
1673
2391
  const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
1674
- const heatmapRender = useMemo(() => {
2392
+ const { start: startClickmap } = useClickmap();
2393
+ const { start: startScrollmap } = useScrollmap();
2394
+ useEffect(() => {
1675
2395
  switch (heatmapType) {
1676
2396
  case IHeatmapType.Click:
1677
- return useClickmap;
2397
+ startClickmap();
2398
+ break;
1678
2399
  case IHeatmapType.Scroll:
1679
- return useScrollmap;
2400
+ startScrollmap();
2401
+ break;
1680
2402
  }
1681
- }, [heatmapType]);
1682
- return heatmapRender?.();
2403
+ }, [heatmapType, startClickmap, startScrollmap]);
1683
2404
  };
1684
2405
 
1685
2406
  const CLICKED_ELEMENT_ID = 'gx-hm-clicked-element';
@@ -1742,7 +2463,7 @@ const ElementCallout = (props) => {
1742
2463
  window.removeEventListener('resize', handleUpdate);
1743
2464
  visualRef?.current?.removeEventListener('scroll', handleUpdate);
1744
2465
  };
1745
- }, [target, visualRef, hozOffset, alignment]);
2466
+ }, [element, target, visualRef, hozOffset, alignment]);
1746
2467
  const calloutContent = (jsx("div", { ref: calloutRef, className: `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`, style: {
1747
2468
  position: 'fixed',
1748
2469
  top: position.top,
@@ -1807,8 +2528,8 @@ const ELEMENT_CALLOUT = {
1807
2528
  alignment: 'left',
1808
2529
  };
1809
2530
  const HeatmapElements = (props) => {
1810
- const height = useHeatmapVizStore((state) => state.iframeHeight);
1811
- const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, ...rest } = props;
2531
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2532
+ const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, } = props;
1812
2533
  const getRect = useHeatmapElementPosition({
1813
2534
  iframeRef,
1814
2535
  wrapperRef,
@@ -1837,14 +2558,21 @@ const HeatmapElements = (props) => {
1837
2558
  });
1838
2559
  if (!isVisible)
1839
2560
  return null;
1840
- return (jsxs("div", { onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height }, children: [jsx(ElementMissing, { show: showMissingElement }), jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementOverlay, { type: "clicked", element: clickedElement, isSecondary: isSecondary }), jsx(ElementOverlay, { type: "hovered", element: hoveredElement, isSecondary: isSecondary, onClick: handleClick }), hoveredElement?.hash !== clickedElement?.hash && hoveredElement && (jsx(ElementCallout, { element: hoveredElement, target: `#${HOVERED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT })), shouldShowCallout && clickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${CLICKED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT }))] }));
2561
+ return (jsxs("div", { onMouseMove: (event) => {
2562
+ handleMouseMove(event);
2563
+ // handleMouseMove2(event as any);
2564
+ }, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height: `${iframeHeight}px` }, children: [jsx(ElementMissing, { show: showMissingElement }), jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementOverlay, { type: "clicked", element: clickedElement, isSecondary: isSecondary }), jsx(ElementOverlay, { type: "hovered", element: hoveredElement, isSecondary: isSecondary, onClick: handleClick }), hoveredElement?.hash !== clickedElement?.hash && hoveredElement && (jsx(ElementCallout, { element: hoveredElement, target: `#${HOVERED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT })), shouldShowCallout && clickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${CLICKED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT }))] }));
1841
2565
  };
1842
2566
 
1843
2567
  const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
1844
2568
  const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
1845
- const contentWidth = useHeatmapDataStore((state) => state.config?.width ?? 0);
2569
+ const contentWidth = useHeatmapConfigStore((state) => state.width);
2570
+ const vizRef = useHeatmapSingleStore((state) => state.vizRef);
1846
2571
  const visualizer = {
1847
2572
  get: (hash) => {
2573
+ if (vizRef) {
2574
+ return vizRef.get(hash);
2575
+ }
1848
2576
  const doc = iframeRef.current?.contentDocument;
1849
2577
  if (!doc)
1850
2578
  return null;
@@ -1870,6 +2598,293 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
1870
2598
  } }));
1871
2599
  };
1872
2600
 
2601
+ const AverageFoldLine = ({ iframeRef, wrapperRef }) => {
2602
+ const averageFold = useHeatmapDataStore((state) => state.dataInfo?.averageFold || 50);
2603
+ const { getZonePosition } = useZonePositions();
2604
+ const position = getZonePosition({
2605
+ startY: averageFold,
2606
+ endY: averageFold,
2607
+ });
2608
+ if (!position)
2609
+ return null;
2610
+ return (jsx("div", { style: {
2611
+ position: 'absolute',
2612
+ top: `${position.top}px`,
2613
+ left: 0,
2614
+ width: '100%',
2615
+ height: '2px',
2616
+ backgroundColor: '#0078D4',
2617
+ pointerEvents: 'none',
2618
+ zIndex: 2,
2619
+ boxShadow: '0 0 4px rgba(0,120,212,0.5)',
2620
+ display: 'flex',
2621
+ alignItems: 'center',
2622
+ }, children: jsxs("div", { style: {
2623
+ position: 'absolute',
2624
+ padding: '8px',
2625
+ backgroundColor: 'rgba(0, 120, 212, 0.9)',
2626
+ color: 'white',
2627
+ fontSize: '16px',
2628
+ fontWeight: 600,
2629
+ borderRadius: '4px',
2630
+ whiteSpace: 'nowrap',
2631
+ left: '12px',
2632
+ minWidth: '120px',
2633
+ textAlign: 'center',
2634
+ }, children: ["Average fold - ", averageFold.toFixed(0), "%"] }) }));
2635
+ };
2636
+
2637
+ const ScrollmapMarker = ({ iframeRef, wrapperRef }) => {
2638
+ const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2639
+ const scrollType = useHeatmapConfigStore((state) => state.scrollType);
2640
+ const { getZonePosition } = useZonePositions();
2641
+ if (!scrollmap || scrollmap.length === 0)
2642
+ return null;
2643
+ const findScrollPositionForUserPercent = (targetPercent) => {
2644
+ for (let i = 0; i < scrollmap.length; i++) {
2645
+ if (scrollmap[i].percUsers <= targetPercent) {
2646
+ if (i > 0) {
2647
+ return scrollmap[i - 1].scrollReachY;
2648
+ }
2649
+ return scrollmap[i].scrollReachY;
2650
+ }
2651
+ }
2652
+ return scrollmap[scrollmap.length - 1]?.scrollReachY || null;
2653
+ };
2654
+ const boundaries = [
2655
+ { percent: 75, label: '75%', color: '#10B981' },
2656
+ { percent: 50, label: '50%', color: '#F59E0B' },
2657
+ { percent: 25, label: '25%', color: '#EF4444' },
2658
+ { percent: 5, label: '5%', color: '#8B5CF6' },
2659
+ ];
2660
+ const isScrollDepth = scrollType === IScrollType.Depth;
2661
+ if (!isScrollDepth)
2662
+ return null;
2663
+ return (jsx(Fragment, { children: boundaries.map((boundary) => {
2664
+ const scrollY = findScrollPositionForUserPercent(boundary.percent);
2665
+ if (scrollY === null)
2666
+ return null;
2667
+ const position = getZonePosition({
2668
+ startY: scrollY,
2669
+ endY: scrollY,
2670
+ });
2671
+ if (!position)
2672
+ return null;
2673
+ return (jsx("div", { className: `marker-boundary-line-${boundary.percent}`, style: {
2674
+ position: 'absolute',
2675
+ top: `${position.top}px`,
2676
+ left: 0,
2677
+ transformOrigin: 'left center',
2678
+ width: '100%',
2679
+ height: '0px',
2680
+ // borderBottom: `2px dashed #323130`,
2681
+ borderBottom: `2px solid ${boundary.color}`,
2682
+ // background: 'repeating-linear-gradient(90deg, #323130, transparent 2px 3px)',
2683
+ zIndex: 1,
2684
+ display: 'flex',
2685
+ alignItems: 'center',
2686
+ }, children: jsx("div", { style: {
2687
+ position: 'absolute',
2688
+ padding: '8px',
2689
+ backgroundColor: boundary.color,
2690
+ color: 'white',
2691
+ fontSize: '16px',
2692
+ fontWeight: 600,
2693
+ borderRadius: '4px',
2694
+ whiteSpace: 'nowrap',
2695
+ left: '12px',
2696
+ minWidth: '120px',
2697
+ textAlign: 'center',
2698
+ // textAlign: 'center',
2699
+ // padding: '8px',
2700
+ // paddingInline: '8px',
2701
+ // fontSize: '16px',
2702
+ // background: '#fff',
2703
+ // width: 'auto',
2704
+ // borderRadius: '4px',
2705
+ // position: 'absolute',
2706
+ // left: '12px',
2707
+ // minWidth: '120px',
2708
+ }, children: boundary.label }) }, boundary.label));
2709
+ }) }));
2710
+ };
2711
+
2712
+ const ScrollMapMinimap = ({ zones, maxUsers }) => {
2713
+ const showMinimap = useHeatmapVizScrollmapStore((state) => state.showMinimap);
2714
+ const scrollType = useHeatmapConfigStore((state) => state.scrollType);
2715
+ const isScrollType = [IScrollType.Attention].includes(scrollType);
2716
+ if (!showMinimap || !isScrollType)
2717
+ return null;
2718
+ return (jsx("div", { style: {
2719
+ position: 'fixed',
2720
+ left: '20px',
2721
+ top: '50%',
2722
+ transform: 'translateY(-50%)',
2723
+ width: '60px',
2724
+ height: '400px',
2725
+ backgroundColor: 'white',
2726
+ borderRadius: '8px',
2727
+ boxShadow: '0 4px 16px rgba(0,0,0,0.15)',
2728
+ zIndex: 10002,
2729
+ padding: '8px',
2730
+ boxSizing: 'border-box',
2731
+ }, children: jsx("div", { style: {
2732
+ width: '100%',
2733
+ height: '100%',
2734
+ borderRadius: '4px',
2735
+ overflow: 'hidden',
2736
+ display: 'flex',
2737
+ flexDirection: 'column',
2738
+ }, children: zones.map((zone) => {
2739
+ const normalized = maxUsers > 0 ? zone.percUsers / maxUsers : 0;
2740
+ const color = getScrollGradientColor(normalized);
2741
+ return (jsx("div", { title: `${zone.label}: ${zone.percUsers.toFixed(2)}%`, style: {
2742
+ width: '100%',
2743
+ flex: `${zone.endY - zone.startY}`,
2744
+ backgroundColor: color,
2745
+ borderBottom: '1px solid rgba(255,255,255,0.2)',
2746
+ } }, zone.id));
2747
+ }) }) }));
2748
+ };
2749
+
2750
+ const ScrollZoneTooltip = ({ zone, position, currentScrollPercent, scrollmap, }) => {
2751
+ const tooltipRef = useRef(null);
2752
+ const currentData = useMemo(() => {
2753
+ if (!scrollmap || scrollmap.length === 0)
2754
+ return null;
2755
+ const roundedPercent = Math.floor(currentScrollPercent);
2756
+ return scrollmap.find((d) => d.scrollReachY === roundedPercent) || null;
2757
+ }, [scrollmap, currentScrollPercent]);
2758
+ return (jsxs("div", { id: "gx-hm-scrollmap-tooltip", ref: tooltipRef, style: {
2759
+ position: 'fixed',
2760
+ top: `${position.y}px`,
2761
+ backgroundColor: 'black',
2762
+ zIndex: 10001,
2763
+ pointerEvents: 'none',
2764
+ width: '100%',
2765
+ height: '2px',
2766
+ }, children: [jsxs("div", { style: {
2767
+ position: 'absolute',
2768
+ left: '50%',
2769
+ top: '-50%',
2770
+ transform: 'translate(-50%, -50%)',
2771
+ padding: '16px',
2772
+ borderRadius: '8px',
2773
+ boxShadow: '0 4px 16px rgba(0,0,0,0.15)',
2774
+ fontSize: '14px',
2775
+ width: 'fit-content',
2776
+ backgroundColor: 'white',
2777
+ minWidth: '230px',
2778
+ display: 'flex',
2779
+ gap: '8px',
2780
+ alignItems: 'center',
2781
+ }, children: [jsxs("p", { style: {
2782
+ fontWeight: 650,
2783
+ fontSize: '20px',
2784
+ lineHeight: '24px',
2785
+ letterSpacing: '-0.2px',
2786
+ verticalAlign: 'middle',
2787
+ fontVariantNumeric: 'tabular-nums',
2788
+ }, children: [currentData?.percUsers?.toFixed(2), "%", ' '] }), jsx("p", { style: { fontWeight: 450 }, children: "user scrolled this far" })] }), jsx(TooltipByZone, { zone: zone })] }));
2789
+ };
2790
+ const TooltipByZone = ({ zone }) => {
2791
+ const scrollType = useHeatmapConfigStore((state) => state.scrollType);
2792
+ if (!zone)
2793
+ return null;
2794
+ const contentMarkup = () => {
2795
+ switch (scrollType) {
2796
+ case IScrollType.Depth:
2797
+ return jsx(BasicTooltipContent, { zone: zone });
2798
+ case IScrollType.Attention:
2799
+ return jsx(MetricsTooltipContent, { zone: zone });
2800
+ default:
2801
+ return jsx(BasicTooltipContent, { zone: zone });
2802
+ }
2803
+ };
2804
+ return (jsx("div", { style: { paddingTop: '12px', borderTop: '1px solid #E5E7EB' }, children: contentMarkup() }));
2805
+ };
2806
+ const BasicTooltipContent = ({ zone }) => {
2807
+ if (!zone)
2808
+ return null;
2809
+ return (jsxs(Fragment, { children: [jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: zone.label }), jsxs("div", { style: { fontSize: '24px', fontWeight: 700, color: '#0078D4' }, children: [zone.percUsers.toFixed(2), "%"] }), jsx("div", { style: { fontSize: '12px', color: '#605E5C', marginTop: '4px' }, children: "of users reached this point" })] }));
2810
+ };
2811
+ const MetricsTooltipContent = ({ zone }) => {
2812
+ if (!zone)
2813
+ return null;
2814
+ return (jsxs(Fragment, { children: [jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: zone.label }), jsxs("div", { style: { fontSize: '20px', fontWeight: 700, marginBottom: '8px' }, children: [zone.percUsers.toFixed(2), "% users"] }), zone.metrics && (jsxs("div", { style: { display: 'grid', gap: '6px', fontSize: '13px' }, children: [zone.metrics.revenue !== undefined && (jsx(MetricRow, { label: "Revenue", value: `$${zone.metrics.revenue.toFixed(2)}` })), zone.metrics.conversionRate !== undefined && (jsx(MetricRow, { label: "Conversion", value: `${zone.metrics.conversionRate.toFixed(2)}%` })), zone.metrics.orders !== undefined && (jsx(MetricRow, { label: "Orders", value: zone.metrics.orders.toString() }))] }))] }));
2815
+ };
2816
+ const MetricRow = ({ label, value }) => (jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [jsxs("span", { style: { color: '#605E5C' }, children: [label, ":"] }), jsx("span", { style: { fontWeight: 600 }, children: value })] }));
2817
+
2818
+ const HoverZones = ({ iframeRef, wrapperRef, position, currentScrollPercent, }) => {
2819
+ const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2820
+ // const hoveredZone = useHeatmapVizScrollmapStore((state) => state.hoveredZone);
2821
+ // const setHoveredZone = useHeatmapVizScrollmapStore((state) => state.setHoveredZone);
2822
+ const { zones, isReady, maxUsers } = useScrollmapZones({
2823
+ iframeRef,
2824
+ wrapperRef,
2825
+ });
2826
+ if (!isReady || !zones.length)
2827
+ return null;
2828
+ if (!position)
2829
+ return null;
2830
+ return (jsxs(Fragment, { children: [jsx(ScrollZoneTooltip, { position: position, currentScrollPercent: currentScrollPercent, scrollmap: scrollmap || [] }), jsx(ScrollMapMinimap, { zones: zones, maxUsers: maxUsers })] }));
2831
+ };
2832
+
2833
+ const ScrollMapOverlay = ({ wrapperRef, iframeRef }) => {
2834
+ const overlayRef = useRef(null);
2835
+ const [position, setPosition] = useState();
2836
+ const [currentScrollPercent, setCurrentScrollPercent] = useState(0);
2837
+ const widthScale = useHeatmapVizStore((state) => state.scale);
2838
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2839
+ const handleMouseMove = (event) => {
2840
+ if (!iframeRef.current || !wrapperRef.current)
2841
+ return;
2842
+ const iframe = iframeRef.current;
2843
+ const iframeRect = iframe.getBoundingClientRect();
2844
+ const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
2845
+ const wrapperEl = wrapperRef.current;
2846
+ const scrollOffset = (wrapperEl?.scrollTop || 0) / widthScale;
2847
+ const actualY = y + scrollOffset;
2848
+ const scrollPercent = Math.min(100, Math.max(0, (actualY / iframeHeight) * 100));
2849
+ setCurrentScrollPercent(scrollPercent);
2850
+ setPosition({ x, y });
2851
+ };
2852
+ const onMouseMove = useCallback((event) => {
2853
+ requestAnimationFrame(() => handleMouseMove(event));
2854
+ }, [handleMouseMove]);
2855
+ const onMouseLeave = () => {
2856
+ requestAnimationFrame(() => {
2857
+ setCurrentScrollPercent(0);
2858
+ setPosition(undefined);
2859
+ });
2860
+ };
2861
+ return (jsx("div", { ref: overlayRef, id: "gx-hm-scrollmap-overlay", onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, style: {
2862
+ position: 'absolute',
2863
+ top: 0,
2864
+ left: 0,
2865
+ width: '100%',
2866
+ height: `${iframeHeight}px`,
2867
+ zIndex: 3,
2868
+ }, children: jsx(HoverZones, { position: position, currentScrollPercent: currentScrollPercent, iframeRef: iframeRef, wrapperRef: wrapperRef }) }));
2869
+ };
2870
+
2871
+ const SCROLL_TYPES = [IHeatmapType.Scroll];
2872
+ const VizScrollMap = ({ iframeRef, wrapperRef }) => {
2873
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2874
+ const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
2875
+ const isHeatmapScroll = SCROLL_TYPES.includes(heatmapType);
2876
+ if (!iframeHeight || !isHeatmapScroll)
2877
+ return null;
2878
+ return (jsxs("div", { style: {
2879
+ position: 'absolute',
2880
+ top: 0,
2881
+ left: '2px',
2882
+ width: `calc(100% - 4px)`,
2883
+ height: '100%',
2884
+ transform: 'translateZ(0)',
2885
+ }, children: [jsx(ScrollmapMarker, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(AverageFoldLine, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(ScrollMapOverlay, { wrapperRef: wrapperRef, iframeRef: iframeRef })] }));
2886
+ };
2887
+
1873
2888
  const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
1874
2889
  const contentWidth = useHeatmapConfigStore((state) => state.width);
1875
2890
  const widthScale = useHeatmapVizStore((state) => state.scale);
@@ -1877,7 +2892,7 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
1877
2892
  ? `${scaledHeight + HEATMAP_CONFIG['heightToolbar'] + HEATMAP_CONFIG['padding'] * 2}px`
1878
2893
  : 'auto';
1879
2894
  return (jsx("div", { ref: visualRef, className: "gx-hm-visual", onScroll: onScroll, style: {
1880
- overflow: 'hidden auto',
2895
+ overflow: 'hidden scroll',
1881
2896
  display: 'flex',
1882
2897
  position: 'relative',
1883
2898
  justifyContent: 'center',
@@ -1904,8 +2919,9 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
1904
2919
 
1905
2920
  const VizDomRenderer = ({ mode = 'heatmap' }) => {
1906
2921
  const width = useHeatmapConfigStore((state) => state.width);
1907
- const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
1908
- const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
2922
+ const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
2923
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2924
+ const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
1909
2925
  const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
1910
2926
  const wrapperRef = useRef(null);
1911
2927
  const visualRef = useRef(null);
@@ -1915,14 +2931,13 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
1915
2931
  iframeRef,
1916
2932
  visualRef,
1917
2933
  iframeHeight,
1918
- setIframeHeight,
1919
2934
  });
1920
2935
  const contentWidth = width ?? 0;
1921
2936
  const onScroll = (e) => {
1922
2937
  const scrollTop = e.currentTarget.scrollTop;
1923
2938
  handleScroll(scrollTop);
1924
2939
  };
1925
- useHeatmapVizCanvas();
2940
+ useHeatmapCanvas({ iframeRef: iframeRef });
1926
2941
  const cleanUp = () => {
1927
2942
  setIframeHeight(0);
1928
2943
  setSelectedElement(null);
@@ -1930,7 +2945,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
1930
2945
  useEffect(() => {
1931
2946
  return cleanUp;
1932
2947
  }, []);
1933
- return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizElements, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, height: iframeHeight, scrolling: "no" })] }));
2948
+ return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [heatmapType === IHeatmapType.Click && (jsx(VizElements, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef })), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, scrolling: "no" }), jsx(VizScrollMap, { iframeRef: iframeRef, wrapperRef: visualRef })] }));
1934
2949
  };
1935
2950
 
1936
2951
  const VizLoading = () => {
@@ -1940,12 +2955,12 @@ const VizLoading = () => {
1940
2955
  const VizDomHeatmap = () => {
1941
2956
  const controls = useHeatmapControlStore((state) => state.controls);
1942
2957
  const isRendering = useHeatmapDataStore((state) => state.isRendering);
1943
- const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
1944
- const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
1945
- const setVizRef = useHeatmapVizStore((state) => state.setVizRef);
2958
+ const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2959
+ const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
2960
+ const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
1946
2961
  useEffect(() => {
1947
2962
  return () => {
1948
- setVizRef(undefined);
2963
+ setVizRef(null);
1949
2964
  setIframeHeight(0);
1950
2965
  };
1951
2966
  }, []);
@@ -1960,7 +2975,7 @@ const VizLiveRenderer = () => {
1960
2975
  const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
1961
2976
  const visualRef = useRef(null);
1962
2977
  const wrapperRef = useRef(null);
1963
- const { iframeRef } = useIframeRender();
2978
+ const { iframeRef } = useVizLiveRender();
1964
2979
  const { scaledHeight, handleScroll } = useHeatmapScale({
1965
2980
  wrapperRef,
1966
2981
  iframeRef,
@@ -1972,13 +2987,15 @@ const VizLiveRenderer = () => {
1972
2987
  const scrollTop = e.currentTarget.scrollTop;
1973
2988
  handleScroll(scrollTop);
1974
2989
  };
1975
- return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, height: iframeHeight, scrolling: "no", sandbox: "allow-scripts allow-same-origin" }) }));
2990
+ return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
2991
+ // height={iframeHeight}
2992
+ scrolling: "no", sandbox: "allow-scripts allow-same-origin" }) }));
1976
2993
  };
1977
2994
 
1978
2995
  const VizLiveHeatmap = () => {
1979
2996
  const controls = useHeatmapControlStore((state) => state.controls);
1980
2997
  const isRendering = useHeatmapDataStore((state) => state.isRendering);
1981
- const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
2998
+ const iframeHeight = useHeatmapLiveStore((state) => state.iframeHeight);
1982
2999
  const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
1983
3000
  const setWrapperHeight = useHeatmapLiveStore((state) => state.setWrapperHeight);
1984
3001
  const reset = useHeatmapLiveStore((state) => state.reset);
@@ -2035,10 +3052,10 @@ const WrapperLayout = () => {
2035
3052
  return (jsxs(BoxStack, { id: "gx-hm-layout", flexDirection: "column", flex: "1", children: [jsx(ContentTopBar, {}), jsx(WrapperPreview, {})] }));
2036
3053
  };
2037
3054
 
2038
- const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
3055
+ const HeatmapLayout = ({ data, clickmap, scrollmap, controls, dataInfo, }) => {
2039
3056
  useRegisterControl(controls);
2040
3057
  useRegisterData(data, dataInfo);
2041
- useRegisterHeatmap(clickmap);
3058
+ useRegisterHeatmap({ clickmap, scrollmap });
2042
3059
  useRegisterConfig();
2043
3060
  return (jsx(BoxStack, { id: "gx-hm-project", flexDirection: "column", flex: "1", height: "100%", style: getVariableStyle(), children: jsx(BoxStack, { id: "gx-hm-project-content", flexDirection: "column", flex: "1", children: jsx("div", { style: {
2044
3061
  minHeight: '100%',
@@ -2053,4 +3070,4 @@ const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
2053
3070
  }
2054
3071
  };
2055
3072
 
2056
- export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore };
3073
+ export { GraphView, HeatmapLayout, IClickType, IHeatmapType, IScrollType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapVizStore };