@gemx-dev/heatmap-react 3.5.29 → 3.5.31

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 (133) hide show
  1. package/dist/esm/components/Layout/ContentMetricBar.d.ts +2 -0
  2. package/dist/esm/components/Layout/ContentMetricBar.d.ts.map +1 -0
  3. package/dist/esm/components/Layout/ContentToolbar.d.ts +2 -0
  4. package/dist/esm/components/Layout/ContentToolbar.d.ts.map +1 -0
  5. package/dist/esm/components/Layout/ContentTopBar.d.ts +2 -0
  6. package/dist/esm/components/Layout/ContentTopBar.d.ts.map +1 -0
  7. package/dist/esm/components/Layout/HeatmapLayout.d.ts +2 -3
  8. package/dist/esm/components/Layout/HeatmapLayout.d.ts.map +1 -1
  9. package/dist/esm/components/Layout/LeftSidebar.d.ts +1 -3
  10. package/dist/esm/components/Layout/LeftSidebar.d.ts.map +1 -1
  11. package/dist/esm/components/Layout/WrapperLayout.d.ts +1 -7
  12. package/dist/esm/components/Layout/WrapperLayout.d.ts.map +1 -1
  13. package/dist/esm/components/Layout/WrapperPreview.d.ts +1 -3
  14. package/dist/esm/components/Layout/WrapperPreview.d.ts.map +1 -1
  15. package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +1 -1
  16. package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  17. package/dist/esm/components/VizElement/ElementCallout.d.ts.map +1 -1
  18. package/dist/esm/components/VizElement/VizElements.d.ts.map +1 -1
  19. package/dist/esm/configs/style.d.ts +8 -1
  20. package/dist/esm/configs/style.d.ts.map +1 -1
  21. package/dist/esm/helpers/iframe.d.ts +1 -1
  22. package/dist/esm/helpers/iframe.d.ts.map +1 -1
  23. package/dist/esm/hooks/index.d.ts +1 -0
  24. package/dist/esm/hooks/index.d.ts.map +1 -1
  25. package/dist/esm/hooks/register/index.d.ts +5 -0
  26. package/dist/esm/hooks/register/index.d.ts.map +1 -0
  27. package/dist/esm/hooks/register/useRegisterConfig.d.ts +2 -0
  28. package/dist/esm/hooks/register/useRegisterConfig.d.ts.map +1 -0
  29. package/dist/esm/hooks/register/useRegisterControl.d.ts +3 -0
  30. package/dist/esm/hooks/register/useRegisterControl.d.ts.map +1 -0
  31. package/dist/esm/hooks/register/useRegisterData.d.ts +3 -0
  32. package/dist/esm/hooks/register/useRegisterData.d.ts.map +1 -0
  33. package/dist/esm/hooks/register/useRegisterHeatmap.d.ts +3 -0
  34. package/dist/esm/hooks/register/useRegisterHeatmap.d.ts.map +1 -0
  35. package/dist/esm/hooks/viz-canvas/index.d.ts +2 -0
  36. package/dist/esm/hooks/viz-canvas/index.d.ts.map +1 -0
  37. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts +2 -0
  38. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -0
  39. package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +5 -0
  40. package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -0
  41. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts +2 -0
  42. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -0
  43. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts +0 -2
  44. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  45. package/dist/esm/hooks/viz-render/useHeatmapVizRender.d.ts +0 -2
  46. package/dist/esm/hooks/viz-render/useHeatmapVizRender.d.ts.map +1 -1
  47. package/dist/esm/hooks/viz-render/useReplayRender.d.ts +0 -2
  48. package/dist/esm/hooks/viz-render/useReplayRender.d.ts.map +1 -1
  49. package/dist/esm/index.js +274 -187
  50. package/dist/esm/index.mjs +274 -187
  51. package/dist/esm/stores/comp.d.ts +7 -0
  52. package/dist/esm/stores/comp.d.ts.map +1 -0
  53. package/dist/esm/stores/data.d.ts +2 -0
  54. package/dist/esm/stores/data.d.ts.map +1 -1
  55. package/dist/esm/stores/index.d.ts +2 -0
  56. package/dist/esm/stores/index.d.ts.map +1 -1
  57. package/dist/esm/stores/viz.d.ts +6 -0
  58. package/dist/esm/stores/viz.d.ts.map +1 -0
  59. package/dist/esm/types/control.d.ts +8 -0
  60. package/dist/esm/types/control.d.ts.map +1 -0
  61. package/dist/esm/types/heatmap.d.ts +6 -1
  62. package/dist/esm/types/heatmap.d.ts.map +1 -1
  63. package/dist/esm/ui/BoxStack/BoxStack.d.ts +1 -1
  64. package/dist/esm/ui/BoxStack/BoxStack.d.ts.map +1 -1
  65. package/dist/style.css +31 -2
  66. package/dist/umd/components/Layout/ContentMetricBar.d.ts +2 -0
  67. package/dist/umd/components/Layout/ContentMetricBar.d.ts.map +1 -0
  68. package/dist/umd/components/Layout/ContentToolbar.d.ts +2 -0
  69. package/dist/umd/components/Layout/ContentToolbar.d.ts.map +1 -0
  70. package/dist/umd/components/Layout/ContentTopBar.d.ts +2 -0
  71. package/dist/umd/components/Layout/ContentTopBar.d.ts.map +1 -0
  72. package/dist/umd/components/Layout/HeatmapLayout.d.ts +2 -3
  73. package/dist/umd/components/Layout/HeatmapLayout.d.ts.map +1 -1
  74. package/dist/umd/components/Layout/LeftSidebar.d.ts +1 -3
  75. package/dist/umd/components/Layout/LeftSidebar.d.ts.map +1 -1
  76. package/dist/umd/components/Layout/WrapperLayout.d.ts +1 -7
  77. package/dist/umd/components/Layout/WrapperLayout.d.ts.map +1 -1
  78. package/dist/umd/components/Layout/WrapperPreview.d.ts +1 -3
  79. package/dist/umd/components/Layout/WrapperPreview.d.ts.map +1 -1
  80. package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +1 -1
  81. package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  82. package/dist/umd/components/VizElement/ElementCallout.d.ts.map +1 -1
  83. package/dist/umd/components/VizElement/VizElements.d.ts.map +1 -1
  84. package/dist/umd/configs/style.d.ts +8 -1
  85. package/dist/umd/configs/style.d.ts.map +1 -1
  86. package/dist/umd/helpers/iframe.d.ts +1 -1
  87. package/dist/umd/helpers/iframe.d.ts.map +1 -1
  88. package/dist/umd/hooks/index.d.ts +1 -0
  89. package/dist/umd/hooks/index.d.ts.map +1 -1
  90. package/dist/umd/hooks/register/index.d.ts +5 -0
  91. package/dist/umd/hooks/register/index.d.ts.map +1 -0
  92. package/dist/umd/hooks/register/useRegisterConfig.d.ts +2 -0
  93. package/dist/umd/hooks/register/useRegisterConfig.d.ts.map +1 -0
  94. package/dist/umd/hooks/register/useRegisterControl.d.ts +3 -0
  95. package/dist/umd/hooks/register/useRegisterControl.d.ts.map +1 -0
  96. package/dist/umd/hooks/register/useRegisterData.d.ts +3 -0
  97. package/dist/umd/hooks/register/useRegisterData.d.ts.map +1 -0
  98. package/dist/umd/hooks/register/useRegisterHeatmap.d.ts +3 -0
  99. package/dist/umd/hooks/register/useRegisterHeatmap.d.ts.map +1 -0
  100. package/dist/umd/hooks/viz-canvas/index.d.ts +2 -0
  101. package/dist/umd/hooks/viz-canvas/index.d.ts.map +1 -0
  102. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts +2 -0
  103. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -0
  104. package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +5 -0
  105. package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -0
  106. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts +2 -0
  107. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -0
  108. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts +0 -2
  109. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  110. package/dist/umd/hooks/viz-render/useHeatmapVizRender.d.ts +0 -2
  111. package/dist/umd/hooks/viz-render/useHeatmapVizRender.d.ts.map +1 -1
  112. package/dist/umd/hooks/viz-render/useReplayRender.d.ts +0 -2
  113. package/dist/umd/hooks/viz-render/useReplayRender.d.ts.map +1 -1
  114. package/dist/umd/index.js +2 -2
  115. package/dist/umd/stores/comp.d.ts +7 -0
  116. package/dist/umd/stores/comp.d.ts.map +1 -0
  117. package/dist/umd/stores/data.d.ts +2 -0
  118. package/dist/umd/stores/data.d.ts.map +1 -1
  119. package/dist/umd/stores/index.d.ts +2 -0
  120. package/dist/umd/stores/index.d.ts.map +1 -1
  121. package/dist/umd/stores/viz.d.ts +6 -0
  122. package/dist/umd/stores/viz.d.ts.map +1 -0
  123. package/dist/umd/types/control.d.ts +8 -0
  124. package/dist/umd/types/control.d.ts.map +1 -0
  125. package/dist/umd/types/heatmap.d.ts +6 -1
  126. package/dist/umd/types/heatmap.d.ts.map +1 -1
  127. package/dist/umd/ui/BoxStack/BoxStack.d.ts +1 -1
  128. package/dist/umd/ui/BoxStack/BoxStack.d.ts.map +1 -1
  129. package/package.json +4 -4
  130. package/dist/esm/components/Layout/ContentHeader.d.ts +0 -4
  131. package/dist/esm/components/Layout/ContentHeader.d.ts.map +0 -1
  132. package/dist/umd/components/Layout/ContentHeader.d.ts +0 -4
  133. package/dist/umd/components/Layout/ContentHeader.d.ts.map +0 -1
@@ -1,10 +1,9 @@
1
1
  "use client"
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import { useNodesState, ReactFlow, Controls, Background } from '@xyflow/react';
4
- import { useEffect, useMemo, useState, useCallback, useRef, Fragment as Fragment$1 } from 'react';
4
+ import { useEffect, useCallback, useState, useRef, useMemo, Fragment as Fragment$1 } from 'react';
5
5
  import { create } from 'zustand';
6
6
  import { Visualizer } from '@gemx-dev/clarity-visualize';
7
- import { createPortal } from 'react-dom';
8
7
 
9
8
  const initialNodes = { id: '1', position: { x: 0, y: 0 }, data: { label: '1' } };
10
9
  const GraphView = ({ children, width, height }) => {
@@ -38,15 +37,71 @@ const GraphView = ({ children, width, height }) => {
38
37
  return (jsxs(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, onNodesChange: onNodesChange, debug: true, minZoom: 0.5, maxZoom: 2, fitView: true, children: [jsx(Controls, {}), jsx(Background, {})] }));
39
38
  };
40
39
 
40
+ const HEATMAP_IFRAME = {
41
+ id: 'clarity-iframe',
42
+ title: 'Clarity Session Replay',
43
+ sandbox: 'allow-same-origin allow-scripts',
44
+ scrolling: 'no',
45
+ height: '100%',
46
+ };
47
+
48
+ const HEATMAP_CONFIG = {
49
+ padding: 8,
50
+ borderWidth: 1,
51
+ borderColor: 'red',
52
+ };
53
+ const HEATMAP_STYLE = {
54
+ viz: {
55
+ background: '#f3f3f3',
56
+ paddingBottom: `${HEATMAP_CONFIG.padding}px`,
57
+ },
58
+ wrapper: {
59
+ padding: `${HEATMAP_CONFIG.padding}px 0`,
60
+ },
61
+ };
62
+ const DEFAULT_SIDEBAR_WIDTH = 260;
63
+
64
+ const useHeatmapControlStore = create()((set, get) => {
65
+ return {
66
+ controls: {
67
+ Sidebar: null,
68
+ TopBar: null,
69
+ Toolbar: null,
70
+ MetricBar: null,
71
+ VizLoading: null,
72
+ },
73
+ registerControl: (key, control) => {
74
+ set({
75
+ controls: {
76
+ ...get().controls,
77
+ [key]: control,
78
+ },
79
+ });
80
+ },
81
+ };
82
+ });
83
+
84
+ var IHeatmapType;
85
+ (function (IHeatmapType) {
86
+ IHeatmapType["Click"] = "click";
87
+ IHeatmapType["Scroll"] = "scroll";
88
+ })(IHeatmapType || (IHeatmapType = {}));
89
+
41
90
  const useHeatmapDataStore = create()((set, get) => {
42
91
  return {
43
92
  data: undefined,
44
93
  clickmap: undefined,
45
- config: undefined,
94
+ config: {
95
+ sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
96
+ width: 1440,
97
+ heatmapType: IHeatmapType.Click,
98
+ },
46
99
  iframeHeight: 0,
47
100
  state: {
48
101
  hideSidebar: false,
49
102
  },
103
+ isRendering: true,
104
+ setIsRendering: (isRendering) => set({ isRendering }),
50
105
  setData: (data) => set({ data }),
51
106
  setClickmap: (clickmap) => set({ clickmap }),
52
107
  setState: (state) => set({ state: { ...get().state, ...state } }),
@@ -56,63 +111,57 @@ const useHeatmapDataStore = create()((set, get) => {
56
111
  };
57
112
  });
58
113
 
59
- const BoxStack = ({ children, ...props }) => {
60
- const id = props.id;
61
- const flexDirection = props.flexDirection;
62
- const overflow = props.overflow || 'hidden';
63
- const position = props.position || 'relative';
64
- const flex = props.flex || 'none';
65
- const justifyContent = props.justifyContent;
66
- const alignItems = props.alignItems;
67
- const style = props.style || {};
68
- const gap = props.gap || 0;
69
- const height = props.height || 'auto';
70
- const styleGap = useMemo(() => {
71
- switch (flexDirection) {
72
- case 'row':
73
- return {
74
- columnGap: gap,
75
- };
76
- case 'column':
77
- return {
78
- rowGap: gap,
79
- };
80
- }
81
- }, [gap, flexDirection]);
82
- const styleProps = {
83
- display: 'flex',
84
- flexDirection,
85
- overflow,
86
- position,
87
- flex,
88
- justifyContent,
89
- alignItems,
90
- height,
91
- ...styleGap,
92
- ...style,
114
+ const useHeatmapVizStore = create()((set, get) => {
115
+ return {
116
+ vizRef: undefined,
117
+ setVizRef: (vizRef) => set({ vizRef }),
93
118
  };
94
- return (jsx("div", { id: id, style: styleProps, children: children }));
95
- };
119
+ });
96
120
 
97
- const ContentHeader = ({ children }) => {
98
- return (jsx(BoxStack, { id: "gx-hm-content-header", flexDirection: "row", alignItems: "center", overflow: "auto", children: children }));
121
+ const useRegisterConfig = () => {
122
+ const config = useHeatmapDataStore((state) => state.config);
123
+ const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
124
+ useEffect(() => {
125
+ setIsRendering(true);
126
+ setTimeout(() => {
127
+ setIsRendering(false);
128
+ }, 1000);
129
+ }, [config]);
99
130
  };
100
131
 
101
- const HEATMAP_IFRAME = {
102
- id: 'clarity-iframe',
103
- title: 'Clarity Session Replay',
104
- sandbox: 'allow-same-origin allow-scripts',
105
- scrolling: 'no',
106
- height: '100%',
132
+ const useRegisterControl = (control) => {
133
+ const registerControl = useHeatmapControlStore((state) => state.registerControl);
134
+ registerControl('Sidebar', control.Sidebar);
135
+ registerControl('TopBar', control.TopBar);
136
+ registerControl('Toolbar', control.Toolbar);
137
+ registerControl('MetricBar', control.MetricBar);
138
+ registerControl('VizLoading', control.VizLoading);
107
139
  };
108
140
 
109
- const HEATMAP_CONFIG = {
110
- paddingBlock: 0,
141
+ const useRegisterData = (data) => {
142
+ const setData = useHeatmapDataStore((state) => state.setData);
143
+ const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
144
+ const handleSetData = useCallback((data) => {
145
+ if (!data)
146
+ return;
147
+ setData(data);
148
+ setIsRendering(false);
149
+ }, [data]);
150
+ useEffect(() => {
151
+ handleSetData(data);
152
+ }, [data]);
111
153
  };
112
- const HEATMAP_STYLE = {
113
- wrapper: {
114
- padding: `${HEATMAP_CONFIG.paddingBlock}px 0`,
115
- },
154
+
155
+ const useRegisterHeatmap = (clickmap) => {
156
+ const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
157
+ const handleSetClickmap = useCallback((clickmap) => {
158
+ if (!clickmap)
159
+ return;
160
+ setClickmap(clickmap);
161
+ }, [clickmap]);
162
+ useEffect(() => {
163
+ handleSetClickmap(clickmap);
164
+ }, [clickmap]);
116
165
  };
117
166
 
118
167
  const useClickedElement = ({ selectedElement, heatmapInfo, getRect }) => {
@@ -340,107 +389,40 @@ const getElementAtPoint = (doc, x, y) => {
340
389
  return element;
341
390
  };
342
391
 
343
- const recreateIframe = (iframeRef, config) => {
344
- const container = iframeRef.current?.parentElement;
345
- if (!container)
346
- return;
347
- const oldIframe = iframeRef.current;
348
- if (!oldIframe?.contentDocument?.body.innerHTML) {
349
- return oldIframe;
350
- }
351
- if (oldIframe && oldIframe.parentElement) {
352
- oldIframe.parentElement.removeChild(oldIframe);
353
- }
354
- const newIframe = document.createElement('iframe');
355
- newIframe.id = HEATMAP_IFRAME.id;
356
- newIframe.title = HEATMAP_IFRAME.title;
357
- newIframe.sandbox = HEATMAP_IFRAME.sandbox;
358
- newIframe.scrolling = HEATMAP_IFRAME.scrolling;
359
- newIframe.width = config?.width ? `${config.width}px` : '100%';
360
- // Append to container
361
- container.appendChild(newIframe);
362
- // Update ref
363
- iframeRef.current = newIframe;
364
- return newIframe;
365
- };
366
-
367
- function isMobileDevice(userAgent) {
368
- if (!userAgent)
369
- return false;
370
- return /android|webos|iphone|ipad|ipod|blackberry|windows phone|opera mini|iemobile|mobile|silk|fennec|bada|tizen|symbian|nokia|palmsource|meego|sailfish|kindle|playbook|bb10|rim/i.test(userAgent);
371
- }
372
-
373
392
  const useHeatmapRender = () => {
374
393
  const data = useHeatmapDataStore((state) => state.data);
375
394
  const config = useHeatmapDataStore((state) => state.config);
376
- const setConfig = useHeatmapDataStore((state) => state.setConfig);
377
- const clickmap = useHeatmapDataStore((state) => state.clickmap);
378
- const visualizerRef = useRef(null);
395
+ const setVizRef = useHeatmapVizStore((state) => state.setVizRef);
379
396
  const iframeRef = useRef(null);
380
- const initializeVisualizer = useCallback((envelope, userAgent) => {
381
- const iframe = iframeRef.current;
382
- if (!iframe?.contentWindow)
383
- return null;
384
- const visualizer = new Visualizer();
385
- const mobile = isMobileDevice(userAgent);
386
- visualizer.setup(iframe.contentWindow, {
387
- version: envelope.version,
388
- onresize: (width) => {
389
- setConfig({ width });
390
- },
391
- mobile,
392
- vNext: true,
393
- locale: 'en-us',
394
- });
395
- return visualizer;
396
- }, []);
397
- // Process and render heatmap HTML
398
397
  const renderHeatmap = useCallback(async (payloads) => {
399
398
  if (!payloads || payloads.length === 0)
400
399
  return;
401
- let visualizer = new Visualizer();
402
- const iframe = recreateIframe(iframeRef, config);
403
- // const merged = visualizer.merge(payloads);
404
- // setIframeHeight(Number(iframeRef.current?.height || 0));
405
- // for (const decoded of payloads) {
406
- // // Initialize on first sequence
407
- // if (decoded.envelope.sequence === 1) {
408
- // const userAgent = (decoded.dimension?.[0]?.data[0]?.[0] as string) || '';
409
- // visualizer = initializeVisualizer(decoded.envelope as any, userAgent);
410
- // if (!visualizer) return;
411
- // visualizerRef.current = visualizer;
412
- // }
413
- // if (!visualizer) continue;
414
- // // Merge and process DOM
415
- // const merged = visualizer.merge([decoded]);
416
- // visualizer.dom(merged.dom);
417
- // }
418
- // Render static HTML
419
- if (visualizer && iframe?.contentWindow) {
420
- await visualizer.html(payloads, iframe.contentWindow);
421
- visualizerRef.current = visualizer;
422
- }
423
- }, [initializeVisualizer]);
400
+ const visualizer = new Visualizer();
401
+ const iframe = iframeRef.current;
402
+ if (!iframe?.contentWindow)
403
+ return;
404
+ await visualizer.html(payloads, iframe.contentWindow);
405
+ setVizRef(visualizer);
406
+ }, []);
424
407
  useEffect(() => {
425
408
  if (!data || data.length === 0)
426
409
  return;
427
410
  renderHeatmap(data);
428
411
  return () => {
429
- visualizerRef.current = null;
412
+ setVizRef(null);
430
413
  };
431
- }, [config, data, renderHeatmap]);
432
- useEffect(() => {
433
- if (!visualizerRef.current || !clickmap || clickmap.length === 0)
434
- return;
435
- visualizerRef.current.clearmap();
436
- visualizerRef.current?.clickmap(clickmap);
437
- }, [clickmap]);
414
+ }, [config, data]);
438
415
  return {
439
416
  iframeRef,
440
- clarityVisualizer: visualizerRef.current,
441
417
  };
442
418
  };
443
419
 
420
+ function isMobileDevice(userAgent) {
421
+ if (!userAgent)
422
+ return false;
423
+ return /android|webos|iphone|ipad|ipod|blackberry|windows phone|opera mini|iemobile|mobile|silk|fennec|bada|tizen|symbian|nokia|palmsource|meego|sailfish|kindle|playbook|bb10|rim/i.test(userAgent);
424
+ }
425
+
444
426
  function sortEvents(a, b) {
445
427
  return a.time - b.time;
446
428
  }
@@ -559,7 +541,6 @@ const useReplayRender = () => {
559
541
  return {
560
542
  iframeRef,
561
543
  isPlaying: isPlayingRef.current,
562
- clarityVisualizer: visualizerRef.current,
563
544
  play,
564
545
  pause,
565
546
  };
@@ -646,16 +627,15 @@ const useIframeHeight = (props) => {
646
627
  console.warn('Cannot measure iframe content:', error);
647
628
  }
648
629
  }, [iframeRef, setIframeHeight]);
649
- // Trigger height update when content width changes
650
630
  useEffect(() => {
631
+ console.log(`🚀 🐥 ~ useIframeHeight ~ contentWidth:`, contentWidth);
651
632
  if (contentWidth > 0) {
652
- // Delay to allow iframe content to reflow after width change
653
633
  const timeoutId = setTimeout(() => {
654
634
  updateIframeHeight();
655
635
  }, 100);
656
636
  return () => clearTimeout(timeoutId);
657
637
  }
658
- }, [contentWidth, updateIframeHeight]);
638
+ }, [contentWidth]);
659
639
  useEffect(() => {
660
640
  const iframe = iframeRef.current;
661
641
  if (!iframe)
@@ -719,7 +699,7 @@ const useScaleCalculation = (props) => {
719
699
  const [scale, setScale] = useState(1);
720
700
  useEffect(() => {
721
701
  if (containerWidth > 0 && contentWidth > 0) {
722
- const availableWidth = containerWidth - HEATMAP_CONFIG['paddingBlock'] * 2;
702
+ const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
723
703
  const calculatedScale = Math.min(availableWidth / contentWidth, 1);
724
704
  setScale(calculatedScale);
725
705
  }
@@ -772,6 +752,84 @@ const useHeatmapScale = (props) => {
772
752
  };
773
753
  };
774
754
 
755
+ const BoxStack = ({ children, ...props }) => {
756
+ const id = props.id;
757
+ const flexDirection = props.flexDirection;
758
+ const overflow = props.overflow || 'hidden';
759
+ const position = props.position || 'relative';
760
+ const flex = props.flex || 'none';
761
+ const justifyContent = props.justifyContent;
762
+ const alignItems = props.alignItems;
763
+ const style = props.style || {};
764
+ const gap = props.gap || 0;
765
+ const height = props.height || 'auto';
766
+ const styleGap = useMemo(() => {
767
+ switch (flexDirection) {
768
+ case 'row':
769
+ return {
770
+ columnGap: gap,
771
+ };
772
+ case 'column':
773
+ return {
774
+ rowGap: gap,
775
+ };
776
+ }
777
+ }, [gap, flexDirection]);
778
+ const styleProps = {
779
+ display: 'flex',
780
+ flexDirection,
781
+ overflow,
782
+ position,
783
+ flex,
784
+ justifyContent,
785
+ alignItems,
786
+ height,
787
+ ...styleGap,
788
+ ...style,
789
+ };
790
+ return (jsx("div", { id: id, style: styleProps, children: children }));
791
+ };
792
+
793
+ const ContentTopBar = () => {
794
+ const controls = useHeatmapControlStore((state) => state.controls);
795
+ return (jsx(BoxStack, { id: "gx-hm-content-header", flexDirection: "row", alignItems: "center", overflow: "auto", style: {
796
+ borderBottom: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
797
+ }, children: controls.TopBar ?? null }));
798
+ };
799
+
800
+ const useClickmap = () => {
801
+ const [isInitialized, setIsInitialized] = useState(false);
802
+ const clickmap = useHeatmapDataStore((state) => state.clickmap);
803
+ const vizRef = useHeatmapVizStore((state) => state.vizRef);
804
+ useEffect(() => {
805
+ if (isInitialized)
806
+ return;
807
+ if (!vizRef || !clickmap || clickmap.length === 0)
808
+ return;
809
+ vizRef.clearmap();
810
+ vizRef?.clickmap(clickmap);
811
+ setIsInitialized(true);
812
+ }, [vizRef, clickmap]);
813
+ return {};
814
+ };
815
+
816
+ const useScrollmap = () => {
817
+ useHeatmapDataStore((state) => state.clickmap);
818
+ return {};
819
+ };
820
+
821
+ const useHeatmapVizCanvas = ({ type }) => {
822
+ const heatmapRender = useMemo(() => {
823
+ switch (type) {
824
+ case IHeatmapType.Click:
825
+ return useClickmap;
826
+ case IHeatmapType.Scroll:
827
+ return useScrollmap;
828
+ }
829
+ }, [type]);
830
+ return heatmapRender?.();
831
+ };
832
+
775
833
  const CLICKED_ELEMENT_ID = 'clickedElement';
776
834
  const SECONDARY_CLICKED_ELEMENT_ID = 'secondaryClickedElementID';
777
835
  const HOVERED_ELEMENT_ID = 'hoveredElement';
@@ -843,7 +901,7 @@ const ElementCallout = ({ element, target, totalClicks, isSecondary, isRecording
843
901
  setPosition({ top, left, placement });
844
902
  };
845
903
  // Initial calculation
846
- calculatePosition();
904
+ // calculatePosition();
847
905
  // Recalculate on scroll/resize
848
906
  const handleUpdate = () => {
849
907
  requestAnimationFrame(calculatePosition);
@@ -857,7 +915,7 @@ const ElementCallout = ({ element, target, totalClicks, isSecondary, isRecording
857
915
  parentRef?.current?.removeEventListener('scroll', handleUpdate);
858
916
  };
859
917
  }, [target, parentRef]);
860
- const calloutContent = (jsxs("div", { ref: calloutRef, className: `clarity-callout clarity-callout--${position.placement} ${isSecondary ? 'clarity-callout--secondary' : ''}`, style: {
918
+ (jsxs("div", { ref: calloutRef, className: `clarity-callout clarity-callout--${position.placement} ${isSecondary ? 'clarity-callout--secondary' : ''}`, style: {
861
919
  position: 'fixed',
862
920
  top: position.top,
863
921
  left: position.left,
@@ -1006,8 +1064,21 @@ const ElementCallout = ({ element, target, totalClicks, isSecondary, isRecording
1006
1064
  height: 14px;
1007
1065
  }
1008
1066
  ` })] }));
1009
- // Render to body using Portal
1010
- return createPortal(calloutContent, document.body);
1067
+ const [portalContainer, setPortalContainer] = useState(null);
1068
+ useEffect(() => {
1069
+ const container = document.querySelector('#gx-hm-project-portal');
1070
+ if (container instanceof HTMLElement) {
1071
+ setPortalContainer(container);
1072
+ }
1073
+ else {
1074
+ console.warn('Portal container #gx-hm-project-portal not found!');
1075
+ }
1076
+ }, []);
1077
+ if (!portalContainer) {
1078
+ return jsx(Fragment, {});
1079
+ }
1080
+ return jsx(Fragment, {});
1081
+ // return createPortal(calloutContent, portalContainer);
1011
1082
  };
1012
1083
 
1013
1084
  const RankBadge = ({ index, elementRect, widthScale, clickOnElement, }) => {
@@ -1108,7 +1179,6 @@ const HeatmapElements = (props) => {
1108
1179
  };
1109
1180
 
1110
1181
  const VizElements = ({ width, height, iframeRef, wrapperRef, widthScale, }) => {
1111
- useHeatmapDataStore((state) => state.data);
1112
1182
  const heatmapInfo = {
1113
1183
  sortedElements: [
1114
1184
  {
@@ -1185,6 +1255,7 @@ const ReplayControls = () => {
1185
1255
 
1186
1256
  const VizDomRenderer = ({ mode = 'heatmap' }) => {
1187
1257
  const config = useHeatmapDataStore((state) => state.config);
1258
+ const setIframeHeight = useHeatmapDataStore((state) => state.setIframeHeight);
1188
1259
  const wrapperRef = useRef(null);
1189
1260
  const visualRef = useRef(null);
1190
1261
  const { iframeRef } = useHeatmapVizRender(mode);
@@ -1197,45 +1268,65 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
1197
1268
  const scrollTop = e.currentTarget.scrollTop;
1198
1269
  handleScroll(scrollTop);
1199
1270
  };
1271
+ useHeatmapVizCanvas({ type: config?.heatmapType });
1272
+ const cleanUp = () => {
1273
+ setIframeHeight(0);
1274
+ };
1275
+ useEffect(() => {
1276
+ return cleanUp;
1277
+ }, []);
1200
1278
  return (jsxs("div", { ref: visualRef, className: "gx-hm-visual", onScroll: onScroll, style: {
1201
1279
  overflow: 'hidden auto',
1202
1280
  display: 'flex',
1203
1281
  position: 'relative',
1204
1282
  justifyContent: 'center',
1205
1283
  flex: 1,
1206
- backgroundColor: '#fff',
1207
- // borderRadius: '8px',
1284
+ paddingBottom: HEATMAP_STYLE['viz']['paddingBottom'],
1285
+ background: HEATMAP_STYLE['viz']['background'],
1208
1286
  }, children: [jsx("div", { className: "gx-hm-visual-unscaled", style: {
1209
1287
  width: '100%',
1210
1288
  display: 'flex',
1211
1289
  justifyContent: 'center',
1212
1290
  alignItems: 'flex-start',
1213
- height: scaledHeight > 0 ? `${scaledHeight + HEATMAP_CONFIG['paddingBlock']}px` : 'auto',
1291
+ height: scaledHeight > 0 ? `${scaledHeight + HEATMAP_CONFIG['padding']}px` : 'auto',
1214
1292
  padding: HEATMAP_STYLE['wrapper']['padding'],
1293
+ borderRadius: '8px',
1215
1294
  }, children: jsxs("div", { className: "gx-hm-wrapper", ref: wrapperRef, style: {
1216
1295
  width: contentWidth,
1217
1296
  height: iframeHeight,
1218
1297
  transform: `scale(${scale})`,
1219
1298
  transformOrigin: 'top center',
1220
- }, children: [jsx(VizElements, { width: contentWidth, height: iframeHeight, widthScale: scale, iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx("iframe", {
1221
- // key={iframeKey}
1222
- ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, height: iframeHeight, scrolling: "no" })] }) }), mode === 'replay' && jsx(ReplayControls, {})] }));
1299
+ paddingBlockEnd: '0',
1300
+ }, children: [jsx(VizElements, { width: contentWidth, height: iframeHeight, widthScale: scale, iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, height: iframeHeight, scrolling: "no" })] }) }), mode === 'replay' && jsx(ReplayControls, {})] }));
1223
1301
  };
1224
1302
 
1225
1303
  const VizDomContainer = () => {
1304
+ const controls = useHeatmapControlStore((state) => state.controls);
1305
+ const isRendering = useHeatmapDataStore((state) => state.isRendering);
1306
+ if (isRendering)
1307
+ return controls.VizLoading ?? null;
1226
1308
  return (jsx(BoxStack, { id: "gx-hm-viz-container", flexDirection: "column", flex: "1 1 auto", overflow: "auto", children: jsx(BoxStack, { id: "gx-hm-content", flexDirection: "column", flex: "1 1 auto", overflow: "hidden", style: {
1227
- // margin: '0px 16px 0px 12px',
1228
- // borderRadius: '8px 8px 0 0',
1229
- // borderRadius: '8px',
1230
1309
  minWidth: '394px',
1231
- padding: '12px',
1232
- background: '#f1f1f1',
1233
1310
  }, children: jsx(VizDomRenderer, {}) }) }));
1234
1311
  };
1235
1312
 
1236
- const SIDEBAR_WIDTH = 280;
1237
- const LeftSidebar = ({ children }) => {
1313
+ const ContentMetricBar = () => {
1314
+ const controls = useHeatmapControlStore((state) => state.controls);
1315
+ return (jsx(BoxStack, { id: "gx-hm-content-header", flexDirection: "row", alignItems: "center", overflow: "auto", style: {
1316
+ borderBottom: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
1317
+ }, children: controls.MetricBar ?? null }));
1318
+ };
1319
+
1320
+ const ContentToolbar = () => {
1321
+ const controls = useHeatmapControlStore((state) => state.controls);
1322
+ return (jsx("div", { id: "gx-hm-content-toolbar", style: { position: 'absolute', bottom: 0, left: 0, right: 0, padding: '8px' }, children: controls.Toolbar ?? null }));
1323
+ };
1324
+
1325
+ const LeftSidebar = () => {
1326
+ const controls = useHeatmapControlStore((state) => state.controls);
1238
1327
  const isHideSidebar = useHeatmapDataStore((state) => state.state.hideSidebar);
1328
+ const config = useHeatmapDataStore((state) => state.config);
1329
+ const sidebarWidth = config?.sidebarWidth || DEFAULT_SIDEBAR_WIDTH;
1239
1330
  if (isHideSidebar) {
1240
1331
  return null;
1241
1332
  }
@@ -1248,41 +1339,37 @@ const LeftSidebar = ({ children }) => {
1248
1339
  transform: 'translateX(-100%)',
1249
1340
  visibility: 'hidden',
1250
1341
  }
1251
- : { width: `${SIDEBAR_WIDTH}px` }),
1252
- }, children: jsx("div", { className: "gx-hm-sidebar-wrapper", style: { height: '100%', width: `${SIDEBAR_WIDTH}px` }, children: children }) }));
1342
+ : { width: `${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px` }),
1343
+ }, children: jsx("div", { className: "gx-hm-sidebar-wrapper", style: {
1344
+ height: '100%',
1345
+ width: `calc(${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px)`,
1346
+ borderRight: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
1347
+ }, children: controls.Sidebar ?? null }) }));
1253
1348
  };
1254
1349
 
1255
- const WrapperPreview = ({ children }) => {
1256
- return (jsxs("div", { className: "gx-hm-container", style: { display: 'flex', overflowY: 'hidden', flex: '1', position: 'relative' }, children: [jsx(LeftSidebar, { children: children }), jsx(VizDomContainer, {})] }));
1350
+ const WrapperPreview = () => {
1351
+ return (jsxs(BoxStack, { id: "gx-hm-container", flexDirection: "row", overflow: "hidden", flex: "1", position: "relative", children: [jsx(LeftSidebar, {}), jsxs(BoxStack, { flexDirection: "column", flex: "1", children: [jsx(ContentMetricBar, {}), jsx(VizDomContainer, {}), jsx(ContentToolbar, {})] })] }));
1257
1352
  };
1258
1353
 
1259
- const WrapperLayout = ({ header, toolbar, sidebar }) => {
1260
- return (jsxs(BoxStack, { id: "gx-hm-layout", flexDirection: "column", flex: "1", children: [jsx(ContentHeader, { children: header }), jsx(ContentHeader, { children: toolbar }), jsx(WrapperPreview, { children: sidebar })] }));
1354
+ const WrapperLayout = () => {
1355
+ return (jsxs(BoxStack, { id: "gx-hm-layout", flexDirection: "column", flex: "1", children: [jsx(ContentTopBar, {}), jsx(WrapperPreview, {})] }));
1261
1356
  };
1262
1357
 
1263
- const HeatmapLayout = ({ data, clickmap, header, toolbar, sidebar, }) => {
1264
- const setData = useHeatmapDataStore((state) => state.setData);
1265
- const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
1266
- const handleSetClickmap = useCallback((clickmap) => {
1267
- if (!clickmap)
1268
- return;
1269
- setClickmap(clickmap);
1270
- }, [clickmap]);
1271
- const handleSetData = useCallback((data) => {
1272
- if (!data)
1273
- return;
1274
- setData(data);
1275
- }, [data]);
1276
- useEffect(() => {
1277
- handleSetData(data);
1278
- }, [data]);
1279
- useEffect(() => {
1280
- handleSetClickmap(clickmap);
1281
- }, [clickmap]);
1282
- return (jsx(BoxStack, { id: "gx-hm-project", flexDirection: "column", flex: "1", height: "100%", children: jsx(BoxStack, { id: "gx-hm-project-content", flexDirection: "column", flex: "1", children: jsx("div", { style: {
1358
+ const HeatmapLayout = ({ data, clickmap, controls }) => {
1359
+ useRegisterControl(controls);
1360
+ useRegisterData(data);
1361
+ useRegisterHeatmap(clickmap);
1362
+ useRegisterConfig();
1363
+ return (jsx(BoxStack, { id: "gx-hm-project", flexDirection: "column", flex: "1", height: "100%", style: getVariableStyle(), children: jsx(BoxStack, { id: "gx-hm-project-content", flexDirection: "column", flex: "1", children: jsx("div", { style: {
1283
1364
  minHeight: '100%',
1284
1365
  display: 'flex',
1285
- }, children: jsx(WrapperLayout, { header: header, toolbar: toolbar, sidebar: sidebar }) }) }) }));
1366
+ }, children: jsx(WrapperLayout, {}) }) }) }));
1367
+ function getVariableStyle() {
1368
+ return {
1369
+ '--gx-hm-border-width': `${HEATMAP_CONFIG.borderWidth}px`,
1370
+ '--gx-hm-border-color': `${HEATMAP_CONFIG.borderColor}`,
1371
+ };
1372
+ }
1286
1373
  };
1287
1374
 
1288
1375
  var PanelContent;
@@ -1303,4 +1390,4 @@ var ErrorType;
1303
1390
  ErrorType["DataError"] = "DataError";
1304
1391
  })(ErrorType || (ErrorType = {}));
1305
1392
 
1306
- export { GraphView, HeatmapLayout, useHeatmapDataStore };
1393
+ export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapDataStore };
@@ -0,0 +1,7 @@
1
+ import { IHeatmapControl } from '../types/control';
2
+ export interface IHeatmapControlStore {
3
+ controls: IHeatmapControl;
4
+ registerControl: (key: keyof IHeatmapControl, control: IHeatmapControl[keyof IHeatmapControl]) => void;
5
+ }
6
+ export declare const useHeatmapControlStore: import("zustand").UseBoundStore<import("zustand").StoreApi<IHeatmapControlStore>>;
7
+ //# sourceMappingURL=comp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comp.d.ts","sourceRoot":"","sources":["../../src/stores/comp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,EAAE,CACf,GAAG,EAAE,MAAM,eAAe,EAC1B,OAAO,EAAE,eAAe,CAAC,MAAM,eAAe,CAAC,KAC5C,IAAI,CAAC;CACX;AAED,eAAO,MAAM,sBAAsB,mFAkBjC,CAAC"}
@@ -8,6 +8,8 @@ export interface IHeatmapDataStore {
8
8
  config?: IHeatmapConfig;
9
9
  iframeHeight: number;
10
10
  state: IHeatmapState;
11
+ isRendering: boolean;
12
+ setIsRendering: (isRendering: boolean) => void;
11
13
  setState: (state: IHeatmapState) => void;
12
14
  setData: (data: DecodedPayload[]) => void;
13
15
  setClickmap: (clickmap: ClickMapPoint[]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/stores/data.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;IAC1C,WAAW,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACjD,SAAS,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,cAAc,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,cAAc,CAAC,KAAK,IAAI,CAAC;IAC9F,eAAe,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,mBAAmB,gFAgB9B,CAAC"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/stores/data.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAgB,MAAM,UAAU,CAAC;AACvF,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;IAC1C,WAAW,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACjD,SAAS,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,cAAc,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,cAAc,CAAC,KAAK,IAAI,CAAC;IAC9F,eAAe,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,mBAAmB,gFAsB9B,CAAC"}
@@ -1,2 +1,4 @@
1
+ export * from './comp';
1
2
  export * from './data';
3
+ export * from './viz';
2
4
  //# sourceMappingURL=index.d.ts.map