@gemx-dev/heatmap-react 3.5.92-dev.2 → 3.5.92-dev.20

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 (294) hide show
  1. package/dist/esm/components/Layout/HeatmapLayout.d.ts +2 -0
  2. package/dist/esm/components/Layout/HeatmapLayout.d.ts.map +1 -1
  3. package/dist/esm/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
  4. package/dist/esm/components/VizDom/VizDomRenderer.d.ts +2 -1
  5. package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  6. package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  7. package/dist/esm/hooks/common/index.d.ts +1 -1
  8. package/dist/esm/hooks/common/index.d.ts.map +1 -1
  9. package/dist/esm/hooks/common/useHeatmapViewportByDevice.d.ts +7 -0
  10. package/dist/esm/hooks/common/useHeatmapViewportByDevice.d.ts.map +1 -0
  11. package/dist/esm/hooks/register/useRegisterConfig.d.ts +3 -1
  12. package/dist/esm/hooks/register/useRegisterConfig.d.ts.map +1 -1
  13. package/dist/esm/hooks/view-context/index.d.ts +1 -0
  14. package/dist/esm/hooks/view-context/index.d.ts.map +1 -1
  15. package/dist/esm/hooks/view-context/useHeatmapCopyView.d.ts.map +1 -1
  16. package/dist/esm/hooks/view-context/useHeatmapDataContext.d.ts +4 -16
  17. package/dist/esm/hooks/view-context/useHeatmapDataContext.d.ts.map +1 -1
  18. package/dist/esm/hooks/view-context/useHeatmapLiveContext.d.ts +34 -0
  19. package/dist/esm/hooks/view-context/useHeatmapLiveContext.d.ts.map +1 -0
  20. package/dist/esm/hooks/view-context/useHeatmapSettingContext.d.ts +3 -1
  21. package/dist/esm/hooks/view-context/useHeatmapSettingContext.d.ts.map +1 -1
  22. package/dist/esm/hooks/view-context/useHeatmapVizContext.d.ts +2 -2
  23. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  24. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  25. package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -1
  26. package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
  27. package/dist/esm/hooks/viz-render/useHeatmapIframeProcessor.d.ts +6 -0
  28. package/dist/esm/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -0
  29. package/dist/esm/hooks/viz-render/useHeatmapRenderByMode.d.ts +3 -2
  30. package/dist/esm/hooks/viz-render/useHeatmapRenderByMode.d.ts.map +1 -1
  31. package/dist/esm/hooks/viz-render/useHeatmapRenderDom.d.ts +5 -0
  32. package/dist/esm/hooks/viz-render/useHeatmapRenderDom.d.ts.map +1 -0
  33. package/dist/esm/hooks/viz-render/useReplayRender.d.ts +2 -2
  34. package/dist/esm/hooks/viz-render/useReplayRender.d.ts.map +1 -1
  35. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  36. package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts +1 -2
  37. package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
  38. package/dist/esm/index.d.ts +1 -1
  39. package/dist/esm/index.d.ts.map +1 -1
  40. package/dist/esm/index.js +1823 -876
  41. package/dist/esm/index.mjs +1823 -876
  42. package/dist/esm/libs/iframe-processor/index.d.ts +2 -5
  43. package/dist/esm/libs/iframe-processor/index.d.ts.map +1 -1
  44. package/dist/esm/libs/iframe-processor/lifecycle.d.ts +15 -7
  45. package/dist/esm/libs/iframe-processor/lifecycle.d.ts.map +1 -1
  46. package/dist/esm/libs/iframe-processor/orchestrator.d.ts +13 -45
  47. package/dist/esm/libs/iframe-processor/orchestrator.d.ts.map +1 -1
  48. package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts +3 -14
  49. package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
  50. package/dist/esm/libs/iframe-processor/processors/height-observer/types.d.ts +9 -1
  51. package/dist/esm/libs/iframe-processor/processors/height-observer/types.d.ts.map +1 -1
  52. package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts +3 -14
  53. package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
  54. package/dist/esm/libs/iframe-processor/processors/navigation/listeners.d.ts +3 -4
  55. package/dist/esm/libs/iframe-processor/processors/navigation/listeners.d.ts.map +1 -1
  56. package/dist/esm/libs/iframe-processor/processors/navigation/types.d.ts +13 -0
  57. package/dist/esm/libs/iframe-processor/processors/navigation/types.d.ts.map +1 -1
  58. package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
  59. package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts.map +1 -1
  60. package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts +0 -1
  61. package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts.map +1 -1
  62. package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts +2 -2
  63. package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts +3 -9
  64. package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
  65. package/dist/esm/libs/iframe-processor/processors/viewport/listeners.d.ts +3 -2
  66. package/dist/esm/libs/iframe-processor/processors/viewport/listeners.d.ts.map +1 -1
  67. package/dist/esm/libs/iframe-processor/processors/viewport/pipeline.d.ts.map +1 -1
  68. package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts +2 -0
  69. package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts.map +1 -1
  70. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts +5 -0
  71. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts.map +1 -0
  72. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +11 -0
  73. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -0
  74. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts +9 -0
  75. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts.map +1 -0
  76. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +13 -0
  77. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -0
  78. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts +16 -0
  79. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts.map +1 -0
  80. package/dist/esm/libs/iframe-processor/processors/viewport/types.d.ts +8 -0
  81. package/dist/esm/libs/iframe-processor/processors/viewport/types.d.ts.map +1 -0
  82. package/dist/esm/libs/iframe-processor/shared/factory-types.d.ts +24 -0
  83. package/dist/esm/libs/iframe-processor/shared/factory-types.d.ts.map +1 -0
  84. package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts +20 -0
  85. package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -0
  86. package/dist/esm/libs/index.d.ts +1 -0
  87. package/dist/esm/libs/index.d.ts.map +1 -1
  88. package/dist/esm/libs/perf.d.ts +83 -0
  89. package/dist/esm/libs/perf.d.ts.map +1 -0
  90. package/dist/esm/libs/visualizer/GXVisualizer.d.ts +12 -4
  91. package/dist/esm/libs/visualizer/GXVisualizer.d.ts.map +1 -1
  92. package/dist/esm/libs/visualizer/cache/config.d.ts +15 -0
  93. package/dist/esm/libs/visualizer/cache/config.d.ts.map +1 -0
  94. package/dist/esm/libs/visualizer/cache/index.d.ts +16 -0
  95. package/dist/esm/libs/visualizer/cache/index.d.ts.map +1 -0
  96. package/dist/esm/libs/visualizer/index.d.ts +1 -2
  97. package/dist/esm/libs/visualizer/index.d.ts.map +1 -1
  98. package/dist/{umd/libs/visualizer → esm/libs/visualizer/renderers}/AttentionMapRenderer.d.ts +1 -1
  99. package/dist/esm/libs/visualizer/renderers/AttentionMapRenderer.d.ts.map +1 -0
  100. package/dist/esm/libs/visualizer/{ClickHeatmapRenderer.d.ts → renderers/ClickHeatmapRenderer.d.ts} +1 -1
  101. package/dist/esm/libs/visualizer/renderers/ClickHeatmapRenderer.d.ts.map +1 -0
  102. package/dist/esm/libs/visualizer/renderers/index.d.ts +3 -0
  103. package/dist/esm/libs/visualizer/renderers/index.d.ts.map +1 -0
  104. package/dist/esm/libs/visualizer/shadow-dom/extractor.d.ts +23 -0
  105. package/dist/esm/libs/visualizer/shadow-dom/extractor.d.ts.map +1 -0
  106. package/dist/esm/libs/visualizer/types/data.d.ts +72 -0
  107. package/dist/esm/libs/visualizer/types/data.d.ts.map +1 -0
  108. package/dist/esm/libs/visualizer/{types.d.ts → types/extend.d.ts} +7 -2
  109. package/dist/esm/libs/visualizer/types/extend.d.ts.map +1 -0
  110. package/dist/esm/libs/visualizer/types/index.d.ts +6 -0
  111. package/dist/esm/libs/visualizer/types/index.d.ts.map +1 -0
  112. package/dist/esm/libs/visualizer/types/layout.d.ts +69 -0
  113. package/dist/esm/libs/visualizer/types/layout.d.ts.map +1 -0
  114. package/dist/esm/libs/visualizer/types/visualize.d.ts +26 -0
  115. package/dist/esm/libs/visualizer/types/visualize.d.ts.map +1 -0
  116. package/dist/esm/libs/visualizer/utils/delay.d.ts +21 -0
  117. package/dist/esm/libs/visualizer/utils/delay.d.ts.map +1 -0
  118. package/dist/esm/libs/visualizer/utils/render.d.ts +7 -0
  119. package/dist/esm/libs/visualizer/utils/render.d.ts.map +1 -0
  120. package/dist/esm/stores/config.d.ts +4 -2
  121. package/dist/esm/stores/config.d.ts.map +1 -1
  122. package/dist/esm/stores/data.d.ts +4 -0
  123. package/dist/esm/stores/data.d.ts.map +1 -1
  124. package/dist/esm/stores/mode-live.d.ts +30 -16
  125. package/dist/esm/stores/mode-live.d.ts.map +1 -1
  126. package/dist/esm/stores/setting.d.ts +3 -1
  127. package/dist/esm/stores/setting.d.ts.map +1 -1
  128. package/dist/esm/stores/viz.d.ts +2 -2
  129. package/dist/esm/types/heatmap-info.d.ts +1 -0
  130. package/dist/esm/types/heatmap-info.d.ts.map +1 -1
  131. package/dist/esm/types/heatmap.d.ts +9 -0
  132. package/dist/esm/types/heatmap.d.ts.map +1 -1
  133. package/dist/esm/types/iframe-helper.d.ts +0 -19
  134. package/dist/esm/types/iframe-helper.d.ts.map +1 -1
  135. package/dist/umd/components/Layout/HeatmapLayout.d.ts +2 -0
  136. package/dist/umd/components/Layout/HeatmapLayout.d.ts.map +1 -1
  137. package/dist/umd/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
  138. package/dist/umd/components/VizDom/VizDomRenderer.d.ts +2 -1
  139. package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  140. package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  141. package/dist/umd/hooks/common/index.d.ts +1 -1
  142. package/dist/umd/hooks/common/index.d.ts.map +1 -1
  143. package/dist/umd/hooks/common/useHeatmapViewportByDevice.d.ts +7 -0
  144. package/dist/umd/hooks/common/useHeatmapViewportByDevice.d.ts.map +1 -0
  145. package/dist/umd/hooks/register/useRegisterConfig.d.ts +3 -1
  146. package/dist/umd/hooks/register/useRegisterConfig.d.ts.map +1 -1
  147. package/dist/umd/hooks/view-context/index.d.ts +1 -0
  148. package/dist/umd/hooks/view-context/index.d.ts.map +1 -1
  149. package/dist/umd/hooks/view-context/useHeatmapCopyView.d.ts.map +1 -1
  150. package/dist/umd/hooks/view-context/useHeatmapDataContext.d.ts +4 -16
  151. package/dist/umd/hooks/view-context/useHeatmapDataContext.d.ts.map +1 -1
  152. package/dist/umd/hooks/view-context/useHeatmapLiveContext.d.ts +34 -0
  153. package/dist/umd/hooks/view-context/useHeatmapLiveContext.d.ts.map +1 -0
  154. package/dist/umd/hooks/view-context/useHeatmapSettingContext.d.ts +3 -1
  155. package/dist/umd/hooks/view-context/useHeatmapSettingContext.d.ts.map +1 -1
  156. package/dist/umd/hooks/view-context/useHeatmapVizContext.d.ts +2 -2
  157. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  158. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  159. package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -1
  160. package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
  161. package/dist/umd/hooks/viz-render/useHeatmapIframeProcessor.d.ts +6 -0
  162. package/dist/umd/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -0
  163. package/dist/umd/hooks/viz-render/useHeatmapRenderByMode.d.ts +3 -2
  164. package/dist/umd/hooks/viz-render/useHeatmapRenderByMode.d.ts.map +1 -1
  165. package/dist/umd/hooks/viz-render/useHeatmapRenderDom.d.ts +5 -0
  166. package/dist/umd/hooks/viz-render/useHeatmapRenderDom.d.ts.map +1 -0
  167. package/dist/umd/hooks/viz-render/useReplayRender.d.ts +2 -2
  168. package/dist/umd/hooks/viz-render/useReplayRender.d.ts.map +1 -1
  169. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  170. package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts +1 -2
  171. package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
  172. package/dist/umd/index.d.ts +1 -1
  173. package/dist/umd/index.d.ts.map +1 -1
  174. package/dist/umd/index.js +2 -2
  175. package/dist/umd/libs/iframe-processor/index.d.ts +2 -5
  176. package/dist/umd/libs/iframe-processor/index.d.ts.map +1 -1
  177. package/dist/umd/libs/iframe-processor/lifecycle.d.ts +15 -7
  178. package/dist/umd/libs/iframe-processor/lifecycle.d.ts.map +1 -1
  179. package/dist/umd/libs/iframe-processor/orchestrator.d.ts +13 -45
  180. package/dist/umd/libs/iframe-processor/orchestrator.d.ts.map +1 -1
  181. package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts +3 -14
  182. package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
  183. package/dist/umd/libs/iframe-processor/processors/height-observer/types.d.ts +9 -1
  184. package/dist/umd/libs/iframe-processor/processors/height-observer/types.d.ts.map +1 -1
  185. package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts +3 -14
  186. package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
  187. package/dist/umd/libs/iframe-processor/processors/navigation/listeners.d.ts +3 -4
  188. package/dist/umd/libs/iframe-processor/processors/navigation/listeners.d.ts.map +1 -1
  189. package/dist/umd/libs/iframe-processor/processors/navigation/types.d.ts +13 -0
  190. package/dist/umd/libs/iframe-processor/processors/navigation/types.d.ts.map +1 -1
  191. package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
  192. package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts.map +1 -1
  193. package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts +0 -1
  194. package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts.map +1 -1
  195. package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts +2 -2
  196. package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts +3 -9
  197. package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
  198. package/dist/umd/libs/iframe-processor/processors/viewport/listeners.d.ts +3 -2
  199. package/dist/umd/libs/iframe-processor/processors/viewport/listeners.d.ts.map +1 -1
  200. package/dist/umd/libs/iframe-processor/processors/viewport/pipeline.d.ts.map +1 -1
  201. package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts +2 -0
  202. package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts.map +1 -1
  203. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts +5 -0
  204. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts.map +1 -0
  205. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +11 -0
  206. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -0
  207. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts +9 -0
  208. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts.map +1 -0
  209. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +13 -0
  210. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -0
  211. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts +16 -0
  212. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts.map +1 -0
  213. package/dist/umd/libs/iframe-processor/processors/viewport/types.d.ts +8 -0
  214. package/dist/umd/libs/iframe-processor/processors/viewport/types.d.ts.map +1 -0
  215. package/dist/umd/libs/iframe-processor/shared/factory-types.d.ts +24 -0
  216. package/dist/umd/libs/iframe-processor/shared/factory-types.d.ts.map +1 -0
  217. package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts +20 -0
  218. package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -0
  219. package/dist/umd/libs/index.d.ts +1 -0
  220. package/dist/umd/libs/index.d.ts.map +1 -1
  221. package/dist/umd/libs/perf.d.ts +83 -0
  222. package/dist/umd/libs/perf.d.ts.map +1 -0
  223. package/dist/umd/libs/visualizer/GXVisualizer.d.ts +12 -4
  224. package/dist/umd/libs/visualizer/GXVisualizer.d.ts.map +1 -1
  225. package/dist/umd/libs/visualizer/cache/config.d.ts +15 -0
  226. package/dist/umd/libs/visualizer/cache/config.d.ts.map +1 -0
  227. package/dist/umd/libs/visualizer/cache/index.d.ts +16 -0
  228. package/dist/umd/libs/visualizer/cache/index.d.ts.map +1 -0
  229. package/dist/umd/libs/visualizer/index.d.ts +1 -2
  230. package/dist/umd/libs/visualizer/index.d.ts.map +1 -1
  231. package/dist/{esm/libs/visualizer → umd/libs/visualizer/renderers}/AttentionMapRenderer.d.ts +1 -1
  232. package/dist/umd/libs/visualizer/renderers/AttentionMapRenderer.d.ts.map +1 -0
  233. package/dist/umd/libs/visualizer/{ClickHeatmapRenderer.d.ts → renderers/ClickHeatmapRenderer.d.ts} +1 -1
  234. package/dist/umd/libs/visualizer/renderers/ClickHeatmapRenderer.d.ts.map +1 -0
  235. package/dist/umd/libs/visualizer/renderers/index.d.ts +3 -0
  236. package/dist/umd/libs/visualizer/renderers/index.d.ts.map +1 -0
  237. package/dist/umd/libs/visualizer/shadow-dom/extractor.d.ts +23 -0
  238. package/dist/umd/libs/visualizer/shadow-dom/extractor.d.ts.map +1 -0
  239. package/dist/umd/libs/visualizer/types/data.d.ts +72 -0
  240. package/dist/umd/libs/visualizer/types/data.d.ts.map +1 -0
  241. package/dist/umd/libs/visualizer/{types.d.ts → types/extend.d.ts} +7 -2
  242. package/dist/umd/libs/visualizer/types/extend.d.ts.map +1 -0
  243. package/dist/umd/libs/visualizer/types/index.d.ts +6 -0
  244. package/dist/umd/libs/visualizer/types/index.d.ts.map +1 -0
  245. package/dist/umd/libs/visualizer/types/layout.d.ts +69 -0
  246. package/dist/umd/libs/visualizer/types/layout.d.ts.map +1 -0
  247. package/dist/umd/libs/visualizer/types/visualize.d.ts +26 -0
  248. package/dist/umd/libs/visualizer/types/visualize.d.ts.map +1 -0
  249. package/dist/umd/libs/visualizer/utils/delay.d.ts +21 -0
  250. package/dist/umd/libs/visualizer/utils/delay.d.ts.map +1 -0
  251. package/dist/umd/libs/visualizer/utils/render.d.ts +7 -0
  252. package/dist/umd/libs/visualizer/utils/render.d.ts.map +1 -0
  253. package/dist/umd/stores/config.d.ts +4 -2
  254. package/dist/umd/stores/config.d.ts.map +1 -1
  255. package/dist/umd/stores/data.d.ts +4 -0
  256. package/dist/umd/stores/data.d.ts.map +1 -1
  257. package/dist/umd/stores/mode-live.d.ts +30 -16
  258. package/dist/umd/stores/mode-live.d.ts.map +1 -1
  259. package/dist/umd/stores/setting.d.ts +3 -1
  260. package/dist/umd/stores/setting.d.ts.map +1 -1
  261. package/dist/umd/stores/viz.d.ts +2 -2
  262. package/dist/umd/types/heatmap-info.d.ts +1 -0
  263. package/dist/umd/types/heatmap-info.d.ts.map +1 -1
  264. package/dist/umd/types/heatmap.d.ts +9 -0
  265. package/dist/umd/types/heatmap.d.ts.map +1 -1
  266. package/dist/umd/types/iframe-helper.d.ts +0 -19
  267. package/dist/umd/types/iframe-helper.d.ts.map +1 -1
  268. package/package.json +4 -4
  269. package/dist/esm/hooks/common/useHeatmapWidthByDevice.d.ts +0 -2
  270. package/dist/esm/hooks/common/useHeatmapWidthByDevice.d.ts.map +0 -1
  271. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts +0 -6
  272. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +0 -1
  273. package/dist/esm/hooks/viz-scale/useContentDimensions.d.ts +0 -9
  274. package/dist/esm/hooks/viz-scale/useContentDimensions.d.ts.map +0 -1
  275. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer.d.ts +0 -54
  276. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer.d.ts.map +0 -1
  277. package/dist/esm/libs/visualizer/AttentionMapRenderer.d.ts.map +0 -1
  278. package/dist/esm/libs/visualizer/ClickHeatmapRenderer.d.ts.map +0 -1
  279. package/dist/esm/libs/visualizer/ScrollHeatmapRenderer.d.ts +0 -17
  280. package/dist/esm/libs/visualizer/ScrollHeatmapRenderer.d.ts.map +0 -1
  281. package/dist/esm/libs/visualizer/types.d.ts.map +0 -1
  282. package/dist/umd/hooks/common/useHeatmapWidthByDevice.d.ts +0 -2
  283. package/dist/umd/hooks/common/useHeatmapWidthByDevice.d.ts.map +0 -1
  284. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts +0 -6
  285. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +0 -1
  286. package/dist/umd/hooks/viz-scale/useContentDimensions.d.ts +0 -9
  287. package/dist/umd/hooks/viz-scale/useContentDimensions.d.ts.map +0 -1
  288. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer.d.ts +0 -54
  289. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer.d.ts.map +0 -1
  290. package/dist/umd/libs/visualizer/AttentionMapRenderer.d.ts.map +0 -1
  291. package/dist/umd/libs/visualizer/ClickHeatmapRenderer.d.ts.map +0 -1
  292. package/dist/umd/libs/visualizer/ScrollHeatmapRenderer.d.ts +0 -17
  293. package/dist/umd/libs/visualizer/ScrollHeatmapRenderer.d.ts.map +0 -1
  294. package/dist/umd/libs/visualizer/types.d.ts.map +0 -1
package/dist/esm/index.js CHANGED
@@ -152,6 +152,7 @@ function useDebounceCallback(callback, delay) {
152
152
 
153
153
  var EDeviceType;
154
154
  (function (EDeviceType) {
155
+ EDeviceType["DesktopLarge"] = "DESKTOP_LARGE";
155
156
  EDeviceType["Desktop"] = "DESKTOP";
156
157
  EDeviceType["Mobile"] = "MOBILE";
157
158
  EDeviceType["Tablet"] = "TABLET";
@@ -161,6 +162,11 @@ var EHeatmapType;
161
162
  EHeatmapType["Click"] = "click";
162
163
  EHeatmapType["Scroll"] = "scroll";
163
164
  })(EHeatmapType || (EHeatmapType = {}));
165
+ var EHeatmapMode;
166
+ (function (EHeatmapMode) {
167
+ EHeatmapMode["Heatmap"] = "heatmap";
168
+ EHeatmapMode["Replay"] = "replay";
169
+ })(EHeatmapMode || (EHeatmapMode = {}));
164
170
  var EClickType;
165
171
  (function (EClickType) {
166
172
  /** Return all clicks (default) */
@@ -197,12 +203,16 @@ var EScrollType;
197
203
  EScrollType["Attention"] = "ATTENTION";
198
204
  EScrollType["Revenue"] = "REVENUE";
199
205
  })(EScrollType || (EScrollType = {}));
200
- var EHeatmapMode;
201
206
  (function (EHeatmapMode) {
202
207
  EHeatmapMode["Single"] = "single";
203
208
  EHeatmapMode["Live"] = "live";
204
209
  EHeatmapMode["Compare"] = "compare";
205
210
  })(EHeatmapMode || (EHeatmapMode = {}));
211
+ var EHeatmapDataSource;
212
+ (function (EHeatmapDataSource) {
213
+ EHeatmapDataSource["Snapshot"] = "snapshot";
214
+ EHeatmapDataSource["Live"] = "live";
215
+ })(EHeatmapDataSource || (EHeatmapDataSource = {}));
206
216
 
207
217
  const ViewIdContext = createContext(undefined);
208
218
  const useViewIdContext = () => {
@@ -314,18 +324,21 @@ const useHeatmapConfigStore = create()((set) => {
314
324
  return {
315
325
  mode: EHeatmapMode.Single,
316
326
  sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
317
- clickMode: EClickMode.Default,
318
- isRendering: true,
327
+ shopId: undefined,
328
+ excludeClassNames: [],
319
329
  setMode: (mode) => set({ mode }),
320
330
  resetMode: () => set({ mode: EHeatmapMode.Single }),
321
331
  setSidebarWidth: (sidebarWidth) => set({ sidebarWidth }),
322
- setIsRendering: (isRendering) => set({ isRendering }),
332
+ setShopId: (shopId) => set({ shopId }),
333
+ setExcludeClassNames: (excludeClassNames) => set({ excludeClassNames }),
323
334
  };
324
335
  });
325
336
 
326
337
  const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
327
338
  return {
328
339
  data: new Map([[DEFAULT_VIEW_ID, undefined]]),
340
+ dataHash: new Map([[DEFAULT_VIEW_ID, undefined]]),
341
+ dataSnapshot: new Map([[DEFAULT_VIEW_ID, undefined]]),
329
342
  clickmap: new Map([[DEFAULT_VIEW_ID, undefined]]),
330
343
  clickAreas: new Map([[DEFAULT_VIEW_ID, undefined]]),
331
344
  dataInfo: new Map([[DEFAULT_VIEW_ID, undefined]]),
@@ -358,6 +371,16 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
358
371
  newData.set(viewId, data);
359
372
  return { data: newData };
360
373
  }),
374
+ setDataHash: (dataHash, viewId = DEFAULT_VIEW_ID) => set((prev) => {
375
+ const newDataHash = new Map(prev.dataHash);
376
+ newDataHash.set(viewId, dataHash);
377
+ return { dataHash: newDataHash };
378
+ }),
379
+ setDataSnapshot: (data, viewId = DEFAULT_VIEW_ID) => set((prev) => {
380
+ const newDataSnapshot = new Map(prev.dataSnapshot);
381
+ newDataSnapshot.set(viewId, data);
382
+ return { dataSnapshot: newDataSnapshot };
383
+ }),
361
384
  setClickmap: (clickmap, viewId = DEFAULT_VIEW_ID) => set((prev) => {
362
385
  const newClickmap = new Map(prev.clickmap);
363
386
  newClickmap.set(viewId, clickmap);
@@ -380,12 +403,16 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
380
403
  }),
381
404
  copyView: (fromViewId, toViewId) => set((prev) => {
382
405
  const newData = new Map(prev.data);
406
+ const newDataSnapshot = new Map(prev.dataSnapshot);
383
407
  const newClickmap = new Map(prev.clickmap);
384
408
  const newClickAreas = new Map(prev.clickAreas);
385
409
  const newDataInfo = new Map(prev.dataInfo);
386
410
  const newScrollmap = new Map(prev.scrollmap);
387
411
  const newAttentionMap = new Map(prev.attentionMap);
412
+ const newDataHash = new Map(prev.dataHash);
388
413
  newData.set(toViewId, prev.data.get(fromViewId));
414
+ newDataSnapshot.set(toViewId, prev.dataSnapshot.get(fromViewId));
415
+ newDataHash.set(toViewId, prev.dataHash.get(fromViewId));
389
416
  newClickmap.set(toViewId, prev.clickmap.get(fromViewId));
390
417
  newClickAreas.set(toViewId, prev.clickAreas.get(fromViewId));
391
418
  newDataInfo.set(toViewId, prev.dataInfo.get(fromViewId));
@@ -393,21 +420,27 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
393
420
  newAttentionMap.set(toViewId, prev.attentionMap.get(fromViewId));
394
421
  return {
395
422
  data: newData,
423
+ dataSnapshot: newDataSnapshot,
396
424
  clickmap: newClickmap,
397
425
  clickAreas: newClickAreas,
398
426
  dataInfo: newDataInfo,
399
427
  scrollmap: newScrollmap,
400
428
  attentionMap: newAttentionMap,
429
+ dataHash: newDataHash,
401
430
  };
402
431
  }),
403
432
  clearView: (viewId) => set((prev) => {
404
433
  const newData = new Map(prev.data);
434
+ const newDataSnapshot = new Map(prev.dataSnapshot);
405
435
  const newClickmap = new Map(prev.clickmap);
406
436
  const newClickAreas = new Map(prev.clickAreas);
407
437
  const newDataInfo = new Map(prev.dataInfo);
408
438
  const newScrollmap = new Map(prev.scrollmap);
409
439
  const newAttentionMap = new Map(prev.attentionMap);
440
+ const newDataHash = new Map(prev.dataHash);
410
441
  newData.delete(viewId);
442
+ newDataSnapshot.delete(viewId);
443
+ newDataHash.delete(viewId);
411
444
  newClickmap.delete(viewId);
412
445
  newClickAreas.delete(viewId);
413
446
  newDataInfo.delete(viewId);
@@ -415,6 +448,8 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
415
448
  newAttentionMap.delete(viewId);
416
449
  return {
417
450
  data: newData,
451
+ dataSnapshot: newDataSnapshot,
452
+ dataHash: newDataHash,
418
453
  clickmap: newClickmap,
419
454
  clickAreas: newClickAreas,
420
455
  dataInfo: newDataInfo,
@@ -424,6 +459,8 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
424
459
  }),
425
460
  resetAll: () => set({
426
461
  data: new Map([[DEFAULT_VIEW_ID, undefined]]),
462
+ dataSnapshot: new Map([[DEFAULT_VIEW_ID, undefined]]),
463
+ dataHash: new Map([[DEFAULT_VIEW_ID, undefined]]),
427
464
  clickmap: new Map([[DEFAULT_VIEW_ID, undefined]]),
428
465
  clickAreas: new Map([[DEFAULT_VIEW_ID, undefined]]),
429
466
  dataInfo: new Map([[DEFAULT_VIEW_ID, undefined]]),
@@ -445,6 +482,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
445
482
  clickMode: new Map([[DEFAULT_VIEW_ID, EClickMode.Default]]),
446
483
  scrollType: new Map([[DEFAULT_VIEW_ID, EScrollType.Depth]]),
447
484
  heatmapType: new Map([[DEFAULT_VIEW_ID, EHeatmapType.Click]]),
485
+ dataSource: new Map([[DEFAULT_VIEW_ID, EHeatmapDataSource.Snapshot]]),
448
486
  setIsRendering: (isRendering, viewId = DEFAULT_VIEW_ID) => set((prev) => {
449
487
  const newIsRendering = new Map(prev.isRendering);
450
488
  newIsRendering.set(viewId, isRendering);
@@ -495,6 +533,11 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
495
533
  newHeatmapType.set(viewId, heatmapType);
496
534
  return { heatmapType: newHeatmapType };
497
535
  }),
536
+ setDataSource: (dataSource, viewId = DEFAULT_VIEW_ID) => set((prev) => {
537
+ const newDataSource = new Map(prev.dataSource);
538
+ newDataSource.set(viewId, dataSource);
539
+ return { dataSource: newDataSource };
540
+ }),
498
541
  copyView: (fromViewId, toViewId) => set((prev) => {
499
542
  const newIsLoadingDom = new Map(prev.isLoadingDom);
500
543
  const newIsLoadingCanvas = new Map(prev.isLoadingCanvas);
@@ -505,6 +548,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
505
548
  const newClickMode = new Map(prev.clickMode);
506
549
  const newScrollType = new Map(prev.scrollType);
507
550
  const newHeatmapType = new Map(prev.heatmapType);
551
+ const newDataSource = new Map(prev.dataSource);
508
552
  newIsShowSidebar.set(toViewId, prev.isShowSidebar.get(fromViewId) ?? false);
509
553
  newRankedBy.set(toViewId, prev.rankedBy.get(fromViewId));
510
554
  newDeviceType.set(toViewId, prev.deviceType.get(fromViewId));
@@ -514,6 +558,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
514
558
  newHeatmapType.set(toViewId, prev.heatmapType.get(fromViewId));
515
559
  newIsLoadingDom.set(toViewId, prev.isLoadingDom.get(fromViewId) ?? false);
516
560
  newIsLoadingCanvas.set(toViewId, prev.isLoadingCanvas.get(fromViewId) ?? false);
561
+ newDataSource.set(toViewId, prev.dataSource.get(fromViewId) ?? EHeatmapDataSource.Snapshot);
517
562
  return {
518
563
  isShowSidebar: newIsShowSidebar,
519
564
  rankedBy: newRankedBy,
@@ -524,6 +569,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
524
569
  clickMode: newClickMode,
525
570
  scrollType: newScrollType,
526
571
  heatmapType: newHeatmapType,
572
+ dataSource: newDataSource,
527
573
  };
528
574
  }),
529
575
  clearView: (viewId) => set((prev) => {
@@ -536,6 +582,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
536
582
  const newClickMode = new Map(prev.clickMode);
537
583
  const newScrollType = new Map(prev.scrollType);
538
584
  const newHeatmapType = new Map(prev.heatmapType);
585
+ const newDataSource = new Map(prev.dataSource);
539
586
  newIsShowSidebar.delete(viewId);
540
587
  newRankedBy.delete(viewId);
541
588
  newIsLoadingDom.delete(viewId);
@@ -545,6 +592,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
545
592
  newClickMode.delete(viewId);
546
593
  newScrollType.delete(viewId);
547
594
  newHeatmapType.delete(viewId);
595
+ newDataSource.delete(viewId);
548
596
  return {
549
597
  isShowSidebar: newIsShowSidebar,
550
598
  rankedBy: newRankedBy,
@@ -555,6 +603,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
555
603
  clickMode: newClickMode,
556
604
  scrollType: newScrollType,
557
605
  heatmapType: newHeatmapType,
606
+ dataSource: newDataSource,
558
607
  };
559
608
  }),
560
609
  resetAll: () => set({
@@ -568,22 +617,23 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
568
617
  clickMode: new Map([[DEFAULT_VIEW_ID, EClickMode.Default]]),
569
618
  scrollType: new Map([[DEFAULT_VIEW_ID, EScrollType.Depth]]),
570
619
  heatmapType: new Map([[DEFAULT_VIEW_ID, EHeatmapType.Click]]),
620
+ dataSource: new Map([[DEFAULT_VIEW_ID, EHeatmapDataSource.Snapshot]]),
571
621
  }),
572
622
  };
573
623
  }));
574
624
 
575
625
  const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
576
626
  return {
577
- isRenderViz: new Map([[DEFAULT_VIEW_ID, false]]),
627
+ isDomLoaded: new Map([[DEFAULT_VIEW_ID, false]]),
578
628
  zoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.DEFAULT]]),
579
629
  minZoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.MIN]]),
580
630
  maxZoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.MAX]]),
581
631
  scale: new Map([[DEFAULT_VIEW_ID, 1]]),
582
632
  isScaledToFit: new Map([[DEFAULT_VIEW_ID, false]]),
583
- setIsRenderViz: (isRenderViz, viewId = DEFAULT_VIEW_ID) => set((prev) => {
584
- const newIsRenderViz = new Map(prev.isRenderViz);
585
- newIsRenderViz.set(viewId, isRenderViz);
586
- return { isRenderViz: newIsRenderViz };
633
+ setIsDomLoaded: (isDomLoaded, viewId = DEFAULT_VIEW_ID) => set((prev) => {
634
+ const newIsDomLoaded = new Map(prev.isDomLoaded);
635
+ newIsDomLoaded.set(viewId, isDomLoaded);
636
+ return { isDomLoaded: newIsDomLoaded };
587
637
  }),
588
638
  setZoomRatio: (zoomRatio, viewId = DEFAULT_VIEW_ID) => set((prev) => {
589
639
  const newZoomRatio = new Map(prev.zoomRatio);
@@ -611,18 +661,18 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
611
661
  return { isScaledToFit: newIsScaledToFit };
612
662
  }),
613
663
  copyView: (fromViewId, toViewId) => set((prev) => {
614
- const newIsRenderViz = new Map(prev.isRenderViz);
664
+ const newIsDomLoaded = new Map(prev.isDomLoaded);
615
665
  const newZoomRatio = new Map(prev.zoomRatio);
616
666
  const newMinZoomRatio = new Map(prev.minZoomRatio);
617
667
  const newScale = new Map(prev.scale);
618
668
  const newIsScaledToFit = new Map(prev.isScaledToFit);
619
- newIsRenderViz.set(toViewId, prev.isRenderViz.get(fromViewId) ?? false);
669
+ newIsDomLoaded.set(toViewId, prev.isDomLoaded.get(fromViewId) ?? false);
620
670
  newZoomRatio.set(toViewId, prev.zoomRatio.get(fromViewId) ?? 100);
621
671
  newMinZoomRatio.set(toViewId, prev.minZoomRatio.get(fromViewId) ?? 10);
622
672
  newScale.set(toViewId, prev.scale.get(fromViewId) ?? 1);
623
673
  newIsScaledToFit.set(toViewId, prev.isScaledToFit.get(fromViewId) ?? false);
624
674
  return {
625
- isRenderViz: newIsRenderViz,
675
+ isDomLoaded: newIsDomLoaded,
626
676
  zoomRatio: newZoomRatio,
627
677
  minZoomRatio: newMinZoomRatio,
628
678
  scale: newScale,
@@ -630,18 +680,18 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
630
680
  };
631
681
  }),
632
682
  clearView: (viewId) => set((prev) => {
633
- const newIsRenderViz = new Map(prev.isRenderViz);
683
+ const newIsDomLoaded = new Map(prev.isDomLoaded);
634
684
  const newZoomRatio = new Map(prev.zoomRatio);
635
685
  const newMinZoomRatio = new Map(prev.minZoomRatio);
636
686
  const newScale = new Map(prev.scale);
637
687
  const newIsScaledToFit = new Map(prev.isScaledToFit);
638
- newIsRenderViz.delete(viewId);
688
+ newIsDomLoaded.delete(viewId);
639
689
  newZoomRatio.delete(viewId);
640
690
  newMinZoomRatio.delete(viewId);
641
691
  newScale.delete(viewId);
642
692
  newIsScaledToFit.delete(viewId);
643
693
  return {
644
- isRenderViz: newIsRenderViz,
694
+ isDomLoaded: newIsDomLoaded,
645
695
  zoomRatio: newZoomRatio,
646
696
  minZoomRatio: newMinZoomRatio,
647
697
  scale: newScale,
@@ -649,7 +699,7 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
649
699
  };
650
700
  }),
651
701
  resetAll: () => set({
652
- isRenderViz: new Map([[DEFAULT_VIEW_ID, false]]),
702
+ isDomLoaded: new Map([[DEFAULT_VIEW_ID, false]]),
653
703
  zoomRatio: new Map([[DEFAULT_VIEW_ID, 100]]),
654
704
  minZoomRatio: new Map([[DEFAULT_VIEW_ID, 10]]),
655
705
  scale: new Map([[DEFAULT_VIEW_ID, 1]]),
@@ -1047,24 +1097,108 @@ const useHeatmapCompareStore = create()((set, get) => {
1047
1097
  });
1048
1098
 
1049
1099
  const initialState = {
1050
- payloads: [],
1051
- htmlContent: '',
1052
- targetUrl: '',
1053
- renderMode: 'portal',
1054
- storefrontPassword: '',
1055
- };
1056
- const useHeatmapLiveStore = create()((set) => {
1057
- return {
1058
- ...initialState,
1059
- reset: () => set(initialState),
1060
- setPayloads: (payloads) => set({ payloads }),
1061
- addPayload: (payload) => set((state) => ({ payloads: [...state.payloads, payload] })),
1062
- setHtmlContent: (htmlContent) => set({ htmlContent }),
1063
- setTargetUrl: (targetUrl) => set({ targetUrl }),
1064
- setRenderMode: (renderMode) => set({ renderMode }),
1065
- setStorefrontPassword: (storefrontPassword) => set({ storefrontPassword }),
1066
- };
1067
- });
1100
+ decodedPayloads: new Map([[DEFAULT_VIEW_ID, []]]),
1101
+ encodedPayloads: new Map([[DEFAULT_VIEW_ID, []]]),
1102
+ htmlContent: new Map([[DEFAULT_VIEW_ID, '']]),
1103
+ targetUrl: new Map([[DEFAULT_VIEW_ID, '']]),
1104
+ renderMode: new Map([[DEFAULT_VIEW_ID, 'portal']]),
1105
+ storefrontPassword: new Map([[DEFAULT_VIEW_ID, '']]),
1106
+ };
1107
+ const useHeatmapLiveStore = create()(subscribeWithSelector((set) => ({
1108
+ ...initialState,
1109
+ addPayload: (payload, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1110
+ const newDecoded = new Map(prev.decodedPayloads);
1111
+ newDecoded.set(viewId, [...(newDecoded.get(viewId) ?? []), payload]);
1112
+ const newEncoded = new Map(prev.encodedPayloads);
1113
+ newEncoded.set(viewId, [...(newEncoded.get(viewId) ?? []), JSON.stringify(payload)]);
1114
+ return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
1115
+ }),
1116
+ setPayloads: (payloads, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1117
+ const newDecoded = new Map(prev.decodedPayloads);
1118
+ newDecoded.set(viewId, payloads);
1119
+ const newEncoded = new Map(prev.encodedPayloads);
1120
+ newEncoded.set(viewId, payloads.map((p) => JSON.stringify(p)));
1121
+ return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
1122
+ }),
1123
+ setEncodedPayloads: (payloads, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1124
+ const newEncoded = new Map(prev.encodedPayloads);
1125
+ newEncoded.set(viewId, payloads);
1126
+ return { encodedPayloads: newEncoded };
1127
+ }),
1128
+ setHtmlContent: (htmlContent, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1129
+ const newHtmlContent = new Map(prev.htmlContent);
1130
+ newHtmlContent.set(viewId, htmlContent);
1131
+ return { htmlContent: newHtmlContent };
1132
+ }),
1133
+ setTargetUrl: (targetUrl, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1134
+ const newTargetUrl = new Map(prev.targetUrl);
1135
+ newTargetUrl.set(viewId, targetUrl);
1136
+ return { targetUrl: newTargetUrl };
1137
+ }),
1138
+ setRenderMode: (renderMode, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1139
+ const newRenderMode = new Map(prev.renderMode);
1140
+ newRenderMode.set(viewId, renderMode);
1141
+ return { renderMode: newRenderMode };
1142
+ }),
1143
+ setStorefrontPassword: (storefrontPassword, viewId = DEFAULT_VIEW_ID) => set((prev) => {
1144
+ const newStorefrontPassword = new Map(prev.storefrontPassword);
1145
+ newStorefrontPassword.set(viewId, storefrontPassword);
1146
+ return { storefrontPassword: newStorefrontPassword };
1147
+ }),
1148
+ resetView: (viewId = DEFAULT_VIEW_ID) => set((prev) => {
1149
+ const newDecoded = new Map(prev.decodedPayloads);
1150
+ newDecoded.set(viewId, []);
1151
+ const newEncoded = new Map(prev.encodedPayloads);
1152
+ newEncoded.set(viewId, []);
1153
+ return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
1154
+ }),
1155
+ copyView: (fromViewId, toViewId) => set((prev) => {
1156
+ const newDecoded = new Map(prev.decodedPayloads);
1157
+ const newEncoded = new Map(prev.encodedPayloads);
1158
+ const newHtmlContent = new Map(prev.htmlContent);
1159
+ const newTargetUrl = new Map(prev.targetUrl);
1160
+ const newRenderMode = new Map(prev.renderMode);
1161
+ const newStorefrontPassword = new Map(prev.storefrontPassword);
1162
+ newDecoded.set(toViewId, prev.decodedPayloads.get(fromViewId) ?? []);
1163
+ newEncoded.set(toViewId, prev.encodedPayloads.get(fromViewId) ?? []);
1164
+ newHtmlContent.set(toViewId, prev.htmlContent.get(fromViewId) ?? '');
1165
+ newTargetUrl.set(toViewId, prev.targetUrl.get(fromViewId) ?? '');
1166
+ newRenderMode.set(toViewId, prev.renderMode.get(fromViewId) ?? 'portal');
1167
+ newStorefrontPassword.set(toViewId, prev.storefrontPassword.get(fromViewId) ?? '');
1168
+ return {
1169
+ decodedPayloads: newDecoded,
1170
+ encodedPayloads: newEncoded,
1171
+ htmlContent: newHtmlContent,
1172
+ targetUrl: newTargetUrl,
1173
+ renderMode: newRenderMode,
1174
+ storefrontPassword: newStorefrontPassword,
1175
+ };
1176
+ }),
1177
+ clearView: (viewId) => set((prev) => {
1178
+ const newDecoded = new Map(prev.decodedPayloads);
1179
+ const newEncoded = new Map(prev.encodedPayloads);
1180
+ const newHtmlContent = new Map(prev.htmlContent);
1181
+ const newTargetUrl = new Map(prev.targetUrl);
1182
+ const newRenderMode = new Map(prev.renderMode);
1183
+ const newStorefrontPassword = new Map(prev.storefrontPassword);
1184
+ newDecoded.delete(viewId);
1185
+ newEncoded.delete(viewId);
1186
+ newHtmlContent.delete(viewId);
1187
+ newTargetUrl.delete(viewId);
1188
+ newRenderMode.delete(viewId);
1189
+ newStorefrontPassword.delete(viewId);
1190
+ return {
1191
+ decodedPayloads: newDecoded,
1192
+ encodedPayloads: newEncoded,
1193
+ htmlContent: newHtmlContent,
1194
+ targetUrl: newTargetUrl,
1195
+ renderMode: newRenderMode,
1196
+ storefrontPassword: newStorefrontPassword,
1197
+ };
1198
+ }),
1199
+ resetAll: () => set(initialState),
1200
+ reset: () => set(initialState),
1201
+ })));
1068
1202
 
1069
1203
  const useHeatmapVizRectStore = create()(subscribeWithSelector((set) => {
1070
1204
  return {
@@ -1170,26 +1304,12 @@ const useHeatmapClickContext = createViewContextHook({
1170
1304
  }),
1171
1305
  });
1172
1306
 
1173
- /**
1174
- * Hook to access heatmap data state and actions with optional selector
1175
- *
1176
- * @example
1177
- * ```tsx
1178
- * // Get everything
1179
- * const { data, clickmap, setData } = useHeatmapDataContext();
1180
- *
1181
- * // Get only what you need (no unnecessary re-renders)
1182
- * const data = useHeatmapDataContext(s => s.data);
1183
- * const { setData, setClickmap } = useHeatmapDataContext(s => ({
1184
- * setData: s.setData,
1185
- * setClickmap: s.setClickmap,
1186
- * }));
1187
- * ```
1188
- */
1189
1307
  const useHeatmapDataContext = createViewContextHook({
1190
1308
  useStore: useHeatmapDataStore,
1191
1309
  getState: (store, viewId) => ({
1192
1310
  data: store.data.get(viewId),
1311
+ dataHash: store.dataHash.get(viewId),
1312
+ dataSnapshot: store.dataSnapshot.get(viewId),
1193
1313
  clickmap: store.clickmap.get(viewId),
1194
1314
  clickAreas: store.clickAreas.get(viewId),
1195
1315
  scrollmap: store.scrollmap.get(viewId),
@@ -1199,6 +1319,8 @@ const useHeatmapDataContext = createViewContextHook({
1199
1319
  }),
1200
1320
  getActions: (store, viewId) => ({
1201
1321
  setData: (newData) => store.setData(newData, viewId),
1322
+ setDataSnapshot: (newData) => store.setDataSnapshot(newData, viewId),
1323
+ setDataHash: (newHash) => store.setDataHash(newHash, viewId),
1202
1324
  setClickmap: (newClickmap) => store.setClickmap(newClickmap, viewId),
1203
1325
  setClickAreas: (newClickAreas) => store.setClickAreas(newClickAreas, viewId),
1204
1326
  setDataInfoByKey: (key, value) => store.setDataInfoByKey(key, value, viewId),
@@ -1221,6 +1343,32 @@ const useHeatmapHoverContext = createViewContextHook({
1221
1343
  }),
1222
1344
  });
1223
1345
 
1346
+ const useHeatmapLiveContext = createViewContextHook({
1347
+ useStore: useHeatmapLiveStore,
1348
+ getState: (store, viewId) => ({
1349
+ decodedPayloads: store.decodedPayloads.get(viewId) ?? [],
1350
+ encodedPayloads: store.encodedPayloads.get(viewId) ?? [],
1351
+ htmlContent: store.htmlContent.get(viewId) ?? '',
1352
+ targetUrl: store.targetUrl.get(viewId) ?? '',
1353
+ renderMode: store.renderMode.get(viewId) ?? 'portal',
1354
+ storefrontPassword: store.storefrontPassword.get(viewId) ?? '',
1355
+ }),
1356
+ getActions: (store, viewId) => ({
1357
+ addPayload: (payload) => store.addPayload(payload, viewId),
1358
+ setPayloads: (payloads) => store.setPayloads(payloads, viewId),
1359
+ setEncodedPayloads: (payloads) => store.setEncodedPayloads(payloads, viewId),
1360
+ setHtmlContent: (htmlContent) => store.setHtmlContent(htmlContent, viewId),
1361
+ setTargetUrl: (targetUrl) => store.setTargetUrl(targetUrl, viewId),
1362
+ setRenderMode: (mode) => store.setRenderMode(mode, viewId),
1363
+ setStorefrontPassword: (password) => store.setStorefrontPassword(password, viewId),
1364
+ resetView: () => store.resetView(viewId),
1365
+ copyView: (fromViewId, toViewId) => store.copyView(fromViewId, toViewId),
1366
+ clearView: (viewId) => store.clearView(viewId),
1367
+ resetAll: () => store.resetAll(),
1368
+ reset: () => store.reset(),
1369
+ }),
1370
+ });
1371
+
1224
1372
  const useHeatmapScrollContext = createViewContextHook({
1225
1373
  useStore: useHeatmapVizScrollStore,
1226
1374
  getState: (store, viewId) => ({
@@ -1250,6 +1398,7 @@ const useHeatmapSettingContext = createViewContextHook({
1250
1398
  clickMode: store.clickMode.get(viewId),
1251
1399
  scrollType: store.scrollType.get(viewId),
1252
1400
  heatmapType: store.heatmapType.get(viewId),
1401
+ dataSource: store.dataSource.get(viewId) ?? EHeatmapDataSource.Snapshot,
1253
1402
  }),
1254
1403
  getActions: (store, viewId) => ({
1255
1404
  setIsShowSidebar: (isShowSidebar) => store.setIsShowSidebar(isShowSidebar, viewId),
@@ -1262,6 +1411,7 @@ const useHeatmapSettingContext = createViewContextHook({
1262
1411
  setIsRendering: (isRendering) => store.setIsRendering(isRendering, viewId),
1263
1412
  setIsLoadingDom: (isLoadingDom) => store.setIsLoadingDom(isLoadingDom, viewId),
1264
1413
  setIsLoadingCanvas: (isLoadingCanvas) => store.setIsLoadingCanvas(isLoadingCanvas, viewId),
1414
+ setDataSource: (dataSource) => store.setDataSource(dataSource, viewId),
1265
1415
  clearView: (viewId) => store.clearView(viewId),
1266
1416
  }),
1267
1417
  });
@@ -1269,7 +1419,7 @@ const useHeatmapSettingContext = createViewContextHook({
1269
1419
  const useHeatmapVizContext = createViewContextHook({
1270
1420
  useStore: useHeatmapVizStore,
1271
1421
  getState: (store, viewId) => ({
1272
- isRenderViz: store.isRenderViz.get(viewId) ?? false,
1422
+ isDomLoaded: store.isDomLoaded.get(viewId) ?? false,
1273
1423
  zoomRatio: store.zoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.DEFAULT,
1274
1424
  minZoomRatio: store.minZoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.MIN,
1275
1425
  maxZoomRatio: store.maxZoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.MAX,
@@ -1277,7 +1427,7 @@ const useHeatmapVizContext = createViewContextHook({
1277
1427
  isScaledToFit: store.isScaledToFit.get(viewId) ?? false,
1278
1428
  }),
1279
1429
  getActions: (store, viewId) => ({
1280
- setIsRenderViz: (value) => store.setIsRenderViz(value, viewId),
1430
+ setIsDomLoaded: (value) => store.setIsDomLoaded(value, viewId),
1281
1431
  setZoomRatio: (value) => store.setZoomRatio(value, viewId),
1282
1432
  setMinZoomRatio: (value) => store.setMinZoomRatio(value, viewId),
1283
1433
  setMaxZoomRatio: (value) => store.setMaxZoomRatio(value, viewId),
@@ -1311,9 +1461,7 @@ const useHeatmapCopyView = () => {
1311
1461
  const copyVizView = useHeatmapVizStore((state) => state.copyView);
1312
1462
  const copyVizClickView = useHeatmapVizClickStore((state) => state.copyView);
1313
1463
  const copyVizAreaClickView = useHeatmapVizClickAreaStore((state) => state.copyView);
1314
- // const copyVizRectView = useHeatmapVizRectStore((state) => state.copyView);
1315
- // const copyVizHoverView = useHeatmapVizHoverStore((state) => state.copyView);
1316
- // const copyVizScrollView = useHeatmapVizScrollStore((state) => state.copyView);
1464
+ const copyLiveView = useHeatmapLiveStore((state) => state.copyView);
1317
1465
  const clearDataView = useHeatmapDataStore((state) => state.clearView);
1318
1466
  const clearSettingView = useHeatmapSettingStore((state) => state.clearView);
1319
1467
  const clearVizView = useHeatmapVizStore((state) => state.clearView);
@@ -1322,6 +1470,7 @@ const useHeatmapCopyView = () => {
1322
1470
  const clearVizHoverView = useHeatmapVizHoverStore((state) => state.clearView);
1323
1471
  const clearVizScrollView = useHeatmapVizScrollStore((state) => state.clearView);
1324
1472
  const clearVizAreaClickView = useHeatmapVizClickAreaStore((state) => state.clearView);
1473
+ const clearLiveView = useHeatmapLiveStore((state) => state.clearView);
1325
1474
  const resetDataAll = useHeatmapDataStore((state) => state.resetAll);
1326
1475
  const resetSettingAll = useHeatmapSettingStore((state) => state.resetAll);
1327
1476
  const resetVizAll = useHeatmapVizStore((state) => state.resetAll);
@@ -1330,15 +1479,14 @@ const useHeatmapCopyView = () => {
1330
1479
  const resetVizHoverAll = useHeatmapVizHoverStore((state) => state.resetAll);
1331
1480
  const resetVizScrollViewAll = useHeatmapVizScrollStore((state) => state.resetAll);
1332
1481
  const resetVizClickAreaAll = useHeatmapVizClickAreaStore((state) => state.resetAll);
1482
+ const resetLiveAll = useHeatmapLiveStore((state) => state.resetAll);
1333
1483
  const copyView = (fromViewId, toViewId) => {
1334
1484
  copyDataView(fromViewId, toViewId);
1335
1485
  copySettingView(fromViewId, toViewId);
1336
1486
  copyVizView(fromViewId, toViewId);
1337
- // copyVizRectView(fromViewId, toViewId);
1338
1487
  copyVizClickView(fromViewId, toViewId);
1339
- // copyVizHoverView(fromViewId, toViewId);
1340
- // copyVizScrollView(fromViewId, toViewId);
1341
1488
  copyVizAreaClickView(fromViewId, toViewId);
1489
+ copyLiveView(fromViewId, toViewId);
1342
1490
  };
1343
1491
  const copyViewToMultiple = (fromViewId, toViewIds) => {
1344
1492
  toViewIds.forEach((toViewId) => {
@@ -1354,6 +1502,7 @@ const useHeatmapCopyView = () => {
1354
1502
  clearVizHoverView(viewId);
1355
1503
  clearVizScrollView(viewId);
1356
1504
  clearVizAreaClickView(viewId);
1505
+ clearLiveView(viewId);
1357
1506
  };
1358
1507
  const clearMultipleViews = (viewIds) => {
1359
1508
  viewIds.forEach((viewId) => {
@@ -1369,6 +1518,7 @@ const useHeatmapCopyView = () => {
1369
1518
  resetVizHoverAll();
1370
1519
  resetVizScrollViewAll();
1371
1520
  resetVizClickAreaAll();
1521
+ resetLiveAll();
1372
1522
  };
1373
1523
  return {
1374
1524
  copyView,
@@ -1379,14 +1529,17 @@ const useHeatmapCopyView = () => {
1379
1529
  };
1380
1530
  };
1381
1531
 
1382
- const useHeatmapWidthByDevice = () => {
1532
+ const useHeatmapViewportByDevice = () => {
1383
1533
  const deviceType = useHeatmapSettingContext((state) => state.deviceType);
1384
1534
  const width = useMemo(() => calcWidthByDeviceType(deviceType), [deviceType]);
1385
- return width;
1535
+ const height = useMemo(() => calcHeightByDeviceType(deviceType), [deviceType]);
1536
+ return { width, height };
1386
1537
  function calcWidthByDeviceType(deviceType) {
1387
1538
  if (!deviceType)
1388
1539
  return 1440;
1389
1540
  switch (deviceType) {
1541
+ case EDeviceType.DesktopLarge:
1542
+ return 1920;
1390
1543
  case EDeviceType.Desktop:
1391
1544
  return 1440;
1392
1545
  case EDeviceType.Tablet:
@@ -1395,20 +1548,45 @@ const useHeatmapWidthByDevice = () => {
1395
1548
  return 375;
1396
1549
  }
1397
1550
  }
1551
+ function calcHeightByDeviceType(deviceType) {
1552
+ if (!deviceType)
1553
+ return 900;
1554
+ switch (deviceType) {
1555
+ case EDeviceType.DesktopLarge:
1556
+ return 1080; // 1920×1080
1557
+ case EDeviceType.Desktop:
1558
+ return 900; // 1440×900
1559
+ case EDeviceType.Tablet:
1560
+ return 1024; // 768×1024 (iPad portrait)
1561
+ case EDeviceType.Mobile:
1562
+ return 812; // 375×812 (iPhone X/11/12/13)
1563
+ }
1564
+ }
1398
1565
  };
1399
1566
 
1400
- const useRegisterConfig = ({ isLoading, isLoadingCanvas, }) => {
1567
+ const useRegisterConfig = ({ shopId, isLoading, isLoadingCanvas, excludeClassNames, }) => {
1401
1568
  const mode = useHeatmapConfigStore((state) => state.mode);
1569
+ const shopIdStore = useHeatmapConfigStore((state) => state.shopId);
1402
1570
  const deviceType = useHeatmapSettingContext((state) => state.deviceType);
1403
1571
  const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
1404
1572
  const setIsRendering = useHeatmapSettingContext((state) => state.setIsRendering);
1405
1573
  const setIsLoadingDom = useHeatmapSettingContext((state) => state.setIsLoadingDom);
1406
1574
  const setIsLoadingCanvas = useHeatmapSettingContext((state) => state.setIsLoadingCanvas);
1575
+ const setShopId = useHeatmapConfigStore((state) => state.setShopId);
1576
+ const setExcludeClassNames = useHeatmapConfigStore((state) => state.setExcludeClassNames);
1577
+ useEffect(() => {
1578
+ if (!shopId || !!shopIdStore || shopIdStore === shopId)
1579
+ return;
1580
+ setShopId(shopId);
1581
+ }, [shopId, setShopId, shopIdStore]);
1582
+ useEffect(() => {
1583
+ setExcludeClassNames(excludeClassNames || []);
1584
+ }, [excludeClassNames, setExcludeClassNames]);
1407
1585
  useEffect(() => {
1408
1586
  setIsRendering(true);
1409
1587
  setTimeout(() => {
1410
1588
  setIsRendering(false);
1411
- }, 100);
1589
+ }, 500);
1412
1590
  }, [mode, deviceType, sidebarWidth]); // eslint-disable-line react-hooks/exhaustive-deps
1413
1591
  useEffect(() => {
1414
1592
  setIsRendering(!!isLoading);
@@ -1770,7 +1948,7 @@ class Logger {
1770
1948
  }
1771
1949
  }
1772
1950
  // Export singleton instance
1773
- const logger$9 = new Logger();
1951
+ const logger$3 = new Logger();
1774
1952
  // Export factory function để tạo logger với config riêng
1775
1953
  function createLogger(config = {}) {
1776
1954
  const instance = new Logger();
@@ -2159,7 +2337,7 @@ function findElementByHash(props) {
2159
2337
  }
2160
2338
  }
2161
2339
  catch (error) {
2162
- logger$9.warn(`Invalid selector "${selector}":`, error);
2340
+ logger$3.warn(`Invalid selector "${selector}":`, error);
2163
2341
  }
2164
2342
  const elementByHash = iframeDocument.querySelector(`[data-clarity-hashalpha="${hash}"], [data-clarity-hash="${hash}"], [data-clarity-hashbeta="${hash}"]`);
2165
2343
  return elementByHash;
@@ -2181,7 +2359,7 @@ function hydrateAreaNode(props) {
2181
2359
  const { id, hash, selector } = persistedData;
2182
2360
  const element = findElementByHash({ hash, selector, iframeDocument, vizRef });
2183
2361
  if (!element) {
2184
- logger$9.warn(`Cannot hydrate area ${id}: element not found for hash ${hash} or selector ${selector}`);
2362
+ logger$3.warn(`Cannot hydrate area ${id}: element not found for hash ${hash} or selector ${selector}`);
2185
2363
  return null;
2186
2364
  }
2187
2365
  const areaNode = buildAreaNode(element, hash, heatmapInfo, shadowRoot, persistedData);
@@ -2198,7 +2376,7 @@ function hydrateAreas(props) {
2198
2376
  hydratedAreas.push(area);
2199
2377
  }
2200
2378
  }
2201
- logger$9.info(`Hydrated ${hydratedAreas.length} of ${clickAreas.length} persisted areas`);
2379
+ logger$3.info(`Hydrated ${hydratedAreas.length} of ${clickAreas.length} persisted areas`);
2202
2380
  return hydratedAreas;
2203
2381
  }
2204
2382
  /**
@@ -2902,16 +3080,16 @@ const calcCalloutPositionAbsolute = (props) => {
2902
3080
 
2903
3081
  function validateAreaCreation(dataInfo, hash, areas) {
2904
3082
  if (!dataInfo?.clickMapMetrics || !dataInfo?.totalClicks) {
2905
- logger$9.warn('Cannot create area: missing heatmap data');
3083
+ logger$3.warn('Cannot create area: missing heatmap data');
2906
3084
  return false;
2907
3085
  }
2908
3086
  if (!hash) {
2909
- logger$9.warn('Cannot create area: missing hash');
3087
+ logger$3.warn('Cannot create area: missing hash');
2910
3088
  return false;
2911
3089
  }
2912
3090
  const alreadyExists = areas.some((area) => area.hash === hash);
2913
3091
  if (alreadyExists) {
2914
- logger$9.warn(`Area already exists for element: ${hash}`);
3092
+ logger$3.warn(`Area already exists for element: ${hash}`);
2915
3093
  return false;
2916
3094
  }
2917
3095
  return true;
@@ -2924,14 +3102,14 @@ function identifyConflictingAreas(area) {
2924
3102
  // Case 1: New area is a child of an existing area
2925
3103
  if (area.parentNode) {
2926
3104
  conflicts.parentId = area.parentNode.id;
2927
- logger$9.info(`New area "${area.selector}" is a child of existing area "${area.parentNode.selector}". Will remove parent.`);
3105
+ logger$3.info(`New area "${area.selector}" is a child of existing area "${area.parentNode.selector}". Will remove parent.`);
2928
3106
  }
2929
3107
  // Case 2: New area is a parent of existing area(s)
2930
3108
  if (area.childNodes.size > 0) {
2931
3109
  area.childNodes.forEach((childArea) => {
2932
3110
  conflicts.childrenIds.push(childArea.id);
2933
3111
  });
2934
- logger$9.info(`New area "${area.selector}" is a parent of ${area.childNodes.size} existing area(s). Will remove children.`);
3112
+ logger$3.info(`New area "${area.selector}" is a parent of ${area.childNodes.size} existing area(s). Will remove children.`);
2935
3113
  }
2936
3114
  return conflicts;
2937
3115
  }
@@ -2982,7 +3160,7 @@ function useAreaCreation(options = {}) {
2982
3160
  }
2983
3161
  }
2984
3162
  catch (error) {
2985
- logger$9.error('Failed to create area:', error);
3163
+ logger$3.error('Failed to create area:', error);
2986
3164
  }
2987
3165
  }, [dataInfo, areas, addArea, removeArea, removeClickArea, customShadowRoot, onAreaCreated]);
2988
3166
  return {
@@ -3097,16 +3275,16 @@ function useAreaHydration(options) {
3097
3275
  return;
3098
3276
  if (!dataInfo)
3099
3277
  return;
3100
- logger$9.info(`Hydrating ${clickAreas.length} persisted areas...`);
3278
+ logger$3.info(`Hydrating ${clickAreas.length} persisted areas...`);
3101
3279
  const hydratedAreas = hydrateAreas({ clickAreas, heatmapInfo: dataInfo, vizRef, shadowRoot });
3102
3280
  if (!hydratedAreas?.length) {
3103
- logger$9.warn('No areas could be hydrated - all elements may have been removed from DOM');
3281
+ logger$3.warn('No areas could be hydrated - all elements may have been removed from DOM');
3104
3282
  return;
3105
3283
  }
3106
3284
  setIsInitializing(true);
3107
3285
  buildAreaGraph(hydratedAreas);
3108
3286
  setAreas(hydratedAreas);
3109
- logger$9.info(`Successfully hydrated ${hydratedAreas.length} areas`);
3287
+ logger$3.info(`Successfully hydrated ${hydratedAreas.length} areas`);
3110
3288
  }, [dataInfo, vizRef, isInitializing, clickAreas]);
3111
3289
  useEffect(() => {
3112
3290
  if (!enabled)
@@ -3240,7 +3418,7 @@ function useAreaRectSync(options) {
3240
3418
  area.rect.update(newRect);
3241
3419
  }
3242
3420
  catch (error) {
3243
- logger$9.error(`Failed to update rect for area ${area.id}:`, error);
3421
+ logger$3.error(`Failed to update rect for area ${area.id}:`, error);
3244
3422
  }
3245
3423
  });
3246
3424
  buildAreaGraph(areas);
@@ -3345,18 +3523,20 @@ const useAreaClickmap = () => {
3345
3523
  const useClickmap = () => {
3346
3524
  const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
3347
3525
  const clickmap = useHeatmapDataContext((s) => s.clickmap);
3348
- const isRenderViz = useHeatmapVizContext((s) => s.isRenderViz);
3526
+ const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
3349
3527
  const start = useCallback(() => {
3350
- if (!vizRef || !clickmap || clickmap.length === 0 || !isRenderViz)
3528
+ if (!vizRef || !clickmap || clickmap.length === 0 || !isDomLoaded)
3351
3529
  return;
3352
3530
  try {
3353
- vizRef?.clearmap?.();
3354
- vizRef?.clickmap?.(clickmap);
3531
+ requestIdleCallback(() => {
3532
+ vizRef?.clearmap?.();
3533
+ vizRef?.clickmap?.(clickmap);
3534
+ }, { timeout: 300 });
3355
3535
  }
3356
3536
  catch (error) {
3357
3537
  console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
3358
3538
  }
3359
- }, [vizRef, clickmap, isRenderViz]);
3539
+ }, [vizRef, clickmap, isDomLoaded]);
3360
3540
  return { start };
3361
3541
  };
3362
3542
 
@@ -3364,6 +3544,7 @@ const useScrollmap = () => {
3364
3544
  const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
3365
3545
  const scrollType = useHeatmapSettingContext((s) => s.scrollType);
3366
3546
  const scrollmap = useHeatmapDataContext((s) => s.scrollmap);
3547
+ const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
3367
3548
  useMemo(() => {
3368
3549
  switch (scrollType) {
3369
3550
  case EScrollType.Depth:
@@ -3377,16 +3558,18 @@ const useScrollmap = () => {
3377
3558
  }
3378
3559
  }, [scrollmap, scrollType]);
3379
3560
  const start = useCallback(() => {
3380
- if (!vizRef || !scrollmap || scrollmap.length === 0)
3561
+ if (!vizRef || !scrollmap || scrollmap.length === 0 || !isDomLoaded)
3381
3562
  return;
3382
3563
  try {
3383
- vizRef?.clearmap?.();
3384
- vizRef?.scrollmap?.(scrollmap);
3564
+ requestIdleCallback(() => {
3565
+ vizRef?.clearmap?.();
3566
+ vizRef?.scrollmap?.(scrollmap);
3567
+ }, { timeout: 300 });
3385
3568
  }
3386
3569
  catch (error) {
3387
- logger$9.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
3570
+ logger$3.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
3388
3571
  }
3389
- }, [vizRef, scrollmap]);
3572
+ }, [vizRef, scrollmap, isDomLoaded]);
3390
3573
  return { start };
3391
3574
  };
3392
3575
 
@@ -3550,7 +3733,7 @@ const useHeatmapEffects = ({ isVisible }) => {
3550
3733
  };
3551
3734
 
3552
3735
  const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
3553
- const heatmapWidth = useHeatmapWidthByDevice();
3736
+ const viewport = useHeatmapViewportByDevice();
3554
3737
  const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
3555
3738
  const widthScale = useHeatmapVizContext((s) => s.widthScale);
3556
3739
  const getRect = useCallback((element) => {
@@ -3578,17 +3761,17 @@ const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
3578
3761
  const outOfBounds = adjustedTop < 0 ||
3579
3762
  adjustedTop > (iframeHeight || Infinity) ||
3580
3763
  layout.left < 0 ||
3581
- (typeof heatmapWidth === 'number' && layout.left > heatmapWidth);
3764
+ (typeof viewport.width === 'number' && layout.left > viewport.width);
3582
3765
  if (outOfBounds)
3583
3766
  return null;
3584
3767
  return {
3585
3768
  left: layout.left,
3586
3769
  top: adjustedTop,
3587
- width: Math.min(layout.width, heatmapWidth || layout.width),
3770
+ width: Math.min(layout.width, viewport.width || layout.width),
3588
3771
  height: layout.height,
3589
3772
  outOfBounds,
3590
3773
  };
3591
- }, [iframeRef, wrapperRef, visualizer, heatmapWidth, iframeHeight, widthScale]);
3774
+ }, [iframeRef, wrapperRef, visualizer, viewport, iframeHeight, widthScale]);
3592
3775
  return { getRect };
3593
3776
  };
3594
3777
 
@@ -3855,7 +4038,7 @@ var MessageType;
3855
4038
  })(MessageType || (MessageType = {}));
3856
4039
  function useVizLiveIframeMsg(options = {}) {
3857
4040
  const { trustedOrigins = [], onMessage } = options;
3858
- const addPayload = useHeatmapLiveStore((state) => state.addPayload);
4041
+ const addPayload = useHeatmapLiveContext((s) => s.addPayload);
3859
4042
  const [isReady, setIsReady] = useState(false);
3860
4043
  const iframeRef = useRef(null);
3861
4044
  const isValidOrigin = useCallback((origin) => {
@@ -3881,7 +4064,7 @@ function useVizLiveIframeMsg(options = {}) {
3881
4064
  switch (message.type) {
3882
4065
  case MessageType.GX_DOM_TRACKING_PAYLOAD:
3883
4066
  if (message.payload) {
3884
- const data = decodeClarity(message.payload);
4067
+ const data = JSON.parse(message.payload);
3885
4068
  if (data) {
3886
4069
  addPayload(data);
3887
4070
  }
@@ -3904,21 +4087,374 @@ function useVizLiveIframeMsg(options = {}) {
3904
4087
  };
3905
4088
  }
3906
4089
 
4090
+ /**
4091
+ * Unified performance timing utility.
4092
+ *
4093
+ * Two complementary tools:
4094
+ *
4095
+ * 1. `perf` — global DevTools session recorder.
4096
+ * Stores structured timing in `window.__gemxPerf` for inspection.
4097
+ * Used by the iframe-processor rendering pipeline.
4098
+ *
4099
+ * perf.startSession('render-1');
4100
+ * const t = perf.mark('viewport.run');
4101
+ * perf.measure('viewport.run', t);
4102
+ * perf.endSession();
4103
+ *
4104
+ * 2. `createPerfTimer` — per-module console logger factory.
4105
+ * Logs prefixed timings to the console AND records entries into the
4106
+ * active global session so they appear in `window.__gemxPerf` too.
4107
+ *
4108
+ * const timer = createPerfTimer('Render');
4109
+ * const t0 = timer.mark('start');
4110
+ * await timer.wrap('visualizer.html', () => visualizer.html(...));
4111
+ * timer.measure('total', t0);
4112
+ */
4113
+ const s = {
4114
+ enabled: true,
4115
+ current: null,
4116
+ sessions: [],
4117
+ maxSessions: 20,
4118
+ };
4119
+ // ── Global singleton functions ────────────────────────────────────────────────
4120
+ function startSession(id) {
4121
+ if (!s.enabled)
4122
+ return;
4123
+ s.current = { id, startedAt: performance.now(), entries: [] };
4124
+ }
4125
+ function endSession() {
4126
+ if (!s.enabled || !s.current)
4127
+ return null;
4128
+ const session = s.current;
4129
+ session.total = performance.now() - session.startedAt;
4130
+ s.sessions = [session, ...s.sessions].slice(0, s.maxSessions);
4131
+ s.current = null;
4132
+ flush();
4133
+ return session;
4134
+ }
4135
+ /** Record a point-in-time mark. Returns `performance.now()` for use with measure(). */
4136
+ function globalMark(label) {
4137
+ const now = performance.now();
4138
+ if (s.enabled && s.current) {
4139
+ s.current.entries.push({ label, t: now - s.current.startedAt });
4140
+ }
4141
+ return now;
4142
+ }
4143
+ /** Record a duration from a previous mark() timestamp. */
4144
+ function globalMeasure(label, t0) {
4145
+ const duration = performance.now() - t0;
4146
+ if (s.enabled && s.current) {
4147
+ s.current.entries.push({ label, t: t0 - s.current.startedAt, duration });
4148
+ }
4149
+ return duration;
4150
+ }
4151
+ function getReport() {
4152
+ return {
4153
+ sessions: s.sessions,
4154
+ latest: s.sessions[0] ?? null,
4155
+ };
4156
+ }
4157
+ function clearSessions() {
4158
+ s.current = null;
4159
+ s.sessions = [];
4160
+ if (typeof window !== 'undefined')
4161
+ delete window.__gemxPerf;
4162
+ }
4163
+ function enableGlobal() {
4164
+ s.enabled = true;
4165
+ }
4166
+ function disableGlobal() {
4167
+ s.enabled = false;
4168
+ }
4169
+ function flush() {
4170
+ if (typeof window === 'undefined')
4171
+ return;
4172
+ window.__gemxPerf = getReport();
4173
+ }
4174
+ // ── Global singleton export ───────────────────────────────────────────────────
4175
+ const perf$3 = {
4176
+ startSession,
4177
+ endSession,
4178
+ mark: globalMark,
4179
+ measure: globalMeasure,
4180
+ getReport,
4181
+ clear: clearSessions,
4182
+ enable: enableGlobal,
4183
+ disable: disableGlobal,
4184
+ };
4185
+ // ── createPerfTimer factory ───────────────────────────────────────────────────
4186
+ function createPerfTimer(config) {
4187
+ let cfg = typeof config === 'string' ? { prefix: config, enabled: true } : { enabled: true, ...config };
4188
+ function log(icon, label, extra) {
4189
+ if (!cfg.enabled)
4190
+ return;
4191
+ const suffix = extra ? ` — ${extra}` : '';
4192
+ console.log(`[${cfg.prefix}] ${icon} ${label}${suffix}`);
4193
+ }
4194
+ return {
4195
+ configure(next) {
4196
+ cfg = { ...cfg, ...next };
4197
+ },
4198
+ mark(label) {
4199
+ const t = globalMark(`[${cfg.prefix}] ${label}`);
4200
+ log('⏱', label);
4201
+ return t;
4202
+ },
4203
+ measure(label, from) {
4204
+ globalMeasure(`[${cfg.prefix}] ${label}`, from);
4205
+ const ms = (performance.now() - from).toFixed(1);
4206
+ log('✅', label, `${ms}ms`);
4207
+ },
4208
+ async wrap(label, fn) {
4209
+ const t = globalMark(`[${cfg.prefix}] ${label}`);
4210
+ log('⏱', label);
4211
+ const result = await fn();
4212
+ const duration = globalMeasure(`[${cfg.prefix}] ${label}`, t);
4213
+ log('✅', label, `${duration.toFixed(1)}ms`);
4214
+ return result;
4215
+ },
4216
+ };
4217
+ }
4218
+
3907
4219
  /**
3908
4220
  * DOM observation setup — ResizeObserver + MutationObserver.
3909
4221
  * Returns a cleanup function that disconnects both observers.
3910
4222
  */
3911
- createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
4223
+ const logger$2 = createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
4224
+ function setup(doc, onChange) {
4225
+ const resizeObserver = new ResizeObserver(onChange);
4226
+ resizeObserver.observe(doc.documentElement);
4227
+ resizeObserver.observe(doc.body);
4228
+ const mutationObserver = new MutationObserver(onChange);
4229
+ mutationObserver.observe(doc.body, {
4230
+ childList: true,
4231
+ subtree: true,
4232
+ attributes: true,
4233
+ attributeFilter: ['style', 'class', 'hidden', 'data-v'],
4234
+ });
4235
+ logger$2.log('DOM observers started (ResizeObserver + MutationObserver)');
4236
+ return () => {
4237
+ resizeObserver.disconnect();
4238
+ mutationObserver.disconnect();
4239
+ logger$2.log('DOM observers disconnected');
4240
+ };
4241
+ }
3912
4242
 
3913
4243
  /**
3914
4244
  * Height Observer Processor
3915
4245
  * Background observer — watches for iframe content height changes.
3916
4246
  */
3917
- createLogger({ enabled: true, prefix: 'IframeHeightObserver' });
4247
+ // ── Module-level functions ────────────────────────────────────────────────────
4248
+ function clearTimers(s) {
4249
+ if (s.throttleTimeout) {
4250
+ clearTimeout(s.throttleTimeout);
4251
+ s.throttleTimeout = null;
4252
+ }
4253
+ if (s.debounceTimeout) {
4254
+ clearTimeout(s.debounceTimeout);
4255
+ s.debounceTimeout = null;
4256
+ }
4257
+ }
4258
+ function getActualHeight(s) {
4259
+ if (!s.iframe?.contentDocument)
4260
+ return 0;
4261
+ const { documentElement: docEl, body } = s.iframe.contentDocument;
4262
+ const heights = [docEl.scrollHeight, docEl.offsetHeight, body.scrollHeight, body.offsetHeight];
4263
+ const maxHeight = Math.max(...heights.filter((h) => h > 0));
4264
+ s.logger.log('Height sources:', {
4265
+ 'documentElement.scrollHeight': docEl.scrollHeight,
4266
+ 'documentElement.offsetHeight': docEl.offsetHeight,
4267
+ 'body.scrollHeight': body.scrollHeight,
4268
+ 'body.offsetHeight': body.offsetHeight,
4269
+ maxHeight,
4270
+ });
4271
+ return maxHeight;
4272
+ }
4273
+ async function processHeightChange(s, newHeight) {
4274
+ if (!s.iframe || !s.config)
4275
+ return;
4276
+ s.isProcessing = true;
4277
+ s.logger.log(`Processing height change: ${newHeight}px`);
4278
+ try {
4279
+ const result = {
4280
+ height: newHeight,
4281
+ width: s.iframe.contentWindow?.innerWidth ?? 0,
4282
+ };
4283
+ s.lastHeight = newHeight;
4284
+ s.logger.log('Height change processed:', result);
4285
+ s.config.onHeightChange?.(result);
4286
+ window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: result }));
4287
+ }
4288
+ catch (error) {
4289
+ s.logger.error('Failed to process height change:', error);
4290
+ s.config.onError?.(error);
4291
+ }
4292
+ finally {
4293
+ s.isProcessing = false;
4294
+ }
4295
+ }
4296
+ function handleHeightChange(s) {
4297
+ if (s.isProcessing || s.throttleTimeout)
4298
+ return;
4299
+ s.throttleTimeout = setTimeout(() => {
4300
+ s.throttleTimeout = null;
4301
+ const currentHeight = getActualHeight(s);
4302
+ if (currentHeight === s.lastHeight)
4303
+ return;
4304
+ s.logger.log(`Height changed: ${s.lastHeight}px -> ${currentHeight}px`);
4305
+ if (s.debounceTimeout)
4306
+ clearTimeout(s.debounceTimeout);
4307
+ s.debounceTimeout = setTimeout(() => {
4308
+ s.debounceTimeout = null;
4309
+ processHeightChange(s, currentHeight);
4310
+ }, s.debounceMs);
4311
+ }, s.throttleMs);
4312
+ }
4313
+ function observe(s) {
4314
+ if (!s.iframe?.contentDocument?.body) {
4315
+ s.logger.warn('Cannot observe height changes: iframe body not found');
4316
+ return;
4317
+ }
4318
+ s.observerCleanup?.();
4319
+ s.lastHeight = s.iframe.contentDocument.documentElement.scrollHeight;
4320
+ s.logger.log('Initial height:', s.lastHeight);
4321
+ s.observerCleanup = setup(s.iframe.contentDocument, () => handleHeightChange(s));
4322
+ }
4323
+ function start$5(s, cfg) {
4324
+ if (s.running) {
4325
+ s.logger.warn('Observer is already running. Call stop() first.');
4326
+ return;
4327
+ }
4328
+ s.iframe = cfg.iframe;
4329
+ s.config = cfg;
4330
+ s.throttleMs = cfg.throttleMs ?? 25;
4331
+ s.debounceMs = cfg.debounceMs ?? 500;
4332
+ s.running = true;
4333
+ observe(s);
4334
+ s.logger.log('Height observer started');
4335
+ }
4336
+ function stop$5(s) {
4337
+ if (!s.running)
4338
+ return;
4339
+ s.observerCleanup?.();
4340
+ s.observerCleanup = null;
4341
+ clearTimers(s);
4342
+ s.iframe = null;
4343
+ s.config = null;
4344
+ s.lastHeight = 0;
4345
+ s.isProcessing = false;
4346
+ s.running = false;
4347
+ s.logger.log('Height observer stopped');
4348
+ }
4349
+ function clear(s) {
4350
+ s.observerCleanup?.();
4351
+ s.observerCleanup = null;
4352
+ clearTimers(s);
4353
+ s.lastHeight = 0;
4354
+ s.isProcessing = false;
4355
+ }
4356
+ function updateConfig$3(s, cfg) {
4357
+ if (!s.running || !s.config) {
4358
+ s.logger.warn('Observer is not running.');
4359
+ return;
4360
+ }
4361
+ s.config = { ...s.config, ...cfg };
4362
+ if (cfg.throttleMs !== undefined)
4363
+ s.throttleMs = cfg.throttleMs;
4364
+ if (cfg.debounceMs !== undefined)
4365
+ s.debounceMs = cfg.debounceMs;
4366
+ s.logger.configure({ enabled: !!s.config.debug });
4367
+ s.logger.log('Config updated');
4368
+ }
4369
+ // ── Factory ───────────────────────────────────────────────────────────────────
4370
+ function createHeightObserver() {
4371
+ const s = {
4372
+ logger: createLogger({ enabled: true, prefix: 'IframeHeightObserver' }),
4373
+ iframe: null,
4374
+ config: null,
4375
+ observerCleanup: null,
4376
+ lastHeight: 0,
4377
+ throttleTimeout: null,
4378
+ debounceTimeout: null,
4379
+ isProcessing: false,
4380
+ throttleMs: 25,
4381
+ debounceMs: 500,
4382
+ running: false,
4383
+ };
4384
+ return {
4385
+ start: (cfg) => start$5(s, cfg),
4386
+ stop: () => stop$5(s),
4387
+ observe: () => observe(s),
4388
+ clear: () => clear(s),
4389
+ updateConfig: (cfg) => updateConfig$3(s, cfg),
4390
+ getCurrentHeight: () => s.lastHeight,
4391
+ isRunning: () => s.running,
4392
+ getStateInfo: () => ({
4393
+ isRunning: s.running,
4394
+ lastHeight: s.lastHeight,
4395
+ isProcessing: s.isProcessing,
4396
+ hasObservers: !!s.observerCleanup,
4397
+ }),
4398
+ };
4399
+ }
4400
+
4401
+ /**
4402
+ * Window-level event management for the navigation processor.
4403
+ *
4404
+ * Responsibilities:
4405
+ * - Subscribe to events dispatched by this processor (for logging/hooks)
4406
+ * - Dispatch navigation events to the parent window
4407
+ */
4408
+ // ── Module-level functions ────────────────────────────────────────────────────
4409
+ function attach$1(s, debug) {
4410
+ s.logger.configure({ enabled: !!debug });
4411
+ s.navigationBlockedListener = (e) => {
4412
+ const ev = e;
4413
+ s.logger.log('Navigation blocked:', ev.detail.url);
4414
+ };
4415
+ s.formSubmitWindowListener = (e) => {
4416
+ const ev = e;
4417
+ s.logger.log('Form submitted:', ev.detail.data);
4418
+ };
4419
+ window.addEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
4420
+ window.addEventListener('iframe-form-submit', s.formSubmitWindowListener);
4421
+ }
4422
+ function detach$1(s) {
4423
+ if (s.navigationBlockedListener) {
4424
+ window.removeEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
4425
+ s.navigationBlockedListener = null;
4426
+ }
4427
+ if (s.formSubmitWindowListener) {
4428
+ window.removeEventListener('iframe-form-submit', s.formSubmitWindowListener);
4429
+ s.formSubmitWindowListener = null;
4430
+ }
4431
+ }
4432
+ function dispatchBlocked(url, showMessage) {
4433
+ if (showMessage)
4434
+ alert(`Navigation blocked: ${url}`);
4435
+ window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', { detail: { url } }));
4436
+ }
4437
+ function dispatchFormSubmit(form, data) {
4438
+ window.dispatchEvent(new CustomEvent('iframe-form-submit', { detail: { form, data } }));
4439
+ }
4440
+ // ── Factory ───────────────────────────────────────────────────────────────────
4441
+ function createNavigationListeners() {
4442
+ const s = {
4443
+ logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
4444
+ navigationBlockedListener: null,
4445
+ formSubmitWindowListener: null,
4446
+ };
4447
+ return {
4448
+ attach: (debug) => attach$1(s, debug),
4449
+ detach: () => detach$1(s),
4450
+ dispatchBlocked,
4451
+ dispatchFormSubmit,
4452
+ };
4453
+ }
3918
4454
 
3919
- const logger$8 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
4455
+ const logger$1 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
3920
4456
  function configure$1(debug) {
3921
- logger$8.configure({ enabled: debug });
4457
+ logger$1.configure({ enabled: debug });
3922
4458
  }
3923
4459
  // ─── DOM Utilities ────────────────────────────────────────────────────────────
3924
4460
  function disableAllLinks(doc) {
@@ -3942,10 +4478,10 @@ function setupLinkBlocker(doc, isEnabled, onBlocked) {
3942
4478
  return;
3943
4479
  const href = link.getAttribute('href');
3944
4480
  if (!href || href === '' || href === '#' || href.startsWith('#')) {
3945
- logger$8.log('Allowed hash navigation:', href);
4481
+ logger$1.log('Allowed hash navigation:', href);
3946
4482
  return;
3947
4483
  }
3948
- logger$8.log('Blocked link navigation to:', href);
4484
+ logger$1.log('Blocked link navigation to:', href);
3949
4485
  e.preventDefault();
3950
4486
  e.stopPropagation();
3951
4487
  e.stopImmediatePropagation();
@@ -3959,7 +4495,7 @@ function setupLinkBlocker(doc, isEnabled, onBlocked) {
3959
4495
  return;
3960
4496
  const href = link.getAttribute('href');
3961
4497
  if (href && !href.startsWith('#')) {
3962
- logger$8.log('Blocked auxclick navigation');
4498
+ logger$1.log('Blocked auxclick navigation');
3963
4499
  e.preventDefault();
3964
4500
  e.stopPropagation();
3965
4501
  e.stopImmediatePropagation();
@@ -3980,7 +4516,7 @@ function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
3980
4516
  const form = e.target;
3981
4517
  const action = form.getAttribute('action');
3982
4518
  if (!action || action === '' || action === '#') {
3983
- logger$8.log('Allowed same-page form');
4519
+ logger$1.log('Allowed same-page form');
3984
4520
  e.preventDefault();
3985
4521
  const data = {};
3986
4522
  new FormData(form).forEach((value, key) => {
@@ -3989,7 +4525,7 @@ function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
3989
4525
  onFormSubmit(form, data);
3990
4526
  return;
3991
4527
  }
3992
- logger$8.log('Blocked form submission to:', action);
4528
+ logger$1.log('Blocked form submission to:', action);
3993
4529
  e.preventDefault();
3994
4530
  e.stopPropagation();
3995
4531
  e.stopImmediatePropagation();
@@ -4003,7 +4539,7 @@ function setupWindowOpenBlocker(win, originalOpen, isEnabled, onBlocked) {
4003
4539
  if (!isEnabled())
4004
4540
  return originalOpen(...args);
4005
4541
  const url = args[0]?.toString() || 'popup';
4006
- logger$8.log('Blocked window.open:', url);
4542
+ logger$1.log('Blocked window.open:', url);
4007
4543
  onBlocked(url);
4008
4544
  return null;
4009
4545
  });
@@ -4015,14 +4551,14 @@ function setupUnloadBlocker(win, isEnabled) {
4015
4551
  const beforeUnloadListener = (e) => {
4016
4552
  if (!isEnabled())
4017
4553
  return;
4018
- logger$8.log('Blocked beforeunload');
4554
+ logger$1.log('Blocked beforeunload');
4019
4555
  e.preventDefault();
4020
4556
  e.returnValue = '';
4021
4557
  };
4022
4558
  const unloadListener = (e) => {
4023
4559
  if (!isEnabled())
4024
4560
  return;
4025
- logger$8.log('Blocked unload');
4561
+ logger$1.log('Blocked unload');
4026
4562
  e.preventDefault();
4027
4563
  e.stopPropagation();
4028
4564
  };
@@ -4039,65 +4575,14 @@ function setupDOMMonitor(doc) {
4039
4575
  return () => observer.disconnect();
4040
4576
  }
4041
4577
 
4042
- /**
4043
- * Window-level event management for the navigation processor.
4044
- *
4045
- * Responsibilities:
4046
- * - Subscribe to events dispatched by this processor (for logging/hooks)
4047
- * - Dispatch navigation events to the parent window
4048
- */
4049
- const logger$7 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
4050
- // ─── State ────────────────────────────────────────────────────────────────────
4051
- let navigationBlockedListener = null;
4052
- let formSubmitWindowListener = null;
4053
- // ─── Subscriptions ────────────────────────────────────────────────────────────
4054
- function attach$1(debug) {
4055
- logger$7.configure({ enabled: !!debug });
4056
- navigationBlockedListener = (e) => {
4057
- const ev = e;
4058
- logger$7.log('Navigation blocked:', ev.detail.url);
4059
- };
4060
- formSubmitWindowListener = (e) => {
4061
- const ev = e;
4062
- logger$7.log('Form submitted:', ev.detail.data);
4063
- };
4064
- window.addEventListener('iframe-navigation-blocked', navigationBlockedListener);
4065
- window.addEventListener('iframe-form-submit', formSubmitWindowListener);
4066
- }
4067
- function detach$1() {
4068
- if (navigationBlockedListener) {
4069
- window.removeEventListener('iframe-navigation-blocked', navigationBlockedListener);
4070
- navigationBlockedListener = null;
4071
- }
4072
- if (formSubmitWindowListener) {
4073
- window.removeEventListener('iframe-form-submit', formSubmitWindowListener);
4074
- formSubmitWindowListener = null;
4075
- }
4076
- }
4077
- // ─── Dispatchers ─────────────────────────────────────────────────────────────
4078
- function dispatchBlocked(url, showMessage) {
4079
- if (showMessage)
4080
- alert(`Navigation blocked: ${url}`);
4081
- window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', { detail: { url } }));
4082
- }
4083
- function dispatchFormSubmit(form, data) {
4084
- window.dispatchEvent(new CustomEvent('iframe-form-submit', { detail: { form, data } }));
4085
- }
4086
-
4087
4578
  /**
4088
4579
  * Navigation Processor
4089
4580
  * Continuous guard — blocks all navigation attempts within the iframe.
4090
4581
  */
4091
- const logger$6 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
4092
- // ─── State ────────────────────────────────────────────────────────────────────
4093
- let isEnabled = false;
4094
- let showMessage = false;
4095
- let running$4 = false;
4096
- let cleanups = [];
4097
- // ─── Public API ───────────────────────────────────────────────────────────────
4098
- function start$5(iframe, cfg) {
4099
- if (running$4) {
4100
- logger$6.warn('Blocker is already running. Call stop() first.');
4582
+ // ── Module-level functions ────────────────────────────────────────────────────
4583
+ function start$4(s, iframe, cfg) {
4584
+ if (s.running) {
4585
+ s.logger.warn('Blocker is already running. Call stop() first.');
4101
4586
  return;
4102
4587
  }
4103
4588
  if (!iframe.contentDocument || !iframe.contentWindow) {
@@ -4106,76 +4591,114 @@ function start$5(iframe, cfg) {
4106
4591
  const doc = iframe.contentDocument;
4107
4592
  const win = iframe.contentWindow;
4108
4593
  const originalOpen = win.open.bind(win);
4109
- logger$6.configure({ enabled: !!cfg?.debug });
4594
+ s.logger.configure({ enabled: !!cfg?.debug });
4110
4595
  configure$1(!!cfg?.debug);
4111
- cleanups = [
4112
- setupLinkBlocker(doc, () => isEnabled, (url) => dispatchBlocked(url, showMessage)),
4113
- setupFormBlocker(doc, () => isEnabled, (url) => dispatchBlocked(url, showMessage), dispatchFormSubmit),
4114
- setupWindowOpenBlocker(win, originalOpen, () => isEnabled, (url) => dispatchBlocked(url, showMessage)),
4115
- setupUnloadBlocker(win, () => isEnabled),
4596
+ s.cleanups = [
4597
+ setupLinkBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
4598
+ setupFormBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage), s.listeners.dispatchFormSubmit),
4599
+ setupWindowOpenBlocker(win, originalOpen, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
4600
+ setupUnloadBlocker(win, () => s.isEnabled),
4116
4601
  setupDOMMonitor(doc),
4117
4602
  ];
4118
- attach$1(cfg?.debug);
4119
- running$4 = true;
4120
- logger$6.log('Navigation blocker started');
4603
+ s.listeners.attach(cfg?.debug);
4604
+ s.running = true;
4605
+ s.logger.log('Started');
4121
4606
  }
4122
- function stop$5() {
4123
- if (!running$4)
4607
+ function stop$4(s) {
4608
+ if (!s.running)
4124
4609
  return;
4125
- cleanups.forEach((fn) => fn());
4126
- cleanups = [];
4127
- detach$1();
4128
- isEnabled = false;
4129
- showMessage = false;
4130
- running$4 = false;
4131
- logger$6.log('Navigation blocker stopped');
4132
- }
4133
- function enable() {
4134
- if (!running$4) {
4135
- logger$6.warn('Blocker is not running. Call start() first.');
4610
+ s.cleanups.forEach((fn) => fn());
4611
+ s.cleanups = [];
4612
+ s.listeners.detach();
4613
+ s.isEnabled = false;
4614
+ s.showMessage = false;
4615
+ s.running = false;
4616
+ s.logger.log('Stopped');
4617
+ }
4618
+ function enable(s) {
4619
+ if (!s.running) {
4620
+ s.logger.warn('Blocker is not running.');
4621
+ return;
4622
+ }
4623
+ s.isEnabled = true;
4624
+ s.logger.log('Navigation blocking enabled');
4625
+ }
4626
+ function disable(s) {
4627
+ if (!s.running) {
4628
+ s.logger.warn('Blocker is not running.');
4629
+ return;
4630
+ }
4631
+ s.isEnabled = false;
4632
+ s.logger.log('Navigation blocking disabled');
4633
+ }
4634
+ function enableMessage(s) {
4635
+ if (!s.running) {
4636
+ s.logger.warn('Blocker is not running.');
4637
+ return;
4638
+ }
4639
+ s.showMessage = true;
4640
+ s.logger.log('Navigation blocking message enabled');
4641
+ }
4642
+ function disableMessage(s) {
4643
+ if (!s.running) {
4644
+ s.logger.warn('Blocker is not running.');
4136
4645
  return;
4137
4646
  }
4138
- isEnabled = true;
4139
- logger$6.log('Navigation blocking enabled');
4647
+ s.showMessage = false;
4648
+ s.logger.log('Navigation blocking message disabled');
4649
+ }
4650
+ // ── Factory ───────────────────────────────────────────────────────────────────
4651
+ function createNavigationBlocker() {
4652
+ const s = {
4653
+ logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
4654
+ listeners: createNavigationListeners(),
4655
+ isEnabled: false,
4656
+ showMessage: false,
4657
+ running: false,
4658
+ cleanups: [],
4659
+ };
4660
+ return {
4661
+ start: (iframe, cfg) => start$4(s, iframe, cfg),
4662
+ stop: () => stop$4(s),
4663
+ enable: () => enable(s),
4664
+ disable: () => disable(s),
4665
+ enableMessage: () => enableMessage(s),
4666
+ disableMessage: () => disableMessage(s),
4667
+ isRunning: () => s.running,
4668
+ isBlockingEnabled: () => s.isEnabled,
4669
+ getStateInfo: () => ({ isRunning: s.running, isEnabled: s.isEnabled, showMessage: s.showMessage }),
4670
+ };
4140
4671
  }
4141
4672
 
4142
- const registry$1 = [];
4143
- /**
4144
- * Register a global fix.
4145
- * Fixes are run in registration order.
4146
- */
4147
- function register$1(fix) {
4148
- registry$1.push(fix);
4673
+ // ── Module-level functions ────────────────────────────────────────────────────
4674
+ function attach(s, debug) {
4675
+ s.logger.configure({ enabled: !!debug });
4676
+ s.dimensionsListener = (e) => {
4677
+ // const ev = e as CustomEvent<IframeDimensionsDetail>;
4678
+ // s.logger.log('Dimensions applied:', ev.detail);
4679
+ };
4680
+ window.addEventListener('iframe-dimensions-applied', s.dimensionsListener);
4149
4681
  }
4150
- /**
4151
- * Returns all fixes that are active for the given context.
4152
- * A fix is active if it has no `shouldApply`, or `shouldApply` returns true.
4153
- */
4154
- function getActiveFixes(ctx) {
4155
- return registry$1.filter((fix) => {
4156
- try {
4157
- return !fix.shouldApply || fix.shouldApply(ctx);
4158
- }
4159
- catch {
4160
- return false;
4161
- }
4162
- });
4682
+ function detach(s) {
4683
+ if (s.dimensionsListener) {
4684
+ window.removeEventListener('iframe-dimensions-applied', s.dimensionsListener);
4685
+ s.dimensionsListener = null;
4686
+ }
4687
+ }
4688
+ // ── Factory ───────────────────────────────────────────────────────────────────
4689
+ function createViewportListeners() {
4690
+ const s = {
4691
+ logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
4692
+ dimensionsListener: null,
4693
+ };
4694
+ return {
4695
+ attach: (debug) => attach(s, debug),
4696
+ detach: () => detach(s),
4697
+ };
4163
4698
  }
4164
4699
 
4165
- /**
4166
- * Computed Style Enforcer Module
4167
- * Enforces computed CSS styles with viewport unit verification
4168
- * @module computed-style-enforcer
4169
- */
4170
- const logger$5 = createLogger({
4171
- enabled: false,
4172
- prefix: 'ComputedStyleEnforcer',
4173
- });
4174
- // ============================================================================
4175
- // Constants
4176
- // ============================================================================
4177
4700
  const DEFAULT_TOLERANCE_PX = 5;
4178
- const VIEWPORT_UNIT_REGEX = /([-.\d]+)(vh|svh|lvh|dvh|%)/gi;
4701
+ const VIEWPORT_UNIT_REGEX = /([-.\\d]+)(vh|svh|lvh|dvh|%)/gi;
4179
4702
  const DEFAULT_CSS_VALUES = ['none', 'auto', 'normal', '0px'];
4180
4703
  const CRITICAL_PROPERTIES = [
4181
4704
  'display',
@@ -4212,424 +4735,216 @@ const CRITICAL_PROPERTIES = [
4212
4735
  'grid-template-rows',
4213
4736
  'gap',
4214
4737
  ];
4215
- // ============================================================================
4216
- // State
4217
- // ============================================================================
4218
- let doc$1 = null;
4219
- let win$1 = null;
4220
- let config$2 = null;
4221
- const elementsWithViewportUnits$1 = new Set();
4222
- let originalValues$1 = new WeakMap();
4223
- let running$3 = false;
4224
- // ============================================================================
4225
- // Helper Functions
4226
- // ============================================================================
4227
- /**
4228
- * Get viewport unit map for conversion from current state
4229
- */
4230
- function getViewportUnitMap() {
4231
- if (!config$2) {
4738
+
4739
+ // ── Helpers ───────────────────────────────────────────────────────────────────
4740
+ function getViewportUnitMap(s) {
4741
+ if (!s.config)
4232
4742
  throw new Error('Config is not initialized');
4233
- }
4234
4743
  return {
4235
- vh: config$2.targetHeight,
4236
- svh: config$2.targetHeight,
4237
- lvh: config$2.targetHeight,
4238
- dvh: config$2.targetHeight,
4239
- vw: config$2.targetWidth,
4240
- svw: config$2.targetWidth,
4241
- lvw: config$2.targetWidth,
4242
- dvw: config$2.targetWidth,
4744
+ vh: s.config.targetHeight,
4745
+ svh: s.config.targetHeight,
4746
+ lvh: s.config.targetHeight,
4747
+ dvh: s.config.targetHeight,
4748
+ vw: s.config.targetWidth,
4749
+ svw: s.config.targetWidth,
4750
+ lvw: s.config.targetWidth,
4751
+ dvw: s.config.targetWidth,
4243
4752
  };
4244
4753
  }
4245
- /**
4246
- * Calculate expected pixel value from viewport unit using current state
4247
- */
4248
- function calculateExpectedPx(value, unit) {
4249
- if (!config$2) {
4754
+ function calculateExpectedPx(s, value, unit) {
4755
+ if (!s.config)
4250
4756
  throw new Error('Config is not initialized');
4251
- }
4252
4757
  const unitLower = unit.toLowerCase();
4253
- if (unitLower === '%') {
4254
- return (value / 100) * config$2.targetHeight;
4255
- }
4256
- const unitMap = getViewportUnitMap();
4257
- return (value / 100) * (unitMap[unitLower] || 0);
4758
+ if (unitLower === '%')
4759
+ return (value / 100) * s.config.targetHeight;
4760
+ return (value / 100) * (getViewportUnitMap(s)[unitLower] || 0);
4258
4761
  }
4259
- /**
4260
- * Check if a CSS value is a default/initial value that should be skipped
4261
- */
4262
4762
  function isDefaultCssValue(value) {
4263
4763
  return DEFAULT_CSS_VALUES.includes(value);
4264
4764
  }
4265
- /**
4266
- * Verify if we should replace the computed value using current state
4267
- * Return true ONLY if computed value matches target config (within tolerance)
4268
- * Return false if computed value is different - don't override correct values
4269
- */
4270
- function shouldReplaceValue(computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4271
- if (!config$2) {
4765
+ function shouldReplaceValue(s, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4766
+ if (!s.config)
4272
4767
  return false;
4273
- }
4274
- // Parse computed value (should be in px)
4275
4768
  const computedPx = parseFloat(computedValue);
4276
- if (isNaN(computedPx)) {
4277
- return false; // Cannot verify, don't replace
4278
- }
4279
- // Parse original value to check what it should be
4769
+ if (isNaN(computedPx))
4770
+ return false;
4280
4771
  const regex = new RegExp(VIEWPORT_UNIT_REGEX.source, VIEWPORT_UNIT_REGEX.flags);
4281
4772
  const match = originalValue.match(regex);
4282
- if (!match) {
4283
- return false; // No viewport units found, don't replace
4284
- }
4773
+ if (!match)
4774
+ return false;
4285
4775
  const [, value, unit] = match;
4286
4776
  const num = parseFloat(value);
4287
- if (isNaN(num)) {
4777
+ if (isNaN(num))
4288
4778
  return false;
4289
- }
4290
- // Calculate expected value based on unit and target config
4291
- const expectedPx = calculateExpectedPx(num, unit);
4292
- // Check if computed value matches expected value (within tolerance)
4779
+ const expectedPx = calculateExpectedPx(s, num, unit);
4293
4780
  const diff = Math.abs(computedPx - expectedPx);
4294
4781
  if (diff <= tolerance) {
4295
- // Matches target config, OK to replace
4296
- logger$5.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4782
+ s.logger.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4297
4783
  return true;
4298
4784
  }
4299
- // Different from target config, DON'T replace - value already has correct computation
4300
- logger$5.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px) - keeping current value`);
4785
+ s.logger.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4301
4786
  return false;
4302
4787
  }
4303
- /**
4304
- * Apply a single property to an element with verification using current state
4305
- */
4306
- function applyPropertyWithVerification(element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4307
- // Verify before replacing - only replace if computed value matches target config
4308
- if (originalValue && shouldReplaceValue(computedValue, originalValue, tolerance)) {
4788
+ function applyPropertyWithVerification(s, element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4789
+ if (originalValue && shouldReplaceValue(s, computedValue, originalValue, tolerance)) {
4309
4790
  element.style.setProperty(prop, computedValue, 'important');
4310
4791
  return true;
4311
4792
  }
4312
4793
  else if (!originalValue) {
4313
- // No original value tracked, use old behavior
4314
4794
  element.style.setProperty(prop, computedValue, 'important');
4315
4795
  return true;
4316
4796
  }
4317
4797
  return false;
4318
4798
  }
4319
- // ============================================================================
4320
- // Public API Functions
4321
- // ============================================================================
4322
- /**
4323
- * Start the computed style enforcer
4324
- * Initialize with iframe document and config
4325
- */
4326
- function start$4(d, w, cfg, options = {}) {
4327
- if (running$3) {
4328
- logger$5.warn('Enforcer is already running. Call stop() first.');
4799
+ // ── Exported module-level functions ───────────────────────────────────────────
4800
+ function start$3(s, d, w, cfg, options = {}) {
4801
+ if (s.running) {
4802
+ s.logger.warn('Enforcer is already running. Call stop() first.');
4329
4803
  return;
4330
4804
  }
4331
- doc$1 = d;
4332
- win$1 = w;
4333
- config$2 = cfg;
4334
- running$3 = true;
4335
- logger$5.configure({ enabled: !!options.debug });
4336
- logger$5.log('Computed style enforcer started');
4805
+ s.doc = d;
4806
+ s.win = w;
4807
+ s.config = cfg;
4808
+ s.running = true;
4809
+ s.logger.configure({ enabled: !!options.debug });
4810
+ s.logger.log('Started');
4337
4811
  }
4338
- /**
4339
- * Stop the enforcer and clear state
4340
- */
4341
- function stop$4() {
4342
- if (!running$3) {
4812
+ function stop$3(s) {
4813
+ if (!s.running)
4814
+ return;
4815
+ s.doc = null;
4816
+ s.win = null;
4817
+ s.config = null;
4818
+ s.elementsWithViewportUnits.clear();
4819
+ s.originalValues = new WeakMap();
4820
+ s.running = false;
4821
+ s.logger.log('Stopped');
4822
+ }
4823
+ function reset(s) {
4824
+ if (!s.running) {
4825
+ s.logger.warn('Enforcer is not running. Call start() first.');
4343
4826
  return;
4344
4827
  }
4345
- doc$1 = null;
4346
- win$1 = null;
4347
- config$2 = null;
4348
- elementsWithViewportUnits$1.clear();
4349
- originalValues$1 = new WeakMap();
4350
- running$3 = false;
4351
- logger$5.log('Computed style enforcer stopped');
4828
+ s.elementsWithViewportUnits.clear();
4829
+ s.originalValues = new WeakMap();
4830
+ s.logger.log('Reset');
4352
4831
  }
4353
- /**
4354
- * Track an element with viewport units
4355
- * Store original CSS values for later verification
4356
- */
4357
- function trackElement(element, propertyOriginalValues) {
4358
- if (!running$3) {
4359
- logger$5.warn('Enforcer is not running. Call start() first.');
4832
+ function trackElement(s, element, propertyOriginalValues) {
4833
+ if (!s.running) {
4834
+ s.logger.warn('Enforcer is not running. Call start() first.');
4360
4835
  return;
4361
4836
  }
4362
- elementsWithViewportUnits$1.add(element);
4363
- // Store original values for this element
4364
- let elementOriginals = originalValues$1.get(element);
4837
+ s.elementsWithViewportUnits.add(element);
4838
+ let elementOriginals = s.originalValues.get(element);
4365
4839
  if (!elementOriginals) {
4366
4840
  elementOriginals = new Map();
4367
- originalValues$1.set(element, elementOriginals);
4841
+ s.originalValues.set(element, elementOriginals);
4368
4842
  }
4369
- // Merge property original values (don't override existing)
4370
4843
  propertyOriginalValues.forEach((value, prop) => {
4371
- if (!elementOriginals.has(prop)) {
4844
+ if (!elementOriginals.has(prop))
4372
4845
  elementOriginals.set(prop, value);
4373
- }
4374
4846
  });
4375
4847
  }
4376
- /**
4377
- * Process a single element - enforce computed styles to inline
4378
- */
4379
- function processElement(element, options = {}) {
4380
- if (!running$3 || !doc$1 || !win$1 || !config$2) {
4381
- logger$5.warn('Enforcer is not running. Call start() first.');
4848
+ function processElement(s, element, options = {}) {
4849
+ if (!s.running || !s.doc || !s.win || !s.config) {
4850
+ s.logger.warn('Enforcer is not running.');
4382
4851
  return 0;
4383
4852
  }
4384
- if (!elementsWithViewportUnits$1.has(element)) {
4853
+ if (!s.elementsWithViewportUnits.has(element))
4385
4854
  return 0;
4386
- }
4387
4855
  const htmlElement = element;
4388
- const computed = win$1.getComputedStyle(htmlElement);
4856
+ const computed = s.win.getComputedStyle(htmlElement);
4389
4857
  const inlineStyle = htmlElement.style;
4390
- const elementOriginals = originalValues$1.get(element);
4858
+ const elementOriginals = s.originalValues.get(element);
4391
4859
  const tolerance = options.tolerance ?? DEFAULT_TOLERANCE_PX;
4392
4860
  let count = 0;
4393
4861
  CRITICAL_PROPERTIES.forEach((prop) => {
4394
4862
  const computedValue = computed.getPropertyValue(prop);
4395
4863
  const inlineValue = inlineStyle.getPropertyValue(prop);
4396
- if (computedValue && (!inlineValue || inlineValue !== computedValue)) {
4397
- if (!isDefaultCssValue(computedValue)) {
4398
- const originalValue = elementOriginals?.get(prop) || '';
4399
- if (applyPropertyWithVerification(htmlElement, prop, computedValue, originalValue, tolerance)) {
4400
- count++;
4401
- }
4402
- }
4864
+ if (computedValue && (!inlineValue || inlineValue !== computedValue) && !isDefaultCssValue(computedValue)) {
4865
+ const originalValue = elementOriginals?.get(prop) || '';
4866
+ if (applyPropertyWithVerification(s, htmlElement, prop, computedValue, originalValue, tolerance))
4867
+ count++;
4403
4868
  }
4404
4869
  });
4405
4870
  return count;
4406
4871
  }
4407
- /**
4408
- * Process all tracked elements
4409
- * Enforce computed styles to inline for all elements with viewport units
4410
- */
4411
- function processAll(options = {}) {
4412
- if (!running$3 || !doc$1 || !win$1 || !config$2) {
4413
- logger$5.warn('Enforcer is not running. Call start() first.');
4872
+ function processAll(s, options = {}) {
4873
+ if (!s.running || !s.doc || !s.win || !s.config) {
4874
+ s.logger.warn('Enforcer is not running.');
4414
4875
  return 0;
4415
4876
  }
4416
4877
  let totalCount = 0;
4417
- elementsWithViewportUnits$1.forEach((element) => {
4418
- totalCount += processElement(element, options);
4878
+ s.elementsWithViewportUnits.forEach((element) => {
4879
+ totalCount += processElement(s, element, options);
4419
4880
  });
4420
- logger$5.log(`Enforced ${totalCount} computed styles for ${elementsWithViewportUnits$1.size} elements`);
4881
+ s.logger.log(`Enforced ${totalCount} computed styles for ${s.elementsWithViewportUnits.size} elements`);
4421
4882
  return totalCount;
4422
4883
  }
4884
+ function updateConfig$2(s, cfg) {
4885
+ if (!s.running || !s.config) {
4886
+ s.logger.warn('Enforcer is not running.');
4887
+ return;
4888
+ }
4889
+ s.config = { ...s.config, ...cfg };
4890
+ s.logger.log('Config updated:', cfg);
4891
+ }
4423
4892
 
4424
4893
  /**
4425
- * Core viewport unit replacement logic.
4426
- * Converts vh/vw/svh/dvh/% to pixel values across all CSS in the iframe.
4894
+ * Computed Style Enforcer
4895
+ * Enforces computed CSS styles with viewport unit verification.
4427
4896
  */
4428
- const logger$4 = createLogger({ enabled: false, prefix: 'ViewportUnitReplacer' });
4429
- // ─── Constants ────────────────────────────────────────────────────────────────
4430
- const HEIGHT_RELATED_PROPERTIES = ['height', 'min-height', 'max-height', 'top', 'bottom'];
4431
- // ─── Per-run tracking state (reset on each process() call) ───────────────────
4432
- let elementsWithViewportUnits = new Set();
4433
- let originalValues = new WeakMap();
4434
- // ─── Regex ────────────────────────────────────────────────────────────────────
4435
- /** Fresh instance every call — avoids shared lastIndex state with the g flag. */
4436
- function createRegex() {
4437
- return /([-.\\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
4438
- }
4439
- // ─── Unit conversion ─────────────────────────────────────────────────────────
4440
- function px(value) {
4441
- return `${value.toFixed(2)}px`;
4442
- }
4443
- function getUnitMap(ctx) {
4897
+ // ── Factory ───────────────────────────────────────────────────────────────────
4898
+ function createEnforcer() {
4899
+ const s = {
4900
+ logger: createLogger({ enabled: false, prefix: 'ComputedStyleEnforcer' }),
4901
+ doc: null,
4902
+ win: null,
4903
+ config: null,
4904
+ elementsWithViewportUnits: new Set(),
4905
+ originalValues: new WeakMap(),
4906
+ running: false,
4907
+ };
4444
4908
  return {
4445
- vh: ctx.targetHeight,
4446
- svh: ctx.targetHeight,
4447
- lvh: ctx.targetHeight,
4448
- dvh: ctx.targetHeight,
4449
- vw: ctx.targetWidth,
4450
- svw: ctx.targetWidth,
4451
- lvw: ctx.targetWidth,
4452
- dvw: ctx.targetWidth,
4909
+ start: (d, w, cfg, options) => start$3(s, d, w, cfg, options),
4910
+ stop: () => stop$3(s),
4911
+ reset: () => reset(s),
4912
+ trackElement: (element, propertyOriginalValues) => trackElement(s, element, propertyOriginalValues),
4913
+ processElement: (element, options) => processElement(s, element, options),
4914
+ processAll: (options) => processAll(s, options),
4915
+ updateConfig: (cfg) => updateConfig$2(s, cfg),
4916
+ getStateInfo: () => ({
4917
+ isRunning: s.running,
4918
+ trackedElementsCount: s.elementsWithViewportUnits.size,
4919
+ hasConfig: !!s.config,
4920
+ }),
4921
+ isRunning: () => s.running,
4453
4922
  };
4454
4923
  }
4455
- function toPx(value, unit, ctx) {
4456
- const u = unit.toLowerCase();
4457
- if (u === '%')
4458
- return (value / 100) * ctx.targetHeight;
4459
- return (value / 100) * (getUnitMap(ctx)[u] ?? 0);
4460
- }
4461
- function convert(value, unit, ctx) {
4462
- const num = parseFloat(value);
4463
- return isNaN(num) ? value : px(toPx(num, unit, ctx));
4464
- }
4465
- function isHeightRelated(prop) {
4466
- return HEIGHT_RELATED_PROPERTIES.includes(prop);
4467
- }
4468
- /**
4469
- * Use `matchOffset` (from replace() callback) instead of indexOf to get the
4470
- * exact position of the current match — avoids false matches for duplicate values.
4924
+
4925
+ const registry$1 = [];
4926
+ /**
4927
+ * Register a global fix.
4928
+ * Fixes are run in registration order.
4471
4929
  */
4472
- function extractProperty(cssText, matchOffset) {
4473
- const before = cssText.substring(0, matchOffset);
4474
- const m = before.match(/([a-z-]+)\s*:\s*[^;{}]*$/i);
4475
- return m ? m[1].toLowerCase() : '';
4476
- }
4477
- function replaceInText(cssText, ctx) {
4478
- return cssText.replace(createRegex(), (match, value, unit, offset) => {
4479
- if (unit === '%') {
4480
- return isHeightRelated(extractProperty(cssText, offset)) ? convert(value, unit, ctx) : match;
4481
- }
4482
- return convert(value, unit, ctx);
4483
- });
4484
- }
4485
- // ─── Element tracking ─────────────────────────────────────────────────────────
4486
- function trackSelector(selector, propOriginals, ctx) {
4487
- try {
4488
- ctx.doc.querySelectorAll(selector).forEach((el) => {
4489
- elementsWithViewportUnits.add(el);
4490
- let originals = originalValues.get(el);
4491
- if (!originals) {
4492
- originals = new Map();
4493
- originalValues.set(el, originals);
4494
- }
4495
- propOriginals.forEach((v, k) => {
4496
- if (!originals.has(k))
4497
- originals.set(k, v);
4498
- });
4499
- trackElement(el, propOriginals);
4500
- });
4501
- }
4502
- catch {
4503
- logger$4.warn('Invalid selector, skipping:', selector);
4504
- }
4505
- }
4506
- // ─── CSS processing ───────────────────────────────────────────────────────────
4507
- function processInlineStyles(ctx) {
4508
- let count = 0;
4509
- ctx.doc.querySelectorAll('[style]').forEach((el) => {
4510
- const style = el.getAttribute('style');
4511
- if (style && createRegex().test(style)) {
4512
- elementsWithViewportUnits.add(el);
4513
- el.setAttribute('style', replaceInText(style, ctx));
4514
- count++;
4515
- }
4516
- });
4517
- logger$4.log(`Replaced ${count} inline style elements`);
4518
- return count;
4519
- }
4520
- function processStyleTags(ctx) {
4521
- let count = 0;
4522
- ctx.doc.querySelectorAll('style').forEach((tag) => {
4523
- const css = tag.textContent || '';
4524
- if (createRegex().test(css)) {
4525
- tag.textContent = replaceInText(css, ctx);
4526
- count++;
4527
- }
4528
- });
4529
- logger$4.log(`Replaced ${count} <style> tags`);
4530
- return count;
4531
- }
4532
- function processRule(rule, ctx) {
4533
- let count = 0;
4534
- if ('style' in rule && rule.style) {
4535
- const cssRule = rule;
4536
- const style = cssRule.style;
4537
- let hasVp = false;
4538
- const propOriginals = new Map();
4539
- for (let i = 0; i < style.length; i++) {
4540
- const prop = style[i];
4541
- const value = style.getPropertyValue(prop);
4542
- if (value && createRegex().test(value)) {
4543
- hasVp = true;
4544
- propOriginals.set(prop, value);
4545
- style.setProperty(prop, replaceInText(value, ctx), style.getPropertyPriority(prop));
4546
- count++;
4547
- }
4548
- }
4549
- if (hasVp && cssRule.selectorText)
4550
- trackSelector(cssRule.selectorText, propOriginals, ctx);
4551
- }
4552
- if ('cssRules' in rule) {
4553
- for (const r of Array.from(rule.cssRules || [])) {
4554
- count += processRule(r, ctx);
4555
- }
4556
- }
4557
- return count;
4930
+ function register$1(fix) {
4931
+ registry$1.push(fix);
4558
4932
  }
4559
- /** Processes only inline <style> sheets. Linked sheets are handled by processLinkedStylesheets. */
4560
- function processStylesheets(ctx) {
4561
- let total = 0;
4562
- Array.from(ctx.doc.styleSheets).forEach((sheet) => {
4563
- if (sheet.href)
4564
- return; // deferred to processLinkedStylesheets
4933
+ /**
4934
+ * Returns all fixes that are active for the given context.
4935
+ * A fix is active if it has no `shouldApply`, or `shouldApply` returns true.
4936
+ */
4937
+ function getActiveFixes(ctx) {
4938
+ return registry$1.filter((fix) => {
4565
4939
  try {
4566
- for (const rule of Array.from(sheet.cssRules || [])) {
4567
- total += processRule(rule, ctx);
4568
- }
4940
+ return !fix.shouldApply || fix.shouldApply(ctx);
4569
4941
  }
4570
- catch (e) {
4571
- logger$4.warn('Cannot read stylesheet (CORS?):', e.message);
4942
+ catch {
4943
+ return false;
4572
4944
  }
4573
4945
  });
4574
- logger$4.log(`Replaced ${total} rules in inline stylesheets`);
4575
- return total;
4576
- }
4577
- async function processLinkedStylesheets(ctx) {
4578
- const links = ctx.doc.querySelectorAll('link[rel="stylesheet"]');
4579
- let count = 0;
4580
- for (const link of Array.from(links)) {
4581
- // Skip cross-origin — already in browser CSSOM, handled via processStylesheets
4582
- if (link.href && !link.href.startsWith(ctx.win.location.origin)) {
4583
- logger$4.log('Skipping cross-origin CSS:', link.href);
4584
- continue;
4585
- }
4586
- try {
4587
- const res = await fetch(link.href);
4588
- let css = await res.text();
4589
- if (createRegex().test(css)) {
4590
- css = replaceInText(css, ctx);
4591
- const style = ctx.doc.createElement('style');
4592
- style.textContent = css;
4593
- style.dataset.originalHref = link.href;
4594
- link.parentNode?.insertBefore(style, link);
4595
- link.remove();
4596
- count++;
4597
- }
4598
- }
4599
- catch (e) {
4600
- logger$4.warn('Cannot load CSS:', link.href, e);
4601
- }
4602
- }
4603
- logger$4.log(`Replaced ${count} linked CSS files`);
4604
- return count;
4605
- }
4606
- // ─── Public entry point ───────────────────────────────────────────────────────
4607
- async function process$1(ctx) {
4608
- logger$4.configure({ enabled: !!ctx.debug });
4609
- // Reset tracking state from any previous run
4610
- elementsWithViewportUnits = new Set();
4611
- originalValues = new WeakMap();
4612
- processInlineStyles(ctx);
4613
- processStyleTags(ctx);
4614
- processStylesheets(ctx);
4615
- await processLinkedStylesheets(ctx);
4616
- // Wait for browser to apply the replaced styles
4617
- await new Promise((resolve) => requestAnimationFrame(resolve));
4618
- // Enforce final computed styles to inline with !important
4619
- const count = processAll({ debug: !!ctx.debug });
4620
- logger$4.log(`Enforced ${count} computed styles for ${elementsWithViewportUnits.size} tracked elements`);
4621
4946
  }
4622
4947
 
4623
- /**
4624
- * Built-in global fix — always runs, no shouldApply condition.
4625
- * Registered first so it runs before any other global process hooks.
4626
- */
4627
- register$1({
4628
- name: 'viewport-unit-replacer',
4629
- description: 'Core: convert vh/vw/svh/dvh/% to px values across all iframe CSS',
4630
- process: process$1,
4631
- });
4632
-
4633
4948
  /**
4634
4949
  * GemPages v7 Slider Fix
4635
4950
  *
@@ -4713,6 +5028,9 @@ function getMaxWByDeviceType(deviceType) {
4713
5028
  // ─── Main fix ─────────────────────────────────────────────────────────────────
4714
5029
  function afterProcess$1({ doc, targetWidth, deviceType }) {
4715
5030
  doc.querySelectorAll(SLIDER_ITEM_SELECTOR).forEach((item) => {
5031
+ // When !gp-min-w-full is set, the item fills 100% width via Tailwind — skip manual width override
5032
+ if (item.classList.contains('!gp-min-w-full'))
5033
+ return;
4716
5034
  const originalWidth = parseFloat(item.style.minWidth) || parseFloat(item.style.maxWidth) || 0;
4717
5035
  if (!originalWidth)
4718
5036
  return;
@@ -4813,23 +5131,6 @@ register$1({
4813
5131
  afterProcess,
4814
5132
  });
4815
5133
 
4816
- const logger$3 = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
4817
- let dimensionsListener = null;
4818
- function attach(debug) {
4819
- logger$3.configure({ enabled: !!debug });
4820
- dimensionsListener = (e) => {
4821
- const ev = e;
4822
- logger$3.log('Dimensions applied:', ev.detail);
4823
- };
4824
- window.addEventListener('iframe-dimensions-applied', dimensionsListener);
4825
- }
4826
- function detach() {
4827
- if (dimensionsListener) {
4828
- window.removeEventListener('iframe-dimensions-applied', dimensionsListener);
4829
- dimensionsListener = null;
4830
- }
4831
- }
4832
-
4833
5134
  /**
4834
5135
  * Default iframe dimension calculation.
4835
5136
  * Used as fallback when no fix overrides getDimensions().
@@ -4853,41 +5154,58 @@ function getFinalWidth(doc) {
4853
5154
  * Phase 3: afterProcess (shop → global)
4854
5155
  * Phase 4: getDimensions (shop → global → default)
4855
5156
  */
4856
- const logger$2 = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
5157
+ const logger = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
4857
5158
  function configure(debug) {
4858
- logger$2.configure({ enabled: debug });
5159
+ logger.configure({ enabled: debug });
4859
5160
  }
4860
5161
  async function run$1(ctx, activeGlobal, shopFix) {
4861
5162
  // ── Phase 1: beforeProcess ────────────────────────────────────────────────
5163
+ const t1 = perf$3.mark('phase1.beforeProcess');
4862
5164
  for (const fix of activeGlobal) {
4863
5165
  if (fix.beforeProcess) {
4864
- logger$2.log(`[beforeProcess] ${fix.name}`);
5166
+ logger.log(`[beforeProcess] ${fix.name}`);
5167
+ const t = perf$3.mark(`phase1.${fix.name}.beforeProcess`);
4865
5168
  await fix.beforeProcess(ctx);
5169
+ perf$3.measure(`phase1.${fix.name}.beforeProcess`, t);
4866
5170
  }
4867
5171
  }
4868
5172
  if (shopFix?.beforeProcess) {
4869
- logger$2.log('[beforeProcess] shop');
5173
+ logger.log('[beforeProcess] shop');
5174
+ const t = perf$3.mark('phase1.shop.beforeProcess');
4870
5175
  await shopFix.beforeProcess(ctx);
5176
+ perf$3.measure('phase1.shop.beforeProcess', t);
4871
5177
  }
5178
+ perf$3.measure('phase1.beforeProcess', t1);
4872
5179
  // ── Phase 2: process ──────────────────────────────────────────────────────
5180
+ const t2 = perf$3.mark('phase2.process');
4873
5181
  for (const fix of activeGlobal) {
4874
5182
  if (fix.process) {
4875
- logger$2.log(`[process] ${fix.name}`);
5183
+ logger.log(`[process] ${fix.name}`);
5184
+ const t = perf$3.mark(`phase2.${fix.name}.process`);
4876
5185
  await fix.process(ctx);
5186
+ perf$3.measure(`phase2.${fix.name}.process`, t);
4877
5187
  }
4878
5188
  }
5189
+ perf$3.measure('phase2.process', t2);
4879
5190
  // ── Phase 3: afterProcess ─────────────────────────────────────────────────
5191
+ const t3 = perf$3.mark('phase3.afterProcess');
4880
5192
  if (shopFix?.afterProcess) {
4881
- logger$2.log('[afterProcess] shop');
5193
+ logger.log('[afterProcess] shop');
5194
+ const t = perf$3.mark('phase3.shop.afterProcess');
4882
5195
  await shopFix.afterProcess(ctx);
5196
+ perf$3.measure('phase3.shop.afterProcess', t);
4883
5197
  }
4884
5198
  for (const fix of activeGlobal) {
4885
5199
  if (fix.afterProcess) {
4886
- logger$2.log(`[afterProcess] ${fix.name}`);
5200
+ logger.log(`[afterProcess] ${fix.name}`);
5201
+ const t = perf$3.mark(`phase3.${fix.name}.afterProcess`);
4887
5202
  await fix.afterProcess(ctx);
5203
+ perf$3.measure(`phase3.${fix.name}.afterProcess`, t);
4888
5204
  }
4889
5205
  }
5206
+ perf$3.measure('phase3.afterProcess', t3);
4890
5207
  // ── Phase 4: getDimensions ────────────────────────────────────────────────
5208
+ const t4 = perf$3.mark('phase4.getDimensions');
4891
5209
  return new Promise((resolve) => {
4892
5210
  requestAnimationFrame(() => {
4893
5211
  let dimensions = null;
@@ -4895,14 +5213,14 @@ async function run$1(ctx, activeGlobal, shopFix) {
4895
5213
  if (shopFix?.getDimensions) {
4896
5214
  dimensions = shopFix.getDimensions(ctx);
4897
5215
  if (dimensions)
4898
- logger$2.log('Dimensions from shop fix:', dimensions);
5216
+ logger.log('Dimensions from shop fix:', dimensions);
4899
5217
  }
4900
5218
  if (!dimensions) {
4901
5219
  for (const fix of activeGlobal) {
4902
5220
  if (fix.getDimensions) {
4903
5221
  dimensions = fix.getDimensions(ctx);
4904
5222
  if (dimensions) {
4905
- logger$2.log(`Dimensions from global fix [${fix.name}]:`, dimensions);
5223
+ logger.log(`Dimensions from global fix [${fix.name}]:`, dimensions);
4906
5224
  break;
4907
5225
  }
4908
5226
  }
@@ -4911,7 +5229,8 @@ async function run$1(ctx, activeGlobal, shopFix) {
4911
5229
  if (!dimensions) {
4912
5230
  dimensions = { height: getFinalHeight(ctx.doc, ctx.win), width: getFinalWidth(ctx.doc) };
4913
5231
  }
4914
- logger$2.log('Final dimensions:', dimensions);
5232
+ logger.log('Final dimensions:', dimensions);
5233
+ perf$3.measure('phase4.getDimensions', t4);
4915
5234
  resolve(dimensions);
4916
5235
  });
4917
5236
  });
@@ -4988,233 +5307,288 @@ register(`566240210141053597`, {
4988
5307
  afterProcess: restoreAndFixLayout,
4989
5308
  });
4990
5309
 
4991
- const logger$1 = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
4992
- // ─── State ────────────────────────────────────────────────────────────────────
4993
- let doc = null;
4994
- let win = null;
4995
- let config$1 = null;
4996
- let shopFix = null;
4997
- let running$2 = false;
4998
- // ─── Public API ───────────────────────────────────────────────────────────────
4999
- function start$3(iframe, cfg) {
5000
- if (running$2) {
5001
- logger$1.warn('Already running. Call stop() first.');
5310
+ // ── Module-level functions ────────────────────────────────────────────────────
5311
+ function start$2(s, iframe, cfg) {
5312
+ if (s.running) {
5313
+ s.logger.warn('Already running. Call stop() first.');
5002
5314
  return;
5003
5315
  }
5004
5316
  if (!iframe.contentDocument || !iframe.contentWindow) {
5005
5317
  throw new Error('Iframe document or window not accessible');
5006
5318
  }
5007
- doc = iframe.contentDocument;
5008
- win = iframe.contentWindow;
5009
- config$1 = cfg;
5010
- running$2 = true;
5011
- shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5012
- if (shopFix) {
5013
- logger$1.log(`Shop fix loaded for "${cfg.shopId}":`, shopFix.description ?? '(no description)');
5014
- }
5015
- logger$1.configure({ enabled: !!cfg.debug });
5319
+ s.doc = iframe.contentDocument;
5320
+ s.win = iframe.contentWindow;
5321
+ s.config = cfg;
5322
+ s.running = true;
5323
+ s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5324
+ if (s.shopFix)
5325
+ s.logger.log(`Shop fix loaded for "${cfg.shopId}":`, s.shopFix.description ?? '(no description)');
5326
+ s.logger.configure({ enabled: !!cfg.debug });
5016
5327
  configure(!!cfg.debug);
5017
- start$4(doc, win, cfg, { debug: !!cfg.debug });
5018
- attach(cfg.debug);
5019
- logger$1.log('Started');
5328
+ s.enforcer.start(s.doc, s.win, cfg, { debug: !!cfg.debug });
5329
+ s.listeners.attach(cfg.debug);
5330
+ s.logger.log('Started');
5020
5331
  }
5021
- function stop$3() {
5022
- if (!running$2)
5332
+ function stop$2(s) {
5333
+ if (!s.running)
5023
5334
  return;
5024
- stop$4();
5025
- detach();
5026
- doc = null;
5027
- win = null;
5028
- config$1 = null;
5029
- shopFix = null;
5030
- running$2 = false;
5031
- logger$1.log('Stopped');
5032
- }
5033
- async function run() {
5034
- if (!running$2 || !doc || !win || !config$1) {
5035
- logger$1.warn('Not running. Call start() first.');
5335
+ s.enforcer.stop();
5336
+ s.listeners.detach();
5337
+ s.doc = null;
5338
+ s.win = null;
5339
+ s.config = null;
5340
+ s.shopFix = null;
5341
+ s.running = false;
5342
+ s.logger.log('Stopped');
5343
+ }
5344
+ async function run(s) {
5345
+ if (!s.running || !s.doc || !s.win || !s.config) {
5346
+ s.logger.warn('Not running. Call start() first.');
5036
5347
  return { height: 1000, width: 1000 };
5037
5348
  }
5038
5349
  const ctx = {
5039
- doc,
5040
- win,
5041
- deviceType: config$1.deviceType,
5042
- targetWidth: config$1.targetWidth,
5043
- targetHeight: config$1.targetHeight,
5044
- debug: config$1.debug,
5350
+ doc: s.doc,
5351
+ win: s.win,
5352
+ deviceType: s.config.deviceType,
5353
+ targetWidth: s.config.targetWidth,
5354
+ targetHeight: s.config.targetHeight,
5355
+ debug: s.config.debug,
5356
+ enforcer: s.enforcer,
5045
5357
  };
5046
5358
  const activeGlobal = getActiveFixes(ctx);
5047
- if (activeGlobal.length > 0) {
5048
- logger$1.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
5049
- }
5359
+ if (activeGlobal.length > 0)
5360
+ s.logger.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
5361
+ const tRun = perf$3.mark('viewport.run');
5050
5362
  try {
5051
- return await run$1(ctx, activeGlobal, shopFix);
5363
+ const result = await run$1(ctx, activeGlobal, s.shopFix);
5364
+ perf$3.measure('viewport.run', tRun);
5365
+ return result;
5052
5366
  }
5053
5367
  catch (err) {
5054
- logger$1.error('Critical error:', err);
5055
- return { height: doc.body?.scrollHeight || 1000, width: doc.body?.scrollWidth || 1000 };
5368
+ perf$3.measure('viewport.run', tRun);
5369
+ s.logger.error('Critical error:', err);
5370
+ return { height: s.doc.body?.scrollHeight || 1000, width: s.doc.body?.scrollWidth || 1000 };
5056
5371
  }
5057
5372
  }
5058
-
5059
- const logger = createLogger({
5060
- enabled: false,
5061
- prefix: 'IframeFixer',
5062
- });
5063
- // ============================================================================
5064
- // State
5065
- // ============================================================================
5066
- let iframe = null;
5067
- let config = null;
5068
- let running$1 = false;
5069
- let loadListener = null;
5070
- // ============================================================================
5071
- // Core API Functions
5072
- // ============================================================================
5073
- function start$2(cfg) {
5074
- if (running$1) {
5075
- logger.warn('Fixer is already running. Call stop() first.');
5373
+ function updateConfig$1(s, cfg) {
5374
+ if (!s.running || !s.config) {
5375
+ s.logger.warn('Not running. Call start() first.');
5076
5376
  return;
5077
5377
  }
5078
- iframe = cfg.iframe;
5079
- config = cfg;
5080
- running$1 = true;
5081
- logger.configure({ enabled: !!cfg.debug });
5082
- logger.log('Iframe fixer started');
5083
- initialize();
5378
+ s.config = { ...s.config, ...cfg };
5379
+ if (cfg.shopId !== undefined)
5380
+ s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5381
+ s.enforcer.updateConfig(cfg);
5382
+ s.logger.log('Config updated');
5383
+ }
5384
+ // ── Factory ───────────────────────────────────────────────────────────────────
5385
+ function createViewportProcessor() {
5386
+ const s = {
5387
+ logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
5388
+ enforcer: createEnforcer(),
5389
+ listeners: createViewportListeners(),
5390
+ doc: null,
5391
+ win: null,
5392
+ config: null,
5393
+ shopFix: null,
5394
+ running: false,
5395
+ };
5396
+ return {
5397
+ start: (iframe, cfg) => start$2(s, iframe, cfg),
5398
+ stop: () => stop$2(s),
5399
+ run: () => run(s),
5400
+ updateConfig: (cfg) => updateConfig$1(s, cfg),
5401
+ isRunning: () => s.running,
5402
+ };
5084
5403
  }
5085
- function stop$2() {
5086
- if (!running$1) {
5404
+
5405
+ // ── Module-level functions ────────────────────────────────────────────────────
5406
+ function dispatchDimensionsEvent(dimensions) {
5407
+ window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: dimensions }));
5408
+ }
5409
+ async function process(s) {
5410
+ if (!s.iframe || !s.config)
5087
5411
  return;
5088
- }
5089
- // Stop viewport replacer
5090
- stop$3();
5091
- stop$5();
5092
- // Remove load listener
5093
- if (iframe && loadListener) {
5094
- iframe.removeEventListener('load', loadListener);
5095
- loadListener = null;
5096
- }
5097
- iframe = null;
5098
- config = null;
5099
- running$1 = false;
5100
- logger.log('Iframe fixer stopped');
5101
- }
5102
- async function initialize() {
5103
- if (!iframe || !config) {
5104
- logger.error('iframe not found');
5105
- config?.onError?.(new Error('iframe not found'));
5412
+ if (!s.iframe.contentDocument || !s.iframe.contentWindow) {
5413
+ s.logger.error('Cannot access iframe document');
5414
+ s.config.onError?.(new Error('Cannot access iframe document'));
5106
5415
  return;
5107
5416
  }
5108
- // Wait for iframe to load completely
5109
- if (iframe.contentDocument?.readyState === 'complete') {
5110
- await process();
5417
+ const sessionId = `render-${Date.now()}`;
5418
+ perf$3.startSession(sessionId);
5419
+ const t0 = perf$3.mark('orchestrator.process');
5420
+ try {
5421
+ s.logger.groupCollapsed('Processing...');
5422
+ s.viewportReplacer.start(s.iframe, s.config);
5423
+ s.navigationBlocker.start(s.iframe, { debug: s.config.debug });
5424
+ const result = await s.viewportReplacer.run();
5425
+ perf$3.measure('orchestrator.process', t0);
5426
+ perf$3.endSession();
5427
+ s.logger.groupEnd();
5428
+ s.logger.log('Process completed:', result);
5429
+ s.config.onSuccess?.(result);
5430
+ dispatchDimensionsEvent(result);
5111
5431
  }
5112
- else {
5113
- loadListener = handleIframeLoad;
5114
- iframe.addEventListener('load', loadListener);
5432
+ catch (error) {
5433
+ perf$3.measure('orchestrator.process', t0);
5434
+ perf$3.endSession();
5435
+ s.logger.error('Failed to process:', error);
5436
+ s.config.onError?.(error);
5115
5437
  }
5116
5438
  }
5117
- async function process() {
5118
- if (!iframe || !config)
5119
- return;
5120
- if (!iframe.contentDocument || !iframe.contentWindow) {
5121
- logger.error('Cannot access iframe document');
5122
- config.onError?.(new Error('Cannot access iframe document'));
5439
+ async function initialize(s) {
5440
+ if (!s.iframe || !s.config) {
5441
+ s.logger.error('iframe not found');
5442
+ s.config?.onError?.(new Error('iframe not found'));
5123
5443
  return;
5124
5444
  }
5125
- try {
5126
- logger.log('Processing viewport units...');
5127
- start$3(iframe, config);
5128
- start$5(iframe, { debug: config.debug });
5129
- const result = await run();
5130
- logger.log('Process completed:', result);
5131
- config.onSuccess?.(result);
5132
- dispatchDimensionsEvent(result);
5133
- // Optionally setup height observer
5134
- // setupHeightObserver();
5445
+ if (s.iframe.contentDocument?.readyState === 'complete') {
5446
+ await process(s);
5135
5447
  }
5136
- catch (error) {
5137
- logger.error('Failed to process:', error);
5138
- config.onError?.(error);
5448
+ else {
5449
+ s.loadListener = () => process(s);
5450
+ s.iframe.addEventListener('load', s.loadListener);
5139
5451
  }
5140
5452
  }
5141
- // ============================================================================
5142
- // Helper Functions
5143
- // ============================================================================
5144
- function dispatchDimensionsEvent(dimensions) {
5145
- window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', {
5146
- detail: dimensions,
5147
- }));
5453
+ function start$1(s, cfg) {
5454
+ if (s.running) {
5455
+ s.logger.warn('Fixer is already running. Call stop() first.');
5456
+ return;
5457
+ }
5458
+ s.iframe = cfg.iframe;
5459
+ s.config = cfg;
5460
+ s.running = true;
5461
+ s.logger.configure({ enabled: !!cfg.debug });
5462
+ s.logger.log('Started');
5463
+ initialize(s);
5148
5464
  }
5149
- function handleIframeLoad() {
5150
- process();
5465
+ function stop$1(s) {
5466
+ if (!s.running)
5467
+ return;
5468
+ s.viewportReplacer.stop();
5469
+ s.heightObserver.stop();
5470
+ s.navigationBlocker.stop();
5471
+ if (s.iframe && s.loadListener) {
5472
+ s.iframe.removeEventListener('load', s.loadListener);
5473
+ s.loadListener = null;
5474
+ }
5475
+ s.iframe = null;
5476
+ s.config = null;
5477
+ s.running = false;
5478
+ s.logger.log('Stopped');
5479
+ }
5480
+ async function recalculate$1(s) {
5481
+ if (!s.running) {
5482
+ s.logger.warn('Fixer is not running.');
5483
+ return;
5484
+ }
5485
+ s.logger.log('Recalculating...');
5486
+ await process(s);
5151
5487
  }
5152
- /**
5153
- * Enable navigation blocking
5154
- */
5155
- function enableNavigationBlocking$2() {
5156
- if (!running$1) {
5157
- logger.warn('Fixer is not running. Call start() first.');
5488
+ function updateConfig(s, cfg) {
5489
+ if (!s.running || !s.config) {
5490
+ s.logger.warn('Fixer is not running.');
5158
5491
  return;
5159
5492
  }
5160
- enable();
5493
+ s.config = { ...s.config, ...cfg };
5494
+ s.viewportReplacer.updateConfig(cfg);
5495
+ s.logger.log('Config updated');
5496
+ }
5497
+ // ── Factory ───────────────────────────────────────────────────────────────────
5498
+ function createOrchestrator() {
5499
+ const s = {
5500
+ logger: createLogger({ enabled: false, prefix: 'IframeFixer' }),
5501
+ viewportReplacer: createViewportProcessor(),
5502
+ navigationBlocker: createNavigationBlocker(),
5503
+ heightObserver: createHeightObserver(),
5504
+ iframe: null,
5505
+ config: null,
5506
+ running: false,
5507
+ loadListener: null,
5508
+ };
5509
+ return {
5510
+ start: (cfg) => start$1(s, cfg),
5511
+ stop: () => stop$1(s),
5512
+ recalculate: () => recalculate$1(s),
5513
+ updateConfig: (cfg) => updateConfig(s, cfg),
5514
+ enableNavigationBlocking: () => s.navigationBlocker.enable(),
5515
+ enableNavigationBlockingMessage: () => s.navigationBlocker.enableMessage(),
5516
+ disableNavigationBlocking: () => s.navigationBlocker.disable(),
5517
+ disableNavigationBlockingMessage: () => s.navigationBlocker.disableMessage(),
5518
+ isRunning: () => s.running,
5519
+ getStateInfo: () => ({
5520
+ isRunning: s.running,
5521
+ hasIframe: !!s.iframe,
5522
+ hasConfig: !!s.config,
5523
+ hasNavigationBlocker: s.navigationBlocker.isRunning(),
5524
+ hasHeightObserver: s.heightObserver.isRunning(),
5525
+ viewportReplacerRunning: s.viewportReplacer.isRunning(),
5526
+ }),
5527
+ };
5161
5528
  }
5162
5529
 
5163
5530
  /**
5164
- * Iframe Helper Starter Module
5165
- * @module start
5531
+ * Iframe Helper factory entry point.
5532
+ *
5533
+ * Each call to `createIframeHelper()` returns a fully isolated instance
5534
+ * with its own processor state. Use one instance per iframe.
5166
5535
  */
5167
- // ============================================================================
5168
- // State
5169
- // ============================================================================
5170
- let running = false;
5171
- // ============================================================================
5172
- // Public API
5173
- // ============================================================================
5174
- function start$1(config) {
5175
- if (running) {
5176
- console.warn('[IframeHelperStarter] Already running. Call stop() first.');
5536
+ // ── Module-level functions ────────────────────────────────────────────────────
5537
+ function start(s, config) {
5538
+ if (s.running) {
5539
+ console.warn('[IframeHelper] Already running. Call stop() first.');
5177
5540
  return;
5178
5541
  }
5179
- start$2(config);
5180
- running = true;
5542
+ s.fixer.start(config);
5543
+ s.running = true;
5181
5544
  }
5182
- function stop$1() {
5183
- if (!running) {
5545
+ function stop(s) {
5546
+ if (!s.running)
5184
5547
  return;
5185
- }
5186
- stop$2();
5187
- running = false;
5548
+ s.fixer.stop();
5549
+ s.running = false;
5188
5550
  }
5189
- function enableNavigationBlocking$1() {
5190
- if (!running) {
5191
- console.warn('[IframeHelperStarter] Not running. Call start() first.');
5551
+ async function recalculate(s) {
5552
+ if (!s.running) {
5553
+ console.warn('[IframeHelper] Not running. Call start() first.');
5192
5554
  return;
5193
5555
  }
5194
- enableNavigationBlocking$2();
5556
+ await s.fixer.recalculate();
5195
5557
  }
5196
-
5197
- function start(config) {
5198
- start$1(config);
5199
- }
5200
- function stop() {
5201
- stop$1();
5558
+ function enableNavigationBlocking(s) {
5559
+ if (!s.running) {
5560
+ console.warn('[IframeHelper] Not running. Call start() first.');
5561
+ return;
5562
+ }
5563
+ s.fixer.enableNavigationBlocking();
5202
5564
  }
5203
- function enableNavigationBlocking() {
5204
- enableNavigationBlocking$1();
5565
+ // ── Factory ───────────────────────────────────────────────────────────────────
5566
+ function createIframeHelper() {
5567
+ const s = {
5568
+ fixer: createOrchestrator(),
5569
+ running: false,
5570
+ };
5571
+ return {
5572
+ start: (config) => start(s, config),
5573
+ stop: () => stop(s),
5574
+ recalculate: () => recalculate(s),
5575
+ enableNavigationBlocking: () => enableNavigationBlocking(s),
5576
+ isRunning: () => s.running,
5577
+ };
5205
5578
  }
5206
5579
 
5580
+ const iframeHelper = createIframeHelper();
5207
5581
  function useVizLiveRender() {
5208
5582
  const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
5209
5583
  const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
5210
5584
  const wrapperWidth = useHeatmapVizRectContext((s) => s.wrapperWidth);
5211
- const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
5212
- const htmlContent = useHeatmapLiveStore((s) => s.htmlContent);
5213
- const targetUrl = useHeatmapLiveStore((s) => s.targetUrl);
5585
+ const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
5586
+ const htmlContent = useHeatmapLiveContext((s) => s.htmlContent);
5587
+ const targetUrl = useHeatmapLiveContext((s) => s.targetUrl);
5214
5588
  const deviceType = useHeatmapSettingContext((s) => s.deviceType);
5215
- const renderMode = useHeatmapLiveStore((s) => s.renderMode);
5216
- const storefrontPassword = useHeatmapLiveStore((s) => s.storefrontPassword);
5217
- useHeatmapWidthByDevice();
5589
+ const renderMode = useHeatmapLiveContext((s) => s.renderMode);
5590
+ const storefrontPassword = useHeatmapLiveContext((s) => s.storefrontPassword);
5591
+ useHeatmapViewportByDevice();
5218
5592
  const { iframeRef, isReady } = useVizLiveIframeMsg();
5219
5593
  // Handle iframe rendering based on mode
5220
5594
  useEffect(() => {
@@ -5254,10 +5628,10 @@ function useVizLiveRender() {
5254
5628
  const hasContent = (renderMode === 'portal' && targetUrl) || (renderMode === 'inline' && htmlContent);
5255
5629
  if (!iframe || !hasContent)
5256
5630
  return;
5257
- setIsRenderViz(true);
5258
- initIframeHelper$1(iframe, deviceType, { width: wrapperWidth, height: wrapperHeight }, (height) => {
5631
+ setIsDomLoaded(true);
5632
+ startIframe$1(iframe, deviceType, { width: wrapperWidth, height: wrapperHeight }, (height) => {
5259
5633
  height && setIframeHeight(height);
5260
- setIsRenderViz(true);
5634
+ setIsDomLoaded(true);
5261
5635
  });
5262
5636
  return () => { };
5263
5637
  }, [
@@ -5269,7 +5643,7 @@ function useVizLiveRender() {
5269
5643
  targetUrl,
5270
5644
  htmlContent,
5271
5645
  iframeRef,
5272
- setIsRenderViz,
5646
+ setIsDomLoaded,
5273
5647
  setIframeHeight,
5274
5648
  ]);
5275
5649
  return {
@@ -5288,9 +5662,9 @@ function buildPortalUrl(targetUrl, storefrontPassword) {
5288
5662
  const portalServiceUrl = getPortalServiceUrl();
5289
5663
  return `${portalServiceUrl}/?${params.toString()}`;
5290
5664
  }
5291
- function initIframeHelper$1(iframe, deviceType = EDeviceType.Desktop, rect, onSuccess) {
5292
- stop();
5293
- start({
5665
+ function startIframe$1(iframe, deviceType = EDeviceType.Desktop, rect, onSuccess) {
5666
+ iframeHelper.stop();
5667
+ iframeHelper.start({
5294
5668
  deviceType: deviceType,
5295
5669
  targetWidth: rect.width,
5296
5670
  targetHeight: rect.height,
@@ -5301,8 +5675,111 @@ function initIframeHelper$1(iframe, deviceType = EDeviceType.Desktop, rect, onSu
5301
5675
  },
5302
5676
  });
5303
5677
  // fixer.recalculate();
5304
- enableNavigationBlocking();
5678
+ iframeHelper.enableNavigationBlocking();
5679
+ }
5680
+
5681
+ const DEFAULT_CONFIG = {
5682
+ dbName: 'gx-viz-html-cache',
5683
+ maxEntries: 20,
5684
+ ttlMs: 24 * 60 * 60 * 1000, // 24 hours
5685
+ cacheVersion: 3.0,
5686
+ };
5687
+ let _config = { ...DEFAULT_CONFIG };
5688
+ function getHtmlCacheConfig() {
5689
+ return _config;
5690
+ }
5691
+ /** Build a full cache key that includes the cache version to handle invalidation. */
5692
+ function buildCacheKey(baseKey, shortCircuitStrategy = 0) {
5693
+ return `v${_config.cacheVersion}:${baseKey}:${shortCircuitStrategy}`;
5694
+ }
5695
+
5696
+ const STORE_NAME = 'entries';
5697
+ const IDB_SCHEMA_VERSION = 1;
5698
+ function openDb() {
5699
+ const { dbName } = getHtmlCacheConfig();
5700
+ return new Promise((resolve, reject) => {
5701
+ const req = indexedDB.open(dbName, IDB_SCHEMA_VERSION);
5702
+ req.onupgradeneeded = () => {
5703
+ const db = req.result;
5704
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
5705
+ const store = db.createObjectStore(STORE_NAME, { keyPath: 'key' });
5706
+ store.createIndex('timestamp', 'timestamp');
5707
+ }
5708
+ };
5709
+ req.onsuccess = () => resolve(req.result);
5710
+ req.onerror = () => reject(req.error);
5711
+ });
5305
5712
  }
5713
+ async function evict(db) {
5714
+ const { maxEntries } = getHtmlCacheConfig();
5715
+ return new Promise((resolve) => {
5716
+ const tx = db.transaction(STORE_NAME, 'readwrite');
5717
+ const store = tx.objectStore(STORE_NAME);
5718
+ const countReq = store.count();
5719
+ countReq.onsuccess = () => {
5720
+ if (countReq.result <= maxEntries) {
5721
+ resolve();
5722
+ return;
5723
+ }
5724
+ const idx = store.index('timestamp');
5725
+ const cursorReq = idx.openCursor();
5726
+ let toDelete = countReq.result - maxEntries;
5727
+ cursorReq.onsuccess = () => {
5728
+ const cursor = cursorReq.result;
5729
+ if (cursor && toDelete > 0) {
5730
+ cursor.delete();
5731
+ toDelete--;
5732
+ cursor.continue();
5733
+ }
5734
+ else {
5735
+ resolve();
5736
+ }
5737
+ };
5738
+ cursorReq.onerror = () => resolve();
5739
+ };
5740
+ countReq.onerror = () => resolve();
5741
+ });
5742
+ }
5743
+ const htmlCache = {
5744
+ async get(key) {
5745
+ try {
5746
+ const { ttlMs } = getHtmlCacheConfig();
5747
+ const db = await openDb();
5748
+ return new Promise((resolve) => {
5749
+ const tx = db.transaction(STORE_NAME, 'readonly');
5750
+ const req = tx.objectStore(STORE_NAME).get(key);
5751
+ req.onsuccess = () => {
5752
+ const entry = req.result;
5753
+ if (!entry || Date.now() - entry.timestamp > ttlMs) {
5754
+ resolve(null);
5755
+ }
5756
+ else {
5757
+ resolve(entry);
5758
+ }
5759
+ };
5760
+ req.onerror = () => resolve(null);
5761
+ });
5762
+ }
5763
+ catch {
5764
+ return null;
5765
+ }
5766
+ },
5767
+ async set(entry) {
5768
+ try {
5769
+ const db = await openDb();
5770
+ await new Promise((resolve, reject) => {
5771
+ const tx = db.transaction(STORE_NAME, 'readwrite');
5772
+ tx.objectStore(STORE_NAME).put(entry);
5773
+ tx.oncomplete = () => resolve();
5774
+ tx.onerror = () => reject(tx.error);
5775
+ });
5776
+ await evict(db);
5777
+ }
5778
+ catch {
5779
+ // ignore cache write errors
5780
+ }
5781
+ },
5782
+ };
5306
5783
 
5307
5784
  const CANVAS_ID = 'clarity-heatmap-canvas';
5308
5785
  const ATTENTION_HUES = [240, 210, 180, 150, 120, 90, 60, 30, 0];
@@ -5512,6 +5989,316 @@ class AttentionMapRenderer {
5512
5989
  };
5513
5990
  }
5514
5991
 
5992
+ var Event;
5993
+ (function (Event) {
5994
+ /* Data */
5995
+ Event[Event["Metric"] = 0] = "Metric";
5996
+ Event[Event["Dimension"] = 1] = "Dimension";
5997
+ Event[Event["Upload"] = 2] = "Upload";
5998
+ Event[Event["Upgrade"] = 3] = "Upgrade";
5999
+ Event[Event["Baseline"] = 4] = "Baseline";
6000
+ Event[Event["Discover"] = 5] = "Discover";
6001
+ Event[Event["Mutation"] = 6] = "Mutation";
6002
+ Event[Event["Region"] = 7] = "Region";
6003
+ Event[Event["Document"] = 8] = "Document";
6004
+ Event[Event["Click"] = 9] = "Click";
6005
+ Event[Event["Scroll"] = 10] = "Scroll";
6006
+ Event[Event["Resize"] = 11] = "Resize";
6007
+ Event[Event["MouseMove"] = 12] = "MouseMove";
6008
+ Event[Event["MouseDown"] = 13] = "MouseDown";
6009
+ Event[Event["MouseUp"] = 14] = "MouseUp";
6010
+ Event[Event["MouseWheel"] = 15] = "MouseWheel";
6011
+ Event[Event["DoubleClick"] = 16] = "DoubleClick";
6012
+ Event[Event["TouchStart"] = 17] = "TouchStart";
6013
+ Event[Event["TouchEnd"] = 18] = "TouchEnd";
6014
+ Event[Event["TouchMove"] = 19] = "TouchMove";
6015
+ Event[Event["TouchCancel"] = 20] = "TouchCancel";
6016
+ Event[Event["Selection"] = 21] = "Selection";
6017
+ Event[Event["Timeline"] = 22] = "Timeline";
6018
+ Event[Event["Page"] = 23] = "Page";
6019
+ Event[Event["Custom"] = 24] = "Custom";
6020
+ Event[Event["Ping"] = 25] = "Ping";
6021
+ Event[Event["Unload"] = 26] = "Unload";
6022
+ Event[Event["Input"] = 27] = "Input";
6023
+ Event[Event["Visibility"] = 28] = "Visibility";
6024
+ Event[Event["Navigation"] = 29] = "Navigation";
6025
+ /**
6026
+ * @deprecated No longer support Network Connection
6027
+ */
6028
+ Event[Event["Connection"] = 30] = "Connection";
6029
+ Event[Event["ScriptError"] = 31] = "ScriptError";
6030
+ /**
6031
+ * @deprecated No longer support Image Error
6032
+ */
6033
+ Event[Event["ImageError"] = 32] = "ImageError";
6034
+ Event[Event["Log"] = 33] = "Log";
6035
+ Event[Event["Variable"] = 34] = "Variable";
6036
+ Event[Event["Limit"] = 35] = "Limit";
6037
+ Event[Event["Summary"] = 36] = "Summary";
6038
+ /**
6039
+ * @deprecated No longer support Box event
6040
+ */
6041
+ Event[Event["Box"] = 37] = "Box";
6042
+ Event[Event["Clipboard"] = 38] = "Clipboard";
6043
+ Event[Event["Submit"] = 39] = "Submit";
6044
+ Event[Event["Extract"] = 40] = "Extract";
6045
+ Event[Event["Fraud"] = 41] = "Fraud";
6046
+ Event[Event["Change"] = 42] = "Change";
6047
+ Event[Event["Snapshot"] = 43] = "Snapshot";
6048
+ Event[Event["Animation"] = 44] = "Animation";
6049
+ Event[Event["StyleSheetAdoption"] = 45] = "StyleSheetAdoption";
6050
+ Event[Event["StyleSheetUpdate"] = 46] = "StyleSheetUpdate";
6051
+ Event[Event["Consent"] = 47] = "Consent";
6052
+ Event[Event["ContextMenu"] = 48] = "ContextMenu";
6053
+ // 49 is reserved for internal use
6054
+ Event[Event["Focus"] = 50] = "Focus";
6055
+ Event[Event["CustomElement"] = 51] = "CustomElement";
6056
+ Event[Event["Chat"] = 52] = "Chat";
6057
+ // Apps specific events
6058
+ Event[Event["WebViewDiscover"] = 100] = "WebViewDiscover";
6059
+ Event[Event["WebViewMutation"] = 101] = "WebViewMutation";
6060
+ Event[Event["MutationError"] = 102] = "MutationError";
6061
+ Event[Event["FragmentVisibility"] = 103] = "FragmentVisibility";
6062
+ Event[Event["Keystrokes"] = 104] = "Keystrokes";
6063
+ Event[Event["BackGesture"] = 105] = "BackGesture";
6064
+ Event[Event["WebViewStatus"] = 106] = "WebViewStatus";
6065
+ Event[Event["AppInstallReferrer"] = 107] = "AppInstallReferrer";
6066
+ // 200-300 reserved for internal use
6067
+ })(Event || (Event = {}));
6068
+
6069
+ var Constant;
6070
+ (function (Constant) {
6071
+ Constant["Empty"] = "";
6072
+ Constant["SvgPrefix"] = "svg:";
6073
+ Constant["DataPrefix"] = "data:";
6074
+ Constant["IFramePrefix"] = "iframe:";
6075
+ Constant["SvgNamespace"] = "http://www.w3.org/2000/svg";
6076
+ Constant["Id"] = "id";
6077
+ Constant["Class"] = "class";
6078
+ Constant["Style"] = "style";
6079
+ Constant["Href"] = "href";
6080
+ Constant["Src"] = "src";
6081
+ Constant["Srcset"] = "srcset";
6082
+ Constant["Hash"] = "#";
6083
+ Constant["Dot"] = ".";
6084
+ Constant["Separator"] = ">";
6085
+ Constant["Tilde"] = "~";
6086
+ Constant["Bang"] = "!";
6087
+ Constant["Period"] = ".";
6088
+ Constant["Comma"] = ",";
6089
+ Constant["DataAttribute"] = "data-";
6090
+ Constant["MaskData"] = "data-clarity-mask";
6091
+ Constant["UnmaskData"] = "data-clarity-unmask";
6092
+ Constant["RegionData"] = "data-clarity-region";
6093
+ Constant["GXDialogModal"] = "gx-dialog-modal";
6094
+ Constant["Type"] = "type";
6095
+ Constant["Submit"] = "submit";
6096
+ Constant["Name"] = "name";
6097
+ Constant["Base"] = "*B";
6098
+ Constant["SameOrigin"] = "*O";
6099
+ Constant["Object"] = "object";
6100
+ Constant["Function"] = "function";
6101
+ Constant["StyleTag"] = "STYLE";
6102
+ Constant["LinkTag"] = "LINK";
6103
+ Constant["InputTag"] = "INPUT";
6104
+ Constant["IFrameTag"] = "IFRAME";
6105
+ Constant["ImageTag"] = "IMG";
6106
+ Constant["TitleTag"] = "TITLE";
6107
+ Constant["BodyTag"] = "BODY";
6108
+ Constant["SvgTag"] = "svg:svg";
6109
+ Constant["BaseTag"] = "BASE";
6110
+ Constant["NativeCode"] = "[native code]";
6111
+ Constant["DocumentTag"] = "*D";
6112
+ Constant["ShadowDomTag"] = "*S";
6113
+ Constant["PolyfillShadowDomTag"] = "*P";
6114
+ Constant["TextTag"] = "*T";
6115
+ Constant["SuspendMutationTag"] = "*M";
6116
+ Constant["ChildList"] = "childList";
6117
+ Constant["Attributes"] = "attributes";
6118
+ Constant["CharacterData"] = "characterData";
6119
+ Constant["Throttle"] = "throttle";
6120
+ Constant["LoadEvent"] = "load";
6121
+ Constant["Pixel"] = "px";
6122
+ Constant["BorderBox"] = "border-box";
6123
+ Constant["Value"] = "value";
6124
+ Constant["MutationObserver"] = "MutationObserver";
6125
+ Constant["JsonLD"] = "application/ld+json";
6126
+ Constant["String"] = "string";
6127
+ Constant["Number"] = "number";
6128
+ Constant["Disable"] = "disable";
6129
+ Constant["HTML"] = "HTML";
6130
+ Constant["Property"] = "property";
6131
+ Constant["Content"] = "content";
6132
+ Constant["Generator"] = "generator";
6133
+ Constant["ogType"] = "og:type";
6134
+ Constant["ogTitle"] = "og:title";
6135
+ Constant["SvgStyle"] = "svg:style";
6136
+ Constant["StyleSheet"] = "stylesheet";
6137
+ })(Constant || (Constant = {}));
6138
+
6139
+ var ShortCircuitStrategy;
6140
+ (function (ShortCircuitStrategy) {
6141
+ ShortCircuitStrategy[ShortCircuitStrategy["None"] = 0] = "None";
6142
+ ShortCircuitStrategy[ShortCircuitStrategy["HashFirstTimestamp"] = 1] = "HashFirstTimestamp";
6143
+ ShortCircuitStrategy[ShortCircuitStrategy["HashFirstTimestampPlusBuffer"] = 2] = "HashFirstTimestampPlusBuffer";
6144
+ ShortCircuitStrategy[ShortCircuitStrategy["HashBeforeDeleted"] = 3] = "HashBeforeDeleted";
6145
+ })(ShortCircuitStrategy || (ShortCircuitStrategy = {}));
6146
+
6147
+ function isShadowDomNode(tag) {
6148
+ return tag === Constant.ShadowDomTag || tag === Constant.PolyfillShadowDomTag;
6149
+ }
6150
+ /** Scan the rendered DOM (including nested shadow roots) to collect tag names of shadow host elements. */
6151
+ function collectShadowHostTags(root, tags = new Set()) {
6152
+ root.querySelectorAll('*').forEach((el) => {
6153
+ if (el.shadowRoot) {
6154
+ tags.add(el.tagName);
6155
+ collectShadowHostTags(el.shadowRoot, tags);
6156
+ }
6157
+ });
6158
+ return tags;
6159
+ }
6160
+ /** Build a shadow subtree ID set from all DOM events.
6161
+ * Two-pass cascade to handle any event ordering:
6162
+ * Pass 1 — seed *S/*P node IDs.
6163
+ * Pass 2 — cascade: any node whose parent is in the set is also in the set (repeat until stable). */
6164
+ function buildShadowSubtreeIds(allDomEvents) {
6165
+ const subtreeIds = new Set();
6166
+ for (const e of allDomEvents) {
6167
+ const data = e.data;
6168
+ for (const node of data ?? []) {
6169
+ if (isShadowDomNode(node.tag))
6170
+ subtreeIds.add(node.id);
6171
+ }
6172
+ }
6173
+ let changed = true;
6174
+ while (changed) {
6175
+ changed = false;
6176
+ for (const e of allDomEvents) {
6177
+ const data = e.data;
6178
+ for (const node of data ?? []) {
6179
+ if (!subtreeIds.has(node.id) && subtreeIds.has(node.parent)) {
6180
+ subtreeIds.add(node.id);
6181
+ changed = true;
6182
+ }
6183
+ }
6184
+ }
6185
+ }
6186
+ return subtreeIds;
6187
+ }
6188
+ function filterShadowNodes(data, subtreeIds, shadowHostTags) {
6189
+ return (data?.filter((node) => {
6190
+ if (isShadowDomNode(node.tag))
6191
+ return true;
6192
+ if (shadowHostTags.has(node.tag ?? ''))
6193
+ return true;
6194
+ return subtreeIds.has(node.id);
6195
+ }) ?? []);
6196
+ }
6197
+ /** Extract shadow DOM nodes from merged.dom (initial Discover event, processed by setup()).
6198
+ * Returns a filtered copy of the dom event, or null if no shadow DOM present. */
6199
+ function extractSpecialDom(dom, events, shadowHostTags) {
6200
+ const mutationEvents = events.filter((e) => e.event === Event.Mutation);
6201
+ const subtreeIds = buildShadowSubtreeIds([dom, ...mutationEvents]);
6202
+ const shadowNodes = filterShadowNodes(dom.data, subtreeIds, shadowHostTags);
6203
+ return shadowNodes.length ? { ...dom, data: shadowNodes } : null;
6204
+ }
6205
+ /** Extract shadow DOM mutations + StyleSheet + CustomElement events from merged.events. */
6206
+ function extractSpecialEvents(events, dom, shadowHostTags) {
6207
+ const mutationEvents = events.filter((e) => e.event === Event.Mutation);
6208
+ const subtreeIds = buildShadowSubtreeIds([dom, ...mutationEvents]);
6209
+ const result = [];
6210
+ for (const e of events) {
6211
+ const ev = e.event;
6212
+ if (ev === Event.StyleSheetAdoption ||
6213
+ ev === Event.StyleSheetUpdate ||
6214
+ ev === Event.CustomElement) {
6215
+ result.push(e);
6216
+ continue;
6217
+ }
6218
+ if (ev === Event.Mutation) {
6219
+ const shadowNodes = filterShadowNodes(e.data, subtreeIds, shadowHostTags);
6220
+ if (shadowNodes.length)
6221
+ result.push({ ...e, data: shadowNodes });
6222
+ }
6223
+ }
6224
+ return result;
6225
+ }
6226
+
6227
+ // utils/retry.ts
6228
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
6229
+ /**
6230
+ * Retry until the callback returns truthy, or throw if the limit is exceeded.
6231
+ *
6232
+ * @example
6233
+ * await retry(() => doc.readyState === 'complete', { timeout: 5000, label: 'DOM ready' });
6234
+ *
6235
+ * @example
6236
+ * const el = await retry(() => document.getElementById('app'), { maxRetries: 20 });
6237
+ */
6238
+ async function retry(callback, options = {}) {
6239
+ const { interval = 100, label = 'Retry' } = options;
6240
+ const maxRetries = options.timeout != null ? Math.ceil(options.timeout / interval) : (options.maxRetries ?? 50);
6241
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
6242
+ console.log(`🔄 [${label}] attempt ${attempt}/${maxRetries}`);
6243
+ const result = await callback();
6244
+ if (result) {
6245
+ return result;
6246
+ }
6247
+ if (attempt < maxRetries) {
6248
+ await delay(interval);
6249
+ }
6250
+ }
6251
+ const totalMs = maxRetries * interval;
6252
+ throw new Error(`[${label}] Timed out after ${maxRetries} retries (${totalMs}ms)`);
6253
+ }
6254
+
6255
+ const perf$2 = createPerfTimer('Render');
6256
+ const YIELD_INTERVAL_MS = 16;
6257
+ async function yieldToMain() {
6258
+ if ('scheduler' in globalThis && typeof globalThis.scheduler?.yield === 'function') {
6259
+ await globalThis.scheduler.yield();
6260
+ }
6261
+ else {
6262
+ await new Promise((resolve) => setTimeout(resolve, 0));
6263
+ }
6264
+ }
6265
+ const renderLoop = async (ctx, options) => {
6266
+ const { events, useproxy } = options;
6267
+ const shortCircuitStrategy = options.shortCircuitStrategy ?? ShortCircuitStrategy.None;
6268
+ const hash = options.hash ?? null;
6269
+ const t0 = perf$2.mark('RenderLoop start');
6270
+ let lastYield = performance.now();
6271
+ const totalEvents = events.length;
6272
+ for (let i = 0; i < totalEvents; i++) {
6273
+ const entry = events[i];
6274
+ const entryEvent = entry.event;
6275
+ const now = performance.now();
6276
+ if (now - lastYield > YIELD_INTERVAL_MS) {
6277
+ console.log(`[RenderLoop] ${i}/${totalEvents} time:`, now - lastYield);
6278
+ await yieldToMain();
6279
+ lastYield = performance.now();
6280
+ }
6281
+ switch (entryEvent) {
6282
+ case Event.StyleSheetAdoption:
6283
+ case Event.StyleSheetUpdate:
6284
+ ctx.layout.styleChange(entry);
6285
+ break;
6286
+ case Event.CustomElement:
6287
+ ctx.layout.customElement(entry);
6288
+ break;
6289
+ case Event.Mutation: {
6290
+ const domEvent = entry;
6291
+ ctx.renderTime = domEvent.time;
6292
+ if (ctx.shortCircuitRendering(shortCircuitStrategy, domEvent, hash))
6293
+ return;
6294
+ ctx.layout.markup(domEvent, useproxy);
6295
+ break;
6296
+ }
6297
+ }
6298
+ }
6299
+ perf$2.measure('RenderLoop', t0);
6300
+ };
6301
+
5515
6302
  class GXVisualizer extends Visualizer {
5516
6303
  attentionMap;
5517
6304
  originalClearmap;
@@ -5519,25 +6306,43 @@ class GXVisualizer extends Visualizer {
5519
6306
  constructor() {
5520
6307
  super();
5521
6308
  this.attentionMap = new AttentionMapRenderer(null);
5522
- // Save references to base implementations before overriding
5523
6309
  this.originalSetup = this.setup;
5524
6310
  this.originalClearmap = this.clearmap;
5525
6311
  this.clearmap = this.clearmapOverride;
5526
6312
  this.setup = this.setupOverride;
5527
6313
  }
5528
- setupOverride = async (target, options) => {
5529
- // Clear existing custom renderers before re-initializing (null-safe)
5530
- this.attentionMap?.clear();
5531
- // Initialize base Visualizer (sets this.state, this.heatmap, this.layout, etc.)
5532
- await this.originalSetup(target, options);
5533
- // Re-create custom renderers with the newly initialized PlaybackState
5534
- const state = this.state;
5535
- this.attentionMap = new AttentionMapRenderer(state);
6314
+ htmlRender = async (props) => {
6315
+ const { decoded, target, portalCanvasId, useproxy, logerror } = props;
6316
+ if (!decoded || decoded.length === 0 || !target)
6317
+ return this;
6318
+ try {
6319
+ const merged = this.mergeForHtml(decoded);
6320
+ await this.setup(target, { version: decoded[0].envelope.version, dom: merged.dom, useproxy, portalCanvasId });
6321
+ await this.renderLoop(this, { events: merged.events, target, useproxy });
6322
+ }
6323
+ catch (e) {
6324
+ if (logerror)
6325
+ logerror(e);
6326
+ }
5536
6327
  return this;
5537
6328
  };
5538
- clearmapOverride = () => {
5539
- this.originalClearmap();
5540
- this.attentionMap?.clear();
6329
+ htmlCached = async (cacheKey, options) => {
6330
+ const { decoded, target } = options;
6331
+ if (!decoded || decoded.length === 0 || !target)
6332
+ return this;
6333
+ const fullKey = buildCacheKey(cacheKey, options.shortCircuitStrategy);
6334
+ const cached = await htmlCache.get(fullKey);
6335
+ if (cached) {
6336
+ try {
6337
+ await this.buildHtmlByCached(cached, options);
6338
+ return this;
6339
+ }
6340
+ catch (e) {
6341
+ options?.logerror?.(e);
6342
+ }
6343
+ }
6344
+ await this.buildHtmlForCache(fullKey, options);
6345
+ return this;
5541
6346
  };
5542
6347
  /**
5543
6348
  * Render attention/engagement map.
@@ -5549,75 +6354,229 @@ class GXVisualizer extends Visualizer {
5549
6354
  this.clearmapOverride();
5550
6355
  this.attentionMap.attention(attentionData, avgFold, this, isSecondary);
5551
6356
  };
6357
+ buildHtmlByCached = async (cached, options) => {
6358
+ const { target, useproxy, portalCanvasId } = options;
6359
+ if (!cached || !target)
6360
+ throw new Error('Failed to render HTML cached');
6361
+ const doc = target.document;
6362
+ target.window;
6363
+ try {
6364
+ await this.setup(target, { version: cached.version, useproxy, portalCanvasId });
6365
+ doc.open();
6366
+ doc.write(cached.html);
6367
+ doc.close();
6368
+ const process = async () => {
6369
+ this.layout.hydrate(doc);
6370
+ // Replay shadow DOM from initial Discover event
6371
+ if (cached.specialDom) {
6372
+ this.layout.markup(cached.specialDom, useproxy);
6373
+ }
6374
+ // Replay shadow DOM mutations + StyleSheet + CustomElement
6375
+ await this.renderLoop(this, { ...options, events: cached.specialEvents });
6376
+ };
6377
+ await retry(() => doc.readyState === 'complete', { timeout: 30000, label: 'DOM ready' });
6378
+ await process();
6379
+ return this;
6380
+ }
6381
+ catch (e) {
6382
+ throw new Error('Failed to render HTML cached', { cause: e });
6383
+ }
6384
+ };
6385
+ buildHtmlForCache = async (cacheKey, options) => {
6386
+ const { decoded, target, useproxy, portalCanvasId, logerror } = options;
6387
+ if (!decoded || decoded.length === 0 || !target)
6388
+ return this;
6389
+ try {
6390
+ const merged = this.mergeForHtml(decoded);
6391
+ await this.setup(target, { version: decoded[0].envelope.version, dom: merged.dom, useproxy, portalCanvasId });
6392
+ await this.renderLoop(this, { events: merged.events, target, useproxy });
6393
+ const timestamp = Date.now();
6394
+ const version = decoded[0].envelope.version;
6395
+ const html = target.document.documentElement.outerHTML;
6396
+ const shadowHostTags = collectShadowHostTags(target.document);
6397
+ const specialDom = extractSpecialDom(merged.dom, merged.events, shadowHostTags);
6398
+ const specialEvents = extractSpecialEvents(merged.events, merged.dom, shadowHostTags);
6399
+ void htmlCache.set({ key: cacheKey, html, specialDom, specialEvents, version, timestamp });
6400
+ }
6401
+ catch (e) {
6402
+ if (logerror)
6403
+ logerror(e);
6404
+ }
6405
+ return this;
6406
+ };
6407
+ renderLoop = async (ctx, options) => {
6408
+ await renderLoop(ctx, options);
6409
+ };
6410
+ setupOverride = async (target, options) => {
6411
+ this.attentionMap?.clear();
6412
+ await this.originalSetup(target, options);
6413
+ this.attentionMap = new AttentionMapRenderer(this.state);
6414
+ return this;
6415
+ };
6416
+ clearmapOverride = () => {
6417
+ this.originalClearmap();
6418
+ this.attentionMap?.clear();
6419
+ };
5552
6420
  }
5553
6421
 
5554
- const useHeatmapRender = () => {
5555
- const viewId = useViewIdContext();
5556
- const data = useHeatmapDataContext((s) => s.data);
5557
- const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
5558
- const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
5559
- const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
5560
- const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
5561
- const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
5562
- const contentWidth = useHeatmapWidthByDevice();
6422
+ const perf$1 = createPerfTimer('Render');
6423
+ const useHeatmapIframeProcessor = () => {
6424
+ const shopId = useHeatmapConfigStore((s) => s.shopId);
5563
6425
  const deviceType = useHeatmapSettingContext((s) => s.deviceType);
5564
- const iframeRef = useRef(null);
5565
- const renderHeatmap = useCallback(async (payloads) => {
5566
- if (contentWidth === 0 || wrapperHeight === 0)
6426
+ const viewport = useHeatmapViewportByDevice();
6427
+ const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
6428
+ const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
6429
+ const helperRef = useRef(null);
6430
+ const pendingRef = useRef(null);
6431
+ const reset = useCallback(() => {
6432
+ pendingRef.current = null;
6433
+ }, []);
6434
+ const run = useCallback((iframe, t0, abort) => {
6435
+ if (viewport.width === 0 || viewport.height === 0) {
6436
+ pendingRef.current = { iframe, t0, abort };
5567
6437
  return;
5568
- if (!payloads || payloads.length === 0)
6438
+ }
6439
+ startIframe({
6440
+ helperRef,
6441
+ iframe,
6442
+ shopId,
6443
+ deviceType,
6444
+ size: viewport,
6445
+ t0,
6446
+ onSuccess: (height) => {
6447
+ if (abort.signal.aborted)
6448
+ return;
6449
+ if (height)
6450
+ setIframeHeight(height);
6451
+ setIsDomLoaded(true);
6452
+ },
6453
+ });
6454
+ }, [deviceType]);
6455
+ // Retry when dims become available
6456
+ useEffect(() => {
6457
+ if (viewport.width === 0 || viewport.height === 0)
5569
6458
  return;
5570
- const visualizer = vizRef ?? new GXVisualizer();
5571
- if (!vizRef)
5572
- setVizRef(visualizer);
5573
- setIsRenderViz(false);
5574
- const iframe = iframeRef.current;
5575
- if (!iframe?.contentWindow)
6459
+ if (!pendingRef.current)
5576
6460
  return;
5577
- await visualizer.html(payloads, iframe.contentWindow, viewId);
5578
- const size = { width: contentWidth, height: wrapperHeight };
5579
- initIframeHelper(iframe, deviceType, size, (height) => {
5580
- height && setIframeHeight(height);
5581
- setIsRenderViz(true);
6461
+ const { iframe, t0, abort } = pendingRef.current;
6462
+ pendingRef.current = null;
6463
+ if (abort.signal.aborted)
6464
+ return;
6465
+ startIframe({
6466
+ helperRef,
6467
+ iframe,
6468
+ shopId,
6469
+ deviceType,
6470
+ size: viewport,
6471
+ t0,
6472
+ onSuccess: (height) => {
6473
+ if (abort.signal.aborted)
6474
+ return;
6475
+ if (height)
6476
+ setIframeHeight(height);
6477
+ setIsDomLoaded(true);
6478
+ },
5582
6479
  });
5583
- // setIsRenderViz(true);
5584
- }, [wrapperHeight, contentWidth, deviceType]);
6480
+ }, [viewport]); // eslint-disable-line react-hooks/exhaustive-deps
5585
6481
  useEffect(() => {
5586
- if (!data || data.length === 0)
5587
- return;
5588
- const decoded = decodeArrayClarity(data);
5589
- renderHeatmap(decoded);
5590
6482
  return () => {
5591
- setVizRef(null);
6483
+ helperRef.current?.stop();
6484
+ helperRef.current = null;
5592
6485
  };
5593
- }, [data, renderHeatmap, setVizRef]);
5594
- return {
5595
- iframeRef,
5596
- };
6486
+ }, []);
6487
+ return { run, reset };
5597
6488
  };
5598
- function initIframeHelper(iframe, deviceType = EDeviceType.Desktop, size, onSuccess) {
6489
+ // ── Helpers ───────────────────────────────────────────────────────────────────
6490
+ function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Desktop, size, t0, onSuccess, }) {
5599
6491
  const docWidth = size.width ?? 0;
5600
6492
  const docHeight = size.height ?? 0;
5601
6493
  if (docHeight === 0)
5602
6494
  return;
5603
- stop();
5604
- start({
5605
- deviceType: deviceType,
6495
+ helperRef.current?.stop();
6496
+ const tHelper = perf$1.mark('IframeHelper.start');
6497
+ const helper = createIframeHelper();
6498
+ helperRef.current = helper;
6499
+ helper.start({
6500
+ deviceType,
5606
6501
  targetWidth: docWidth,
5607
6502
  targetHeight: docHeight,
5608
- iframe: iframe,
6503
+ iframe,
5609
6504
  debug: true,
6505
+ shopId,
5610
6506
  onSuccess: (data) => {
6507
+ perf$1.measure('IframeHelper processing', tHelper);
6508
+ perf$1.measure('Total render', t0);
5611
6509
  iframe.style.height = `${data.height}px`;
5612
6510
  onSuccess(data.height);
5613
6511
  },
5614
6512
  });
5615
- // fixer.recalculate();
5616
6513
  }
5617
6514
 
6515
+ const perf = createPerfTimer('Render');
6516
+ const useHeatmapRenderDom = () => {
6517
+ const viewId = useViewIdContext();
6518
+ const data = useHeatmapDataContext((s) => s.data);
6519
+ const excludeClassNames = useHeatmapConfigStore((s) => s.excludeClassNames);
6520
+ const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
6521
+ const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
6522
+ const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
6523
+ const deviceType = useHeatmapSettingContext((s) => s.deviceType);
6524
+ const heatmapType = useHeatmapSettingContext((s) => s.heatmapType);
6525
+ const elementToShow = useHeatmapDataContext((s) => s.dataInfo?.elementToShow);
6526
+ const dataHash = useHeatmapDataContext((s) => s.dataHash);
6527
+ const iframeRef = useRef(null);
6528
+ const abortRef = useRef(null);
6529
+ const elementToShowRef = useRef(null);
6530
+ const dataHashRef = useRef(null);
6531
+ const heatmapTypeRef = useRef(heatmapType);
6532
+ elementToShowRef.current = elementToShow ?? null;
6533
+ dataHashRef.current = dataHash ?? null;
6534
+ heatmapTypeRef.current = heatmapType;
6535
+ const { run: runIframeSetup, reset: resetIframeSetup } = useHeatmapIframeProcessor();
6536
+ const renderHeatmap = useCallback(async (payloads) => {
6537
+ if (!payloads || payloads.length === 0)
6538
+ return;
6539
+ const iframe = iframeRef.current;
6540
+ const contentWindow = iframe?.contentWindow;
6541
+ if (!contentWindow)
6542
+ return;
6543
+ abortRef.current?.abort();
6544
+ const abort = new AbortController();
6545
+ abortRef.current = abort;
6546
+ resetIframeSetup();
6547
+ const t0 = perf.mark('RenderHeatmap start');
6548
+ const visualizer = vizRef ?? new GXVisualizer();
6549
+ if (!vizRef)
6550
+ setVizRef(visualizer);
6551
+ visualizer.configure({ excludeClassNames });
6552
+ setIsDomLoaded(false);
6553
+ // Phase 1: render DOM — does not depend on contentWidth/wrapperHeight
6554
+ const cacheKey = dataHashRef.current;
6555
+ const options = {
6556
+ decoded: payloads,
6557
+ target: contentWindow,
6558
+ portalCanvasId: viewId,
6559
+ logerror: (error) => {
6560
+ console.error('Error rendering HTML', error);
6561
+ },
6562
+ };
6563
+ await perf.wrap('RenderHtml', () => cacheKey ? visualizer.htmlCached(cacheKey, options) : visualizer.htmlRender(options));
6564
+ if (abort.signal.aborted)
6565
+ return;
6566
+ // Phase 2: iframe setup — deferred to useIframeSetup (handles dims dependency)
6567
+ runIframeSetup(iframe, t0, abort);
6568
+ }, [deviceType]);
6569
+ useEffect(() => {
6570
+ if (!data || data.length === 0)
6571
+ return;
6572
+ renderHeatmap(decodeArrayClarity(data));
6573
+ }, [data, renderHeatmap]);
6574
+ return { iframeRef };
6575
+ };
6576
+
5618
6577
  const useReplayRender = () => {
5619
6578
  const data = useHeatmapDataContext((s) => s.data);
5620
- const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
6579
+ const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
5621
6580
  const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
5622
6581
  const visualizerRef = useRef(null);
5623
6582
  const iframeRef = useRef(null);
@@ -5637,7 +6596,7 @@ const useReplayRender = () => {
5637
6596
  version: envelope.version,
5638
6597
  onresize: (height) => {
5639
6598
  height && setIframeHeight(height);
5640
- setIsRenderViz(true);
6599
+ setIsDomLoaded(true);
5641
6600
  },
5642
6601
  mobile,
5643
6602
  vNext: true,
@@ -5740,10 +6699,12 @@ const useReplayRender = () => {
5740
6699
  const useHeatmapRenderByMode = (mode) => {
5741
6700
  const heatmapResult = useMemo(() => {
5742
6701
  switch (mode) {
5743
- case 'heatmap':
5744
- return useHeatmapRender;
5745
- case 'replay':
6702
+ case EHeatmapMode.Heatmap:
6703
+ return useHeatmapRenderDom;
6704
+ case EHeatmapMode.Replay:
5746
6705
  return useReplayRender;
6706
+ default:
6707
+ return useHeatmapRenderDom;
5747
6708
  }
5748
6709
  }, [mode]);
5749
6710
  return heatmapResult();
@@ -5778,22 +6739,10 @@ const useContainerDimensions = (props) => {
5778
6739
  return { containerWidth, containerHeight };
5779
6740
  };
5780
6741
 
5781
- const useContentDimensions = ({ iframeRef }) => {
5782
- const contentWidth = useHeatmapWidthByDevice();
5783
- useEffect(() => {
5784
- if (!contentWidth)
5785
- return;
5786
- if (!iframeRef.current)
5787
- return;
5788
- // iframeRef.current.width = `${contentWidth}px`;
5789
- }, [contentWidth, iframeRef]);
5790
- return { contentWidth };
5791
- };
5792
-
5793
6742
  const useObserveIframeHeight = (props) => {
5794
6743
  const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
5795
6744
  const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
5796
- const isRenderViz = useHeatmapVizContext((s) => s.isRenderViz);
6745
+ const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
5797
6746
  const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
5798
6747
  const { iframeRef } = props;
5799
6748
  const resizeObserverRef = useRef(null);
@@ -5854,7 +6803,7 @@ const useObserveIframeHeight = (props) => {
5854
6803
  }, [updateIframeHeight]);
5855
6804
  useEffect(() => {
5856
6805
  const iframe = iframeRef.current;
5857
- if (!iframe || !iframeHeight || !isRenderViz)
6806
+ if (!iframe || !iframeHeight || !isDomLoaded)
5858
6807
  return;
5859
6808
  const setupObservers = () => {
5860
6809
  try {
@@ -5916,7 +6865,7 @@ const useObserveIframeHeight = (props) => {
5916
6865
  }
5917
6866
  iframe.removeEventListener('load', setupObservers);
5918
6867
  };
5919
- }, [iframeRef, iframeHeight, isRenderViz]);
6868
+ }, [iframeRef, iframeHeight, isDomLoaded]);
5920
6869
  return {};
5921
6870
  };
5922
6871
 
@@ -5929,9 +6878,10 @@ const useScaleCalculation = (props) => {
5929
6878
  const setScale = useHeatmapVizContext((s) => s.setScale);
5930
6879
  const setIsScaledToFit = useHeatmapVizContext((s) => s.setIsScaledToFit);
5931
6880
  const setMinZoomRatio = useHeatmapVizContext((s) => s.setMinZoomRatio);
5932
- const { containerWidth, containerHeight, contentWidth, contentHeight } = props;
6881
+ const viewport = useHeatmapViewportByDevice();
6882
+ const { containerWidth, containerHeight, iframeHeight } = props;
5933
6883
  const calculateScaleResult = useCallback(() => {
5934
- if (containerWidth > 0 && contentWidth > 0 && containerHeight > 0 && contentHeight > 0) {
6884
+ if (containerWidth > 0 && viewport.width > 0 && containerHeight > 0 && iframeHeight > 0) {
5935
6885
  // 1. Calculate available dimensions
5936
6886
  const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
5937
6887
  const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] || 0;
@@ -5939,12 +6889,12 @@ const useScaleCalculation = (props) => {
5939
6889
  const availableHeight = containerHeight - toolbarHeight - paddingTotal;
5940
6890
  // 2. Calculate widthScale (base scale to fit content width into container width)
5941
6891
  // This represents 100% zoom (fit to width)
5942
- const widthScale = Math.min(availableWidth / contentWidth, 1);
6892
+ const widthScale = Math.min(availableWidth / viewport.width, 1);
5943
6893
  // 3. Calculate minZoomRatio (zoom ratio to fit height)
5944
6894
  // At minZoomRatio, the content should fit entirely within the container height
5945
- // Formula: contentHeight * widthScale * (minZoomRatio / 100) = availableHeight
5946
- // => minZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100
5947
- const calculatedMinZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100;
6895
+ // Formula: iframeHeight * widthScale * (minZoomRatio / 100) = availableHeight
6896
+ // => minZoomRatio = (availableHeight / (iframeHeight * widthScale)) * 100
6897
+ const calculatedMinZoomRatio = (availableHeight / (iframeHeight * widthScale)) * 100;
5948
6898
  // Limit minZoomRatio: cannot exceed MAX_ZOOM_RATIO (100%)
5949
6899
  // and should have a reasonable minimum (e.g., 1%)
5950
6900
  const finalMinZoomRatio = Math.max(1, Math.min(calculatedMinZoomRatio, maxZoomRatio));
@@ -5963,7 +6913,7 @@ const useScaleCalculation = (props) => {
5963
6913
  setIsScaledToFit(isCurrentlyFitted);
5964
6914
  setMinZoomRatio(finalMinZoomRatio);
5965
6915
  }
5966
- }, [containerWidth, containerHeight, contentWidth, contentHeight, zoomRatio, maxZoomRatio]);
6916
+ }, [containerWidth, containerHeight, viewport.width, iframeHeight, zoomRatio, maxZoomRatio]);
5967
6917
  useEffect(() => {
5968
6918
  calculateScaleResult();
5969
6919
  }, [calculateScaleResult]);
@@ -5996,20 +6946,15 @@ const useHeatmapScale = (props) => {
5996
6946
  // 1. Observe container dimensions
5997
6947
  const { containerWidth, containerHeight } = useContainerDimensions({ wrapperRef });
5998
6948
  // 2. Get content dimensions from config
5999
- const { contentWidth } = useContentDimensions({ iframeRef });
6949
+ const viewport = useHeatmapViewportByDevice();
6000
6950
  // 3. Observe iframe height (now reacts to width changes)
6001
6951
  useObserveIframeHeight({ iframeRef });
6002
6952
  // 4. Calculate scale
6003
- const { widthScale } = useScaleCalculation({
6004
- containerWidth,
6005
- containerHeight,
6006
- contentWidth,
6007
- contentHeight: iframeHeight,
6008
- });
6953
+ const { widthScale } = useScaleCalculation({ containerWidth, containerHeight, iframeHeight });
6009
6954
  // 5. Setup scroll sync
6010
6955
  const { handleScroll } = useScrollSync({ widthScale, iframeRef });
6011
6956
  const scaledHeight = iframeHeight * widthScale;
6012
- const scaledWidth = contentWidth * widthScale;
6957
+ const scaledWidth = viewport.width * widthScale;
6013
6958
  return {
6014
6959
  scaledWidth,
6015
6960
  scaledHeight,
@@ -6215,10 +7160,10 @@ const useScrollmapZones = (options) => {
6215
7160
  const newZones = createZones(scrollmap);
6216
7161
  setZones(newZones);
6217
7162
  setIsReady(true);
6218
- logger$9.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
7163
+ logger$3.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
6219
7164
  }
6220
7165
  catch (error) {
6221
- logger$9.error('[useScrollmap] Error:', error);
7166
+ logger$3.error('[useScrollmap] Error:', error);
6222
7167
  setIsReady(false);
6223
7168
  }
6224
7169
  }, [enabled, scrollmap, mode, createZones]);
@@ -7048,11 +7993,11 @@ const AutoScrollHandler = ({ visualRef }) => {
7048
7993
  };
7049
7994
 
7050
7995
  const PortalAreaRenderer = ({ iframeRef, visualRef, shadowRoot, onAreaCreated, onAreaClick, }) => {
7051
- const isRenderViz = useHeatmapVizContext((s) => s.isRenderViz);
7996
+ const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
7052
7997
  const iframeDocument = iframeRef.current?.contentDocument || undefined;
7053
7998
  const { shadowContainer, isReady } = useAreaRendererContainer(iframeDocument, shadowRoot);
7054
- useAreaRectSync({ iframeDocument, shadowRoot, enabled: isReady && isRenderViz });
7055
- useAreaPositionsUpdater({ iframeRef, visualRef, enabled: isReady && isRenderViz });
7999
+ useAreaRectSync({ iframeDocument, shadowRoot, enabled: isReady && isDomLoaded });
8000
+ useAreaPositionsUpdater({ iframeRef, visualRef, enabled: isReady && isDomLoaded });
7056
8001
  if (!shadowContainer || !isReady)
7057
8002
  return null;
7058
8003
  return (jsxs(Fragment$1, { children: [jsx(AutoScrollHandler, { visualRef: visualRef }), jsx(AreasPortal, { shadowContainer: shadowContainer, onAreaClick: onAreaClick }), jsx(AreaEditHighlightPortal, { shadowContainer: shadowContainer, iframeRef: iframeRef, customShadowRoot: shadowRoot, onAreaCreated: onAreaCreated })] }));
@@ -7061,7 +8006,7 @@ const PortalAreaRenderer = ({ iframeRef, visualRef, shadowRoot, onAreaCreated, o
7061
8006
  const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, enableOverlapResolution = true, onAreaClick, }) => {
7062
8007
  const clickAreas = useHeatmapDataContext((s) => s.clickAreas);
7063
8008
  const resetView = useHeatmapAreaClickContext((s) => s.resetView);
7064
- const isRenderViz = useHeatmapVizContext((s) => s.isRenderViz);
8009
+ const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
7065
8010
  useAreaTopAutoDetect({ autoCreateTopN, shadowRoot, disabled: !!clickAreas?.length });
7066
8011
  useAreaFilterVisible({ iframeRef, enableOverlapResolution });
7067
8012
  useAreaHydration({ shadowRoot });
@@ -7070,7 +8015,7 @@ const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, e
7070
8015
  resetView();
7071
8016
  };
7072
8017
  }, []);
7073
- if (!iframeRef.current || !isRenderViz)
8018
+ if (!iframeRef.current || !isDomLoaded)
7074
8019
  return null;
7075
8020
  return (jsx(Fragment, { children: jsx(PortalAreaRenderer, { iframeRef: iframeRef, visualRef: visualRef, shadowRoot: shadowRoot, onAreaClick: onAreaClick }) }));
7076
8021
  };
@@ -7201,7 +8146,7 @@ const useAnchorPosition = (calloutRef, props) => {
7201
8146
  const ElementMissing = ({ show = true, visualRef }) => {
7202
8147
  const widthScale = useHeatmapVizContext((s) => s.widthScale);
7203
8148
  const missingElementRef = useRef(null);
7204
- const wrapperWidth = useHeatmapWidthByDevice();
8149
+ const viewport = useHeatmapViewportByDevice();
7205
8150
  const [scrollPosition, setScrollPosition] = useState({ scrollTop: 0, scrollLeft: 0 });
7206
8151
  useEffect(() => {
7207
8152
  const container = visualRef.current;
@@ -7231,7 +8176,7 @@ const ElementMissing = ({ show = true, visualRef }) => {
7231
8176
  const containerHeight = containerRect?.height ?? 0;
7232
8177
  const topPosition = scrollTop + (containerHeight + elementHeightCenter) / 2;
7233
8178
  const topPositionScaled = topPosition / widthScale;
7234
- const leftPosition = wrapperWidth / 2;
8179
+ const leftPosition = viewport.width / 2;
7235
8180
  return (jsxs(Fragment, { children: [jsx("div", { className: "missingElement-backdrop", style: {
7236
8181
  position: 'absolute',
7237
8182
  top: 0,
@@ -7356,7 +8301,7 @@ const ElementOverlayComponent = (props) => {
7356
8301
  const { type, element, onClick, elementId, hideOutline } = props;
7357
8302
  const widthScale = useHeatmapVizContext((s) => s.widthScale);
7358
8303
  const viewportHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
7359
- const viewportWidth = useHeatmapWidthByDevice();
8304
+ const viewport = useHeatmapViewportByDevice();
7360
8305
  const overlayStyle = useMemo(() => {
7361
8306
  const isInvalid = !element || (element.width === 0 && element.height === 0);
7362
8307
  if (isInvalid)
@@ -7373,7 +8318,7 @@ const ElementOverlayComponent = (props) => {
7373
8318
  const isHovered = type === 'hovered';
7374
8319
  const badgeWidthScale = isHovered ? 1 : widthScale;
7375
8320
  const showCallout = !!element?.mousePosition && !isHovered;
7376
- return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: `heatmapElement heatmapElement--${type} ${hideOutline ? 'heatmapElement--hide-outline' : ''}`, id: elementId, style: overlayStyle, children: showCallout && jsx(ElementCalloutOverlay, { ...props }) }), jsx(BackdropCanvas, { activeElement: overlayStyle, viewportWidth: viewportWidth, viewportHeight: viewportHeight, show: !isHovered }), jsx(RankBadge, { hash: element.hash, show: isHovered, index: element.rank, elementRect: element, widthScale: badgeWidthScale, clickOnElement: onClick })] }));
8321
+ return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: `heatmapElement heatmapElement--${type} ${hideOutline ? 'heatmapElement--hide-outline' : ''}`, id: elementId, style: overlayStyle, children: showCallout && jsx(ElementCalloutOverlay, { ...props }) }), jsx(BackdropCanvas, { activeElement: overlayStyle, viewportWidth: viewport.width, viewportHeight: viewportHeight, show: !isHovered }), jsx(RankBadge, { hash: element.hash, show: isHovered, index: element.rank, elementRect: element, widthScale: badgeWidthScale, clickOnElement: onClick })] }));
7377
8322
  };
7378
8323
  ElementOverlayComponent.displayName = 'ElementOverlay';
7379
8324
  const ElementOverlay = memo(ElementOverlayComponent);
@@ -7438,7 +8383,7 @@ const HeatmapElements = (props) => {
7438
8383
  };
7439
8384
 
7440
8385
  const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
7441
- const contentWidth = useHeatmapWidthByDevice();
8386
+ const viewport = useHeatmapViewportByDevice();
7442
8387
  const dataInfo = useHeatmapDataContext((s) => s.dataInfo);
7443
8388
  const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
7444
8389
  const visualizer = {
@@ -7452,7 +8397,7 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
7452
8397
  if (!iframeRef.current)
7453
8398
  return null;
7454
8399
  return (jsx(HeatmapElements, { visualizer: visualizer, visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef, heatmapInfo: dataInfo, isVisible: true, positionMode: DEFAULT_POSITION_MODE, isHideTopRank: true, iframeDimensions: {
7455
- width: contentWidth,
8400
+ width: viewport.width,
7456
8401
  position: 'absolute',
7457
8402
  top: 0,
7458
8403
  left: 0,
@@ -7716,7 +8661,7 @@ const VizLoadingCanvas = () => {
7716
8661
  const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
7717
8662
  const isLoadingCanvas = useHeatmapSettingContext((state) => state.isLoadingCanvas);
7718
8663
  const widthScale = useHeatmapVizContext((s) => s.widthScale);
7719
- const contentWidth = useHeatmapWidthByDevice();
8664
+ const viewport = useHeatmapViewportByDevice();
7720
8665
  const contentHeight = calcContentHeight();
7721
8666
  return (jsx("div", { ref: visualRef, className: "gx-hm-visual Polaris-Scrollable Polaris-Scrollable--vertical Polaris-Scrollable--scrollbarWidthThin Polaris-Scrollable--scrollbarGutterStable", onScroll: onScroll, style: {
7722
8667
  overflowX: 'hidden',
@@ -7738,7 +8683,7 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
7738
8683
  paddingBottom: HEATMAP_STYLE['viz']['paddingBottom'],
7739
8684
  background: HEATMAP_STYLE['viz']['background'],
7740
8685
  }, children: jsx("div", { className: "gx-hm-wrapper", ref: wrapperRef, style: {
7741
- width: contentWidth,
8686
+ width: viewport.width,
7742
8687
  height: iframeHeight,
7743
8688
  transform: `scale(${widthScale})`,
7744
8689
  transformOrigin: 'top center',
@@ -7751,14 +8696,14 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
7751
8696
  }
7752
8697
  };
7753
8698
 
7754
- const VizDomRenderer = ({ mode = 'heatmap' }) => {
8699
+ const VizDomRenderer = ({ mode }) => {
7755
8700
  const viewId = useViewIdContext();
7756
- const contentWidth = useHeatmapWidthByDevice();
8701
+ const viewport = useHeatmapViewportByDevice();
7757
8702
  const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
7758
8703
  const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
7759
8704
  const wrapperRef = useRef(null);
7760
8705
  const visualRef = useRef(null);
7761
- const { iframeRef } = useHeatmapRenderByMode(mode);
8706
+ const { iframeRef } = useHeatmapRenderDom();
7762
8707
  const { scaledHeight, handleScroll } = useHeatmapScale({ wrapperRef, iframeRef, visualRef });
7763
8708
  useHeatmapCanvas();
7764
8709
  useRenderCount('VizDomRenderer');
@@ -7766,7 +8711,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
7766
8711
  const scrollTop = e.currentTarget.scrollTop;
7767
8712
  handleScroll(scrollTop);
7768
8713
  };
7769
- return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizClickmap, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ...HEATMAP_IFRAME, id: `clarity-iframe-${viewId}`, ref: iframeRef, width: contentWidth, height: wrapperHeight }), jsx(VizLoadingCanvas, {}), jsx(VizScrollMap, { visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef })] }));
8714
+ return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizClickmap, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ...HEATMAP_IFRAME, id: `clarity-iframe-${viewId}`, ref: iframeRef, width: viewport.width, height: wrapperHeight }), jsx(VizLoadingCanvas, {}), jsx(VizScrollMap, { visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef })] }));
7770
8715
  };
7771
8716
 
7772
8717
  const VizLoading = () => {
@@ -7783,8 +8728,9 @@ const VizLoading = () => {
7783
8728
  const VizDomHeatmap = () => {
7784
8729
  const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
7785
8730
  const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
8731
+ const setWrapperHeight = useHeatmapVizRectContext((s) => s.setWrapperHeight);
7786
8732
  const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
7787
- const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
8733
+ const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
7788
8734
  const setSelectedElement = useHeatmapClickContext((s) => s.setSelectedElement);
7789
8735
  const setHoveredElement = useHeatmapHoverContext((s) => s.setHoveredElement);
7790
8736
  // const setSelectedArea = useHeatmapAreaClickContext((s) => s.setSelectedArea);
@@ -7794,7 +8740,8 @@ const VizDomHeatmap = () => {
7794
8740
  const cleanUp = () => {
7795
8741
  setVizRef(null);
7796
8742
  setIframeHeight(0);
7797
- setIsRenderViz(false);
8743
+ setWrapperHeight(0);
8744
+ setIsDomLoaded(false);
7798
8745
  setSelectedElement(null);
7799
8746
  setHoveredElement(null);
7800
8747
  // setSelectedArea(null);
@@ -7803,13 +8750,13 @@ const VizDomHeatmap = () => {
7803
8750
  };
7804
8751
  useEffect(() => {
7805
8752
  return cleanUp;
7806
- }, []);
7807
- return (jsxs(VizContainer, { isActive: true, children: [jsx(VizDomRenderer, {}), iframeHeight === 0 && jsx(VizLoading, {})] }));
8753
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
8754
+ return (jsxs(VizContainer, { isActive: true, children: [jsx(VizDomRenderer, { mode: EHeatmapMode.Heatmap }), iframeHeight === 0 && jsx(VizLoading, {})] }));
7808
8755
  };
7809
8756
  VizDomHeatmap.displayName = 'VizDomHeatmap';
7810
8757
 
7811
8758
  const VizLiveRenderer = () => {
7812
- const contentWidth = useHeatmapWidthByDevice();
8759
+ const viewport = useHeatmapViewportByDevice();
7813
8760
  const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
7814
8761
  const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
7815
8762
  const visualRef = useRef(null);
@@ -7820,13 +8767,13 @@ const VizLiveRenderer = () => {
7820
8767
  const scrollTop = e.currentTarget.scrollTop;
7821
8768
  handleScroll(scrollTop);
7822
8769
  };
7823
- return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, height: wrapperHeight, scrolling: "no" }) }));
8770
+ return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: viewport.width, height: wrapperHeight, scrolling: "no" }) }));
7824
8771
  };
7825
8772
 
7826
8773
  const VizLiveHeatmap = () => {
7827
8774
  const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
7828
8775
  const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
7829
- useHeatmapLiveStore((state) => state.reset);
8776
+ useHeatmapLiveContext((s) => s.reset);
7830
8777
  const CompVizLoading = useHeatmapControlStore((state) => state.controls.VizLoading);
7831
8778
  // TODO: Remove this after testing
7832
8779
  useEffect(() => {
@@ -7877,11 +8824,11 @@ const ContentTopBar = () => {
7877
8824
  }, children: CompTopBar && jsx(CompTopBar, {}) }));
7878
8825
  };
7879
8826
 
7880
- const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, attentionMap, controls, dataInfo, isLoading, isLoadingCanvas, }) => {
8827
+ const HeatmapLayout = ({ shopId, data, clickmap, clickAreas, scrollmap, attentionMap, controls, dataInfo, isLoading, isLoadingCanvas, excludeClassNames, }) => {
7881
8828
  useRegisterControl(controls);
7882
8829
  useRegisterData(data, dataInfo);
7883
8830
  useRegisterHeatmap({ clickmap, scrollmap, clickAreas, attentionMap });
7884
- useRegisterConfig({ isLoading, isLoadingCanvas });
8831
+ useRegisterConfig({ isLoading, isLoadingCanvas, shopId, excludeClassNames });
7885
8832
  // performanceLogger.configure({
7886
8833
  // enabled: true,
7887
8834
  // logToConsole: false,
@@ -7911,4 +8858,4 @@ const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, attentionMap, co
7911
8858
  }
7912
8859
  };
7913
8860
 
7914
- export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO, EClickMode, EClickRankType, EClickType, EDeviceType, EHeatmapMode, EHeatmapType, ELM_CALLOUT_CONFIG, EScrollType, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, ViewIdContext, Z_INDEX$1 as Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, createViewContextHook, decodeArrayClarity, decodeClarity, downloadPerformanceReport, getCompareViewId, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClickContext, useHeatmapCanvas, useHeatmapClickContext, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapDataContext, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHoverContext, useHeatmapLiveStore, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapVizContext, useHeatmapVizRectContext, useHeatmapWidthByDevice, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
8861
+ export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO, EClickMode, EClickRankType, EClickType, EDeviceType, EHeatmapDataSource, EHeatmapMode, EHeatmapType, ELM_CALLOUT_CONFIG, EScrollType, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, ViewIdContext, Z_INDEX$1 as Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, createViewContextHook, decodeArrayClarity, decodeClarity, downloadPerformanceReport, getCompareViewId, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClickContext, useHeatmapCanvas, useHeatmapClickContext, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapDataContext, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHoverContext, useHeatmapLiveContext, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapViewportByDevice, useHeatmapVizContext, useHeatmapVizRectContext, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };