clarity-js 0.8.9 → 0.8.10

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 (90) hide show
  1. package/.lintstagedrc.yml +3 -0
  2. package/biome.json +43 -0
  3. package/build/clarity.extended.js +1 -1
  4. package/build/clarity.insight.js +1 -1
  5. package/build/clarity.js +3095 -2876
  6. package/build/clarity.min.js +1 -1
  7. package/build/clarity.module.js +3095 -2876
  8. package/build/clarity.performance.js +1 -1
  9. package/package.json +17 -10
  10. package/rollup.config.ts +84 -88
  11. package/src/clarity.ts +34 -28
  12. package/src/core/config.ts +2 -2
  13. package/src/core/event.ts +36 -32
  14. package/src/core/hash.ts +5 -6
  15. package/src/core/history.ts +10 -11
  16. package/src/core/index.ts +21 -11
  17. package/src/core/measure.ts +9 -5
  18. package/src/core/report.ts +9 -5
  19. package/src/core/scrub.ts +29 -20
  20. package/src/core/task.ts +73 -45
  21. package/src/core/time.ts +3 -3
  22. package/src/core/timeout.ts +2 -2
  23. package/src/core/version.ts +1 -1
  24. package/src/data/baseline.ts +60 -55
  25. package/src/data/consent.ts +2 -2
  26. package/src/data/custom.ts +8 -13
  27. package/src/data/dimension.ts +11 -7
  28. package/src/data/encode.ts +36 -30
  29. package/src/data/envelope.ts +38 -38
  30. package/src/data/extract.ts +86 -77
  31. package/src/data/index.ts +10 -6
  32. package/src/data/limit.ts +1 -1
  33. package/src/data/metadata.ts +305 -266
  34. package/src/data/metric.ts +18 -8
  35. package/src/data/ping.ts +8 -4
  36. package/src/data/signal.ts +18 -18
  37. package/src/data/summary.ts +6 -4
  38. package/src/data/token.ts +10 -8
  39. package/src/data/upgrade.ts +7 -3
  40. package/src/data/upload.ts +100 -49
  41. package/src/data/variable.ts +27 -20
  42. package/src/diagnostic/encode.ts +2 -2
  43. package/src/diagnostic/fraud.ts +3 -4
  44. package/src/diagnostic/internal.ts +11 -5
  45. package/src/diagnostic/script.ts +12 -8
  46. package/src/global.ts +1 -1
  47. package/src/insight/blank.ts +4 -4
  48. package/src/insight/encode.ts +23 -17
  49. package/src/insight/snapshot.ts +57 -37
  50. package/src/interaction/change.ts +9 -6
  51. package/src/interaction/click.ts +34 -28
  52. package/src/interaction/clipboard.ts +2 -2
  53. package/src/interaction/encode.ts +35 -31
  54. package/src/interaction/input.ts +11 -9
  55. package/src/interaction/pointer.ts +41 -30
  56. package/src/interaction/resize.ts +5 -5
  57. package/src/interaction/scroll.ts +20 -17
  58. package/src/interaction/selection.ts +12 -8
  59. package/src/interaction/submit.ts +2 -2
  60. package/src/interaction/timeline.ts +13 -9
  61. package/src/interaction/unload.ts +1 -1
  62. package/src/interaction/visibility.ts +2 -2
  63. package/src/layout/animation.ts +47 -41
  64. package/src/layout/discover.ts +5 -5
  65. package/src/layout/document.ts +31 -19
  66. package/src/layout/dom.ts +141 -91
  67. package/src/layout/encode.ts +52 -37
  68. package/src/layout/mutation.ts +321 -318
  69. package/src/layout/node.ts +104 -81
  70. package/src/layout/offset.ts +7 -6
  71. package/src/layout/region.ts +66 -43
  72. package/src/layout/schema.ts +15 -8
  73. package/src/layout/selector.ts +47 -25
  74. package/src/layout/style.ts +45 -37
  75. package/src/layout/target.ts +14 -10
  76. package/src/layout/traverse.ts +17 -11
  77. package/src/performance/blank.ts +1 -1
  78. package/src/performance/encode.ts +4 -4
  79. package/src/performance/interaction.ts +58 -70
  80. package/src/performance/navigation.ts +2 -2
  81. package/src/performance/observer.ts +59 -26
  82. package/src/queue.ts +16 -9
  83. package/tsconfig.json +1 -1
  84. package/tslint.json +25 -32
  85. package/types/core.d.ts +13 -13
  86. package/types/data.d.ts +32 -29
  87. package/types/diagnostic.d.ts +1 -1
  88. package/types/interaction.d.ts +5 -4
  89. package/types/layout.d.ts +36 -21
  90. package/types/performance.d.ts +6 -5
@@ -1,9 +1,8 @@
1
- import { Constant, Event, Token } from "@clarity-types/data";
1
+ import { Constant, Event, type Token } from "@clarity-types/data";
2
2
  import * as scrub from "@src/core/scrub";
3
3
  import { time } from "@src/core/time";
4
4
  import * as baseline from "@src/data/baseline";
5
5
  import { queue } from "@src/data/upload";
6
- import { metadata } from "@src/layout/target";
7
6
  import * as change from "@src/interaction/change";
8
7
  import * as click from "@src/interaction/click";
9
8
  import * as clipboard from "@src/interaction/clipboard";
@@ -16,9 +15,10 @@ import * as submit from "@src/interaction/submit";
16
15
  import * as timeline from "@src/interaction/timeline";
17
16
  import * as unload from "@src/interaction/unload";
18
17
  import * as visibility from "@src/interaction/visibility";
18
+ import { metadata } from "@src/layout/target";
19
19
 
20
20
  export default async function (type: Event, ts: number = null): Promise<void> {
21
- let t = ts || time();
21
+ const t = ts || time();
22
22
  let tokens: Token[] = [t, type];
23
23
  switch (type) {
24
24
  case Event.MouseDown:
@@ -30,15 +30,15 @@ export default async function (type: Event, ts: number = null): Promise<void> {
30
30
  case Event.TouchEnd:
31
31
  case Event.TouchMove:
32
32
  case Event.TouchCancel:
33
- for (let entry of pointer.state) {
34
- let pTarget = metadata(entry.data.target as Node, entry.event);
33
+ for (const entry of pointer.state) {
34
+ const pTarget = metadata(entry.data.target as Node, entry.event);
35
35
  if (pTarget.id > 0) {
36
36
  tokens = [entry.time, entry.event];
37
37
  tokens.push(pTarget.id);
38
38
  tokens.push(entry.data.x);
39
39
  tokens.push(entry.data.y);
40
- if (entry.data.id !== undefined) {
41
- tokens.push(entry.data.id);
40
+ if (entry.data.id !== undefined) {
41
+ tokens.push(entry.data.id);
42
42
 
43
43
  if (entry.data.isPrimary !== undefined) {
44
44
  tokens.push(entry.data.isPrimary.toString());
@@ -53,10 +53,10 @@ export default async function (type: Event, ts: number = null): Promise<void> {
53
53
  pointer.reset();
54
54
  break;
55
55
  case Event.Click:
56
- for (let entry of click.state) {
57
- let cTarget = metadata(entry.data.target as Node, entry.event, entry.data.text);
56
+ for (const entry of click.state) {
57
+ const cTarget = metadata(entry.data.target as Node, entry.event, entry.data.text);
58
58
  tokens = [entry.time, entry.event];
59
- let cHash = cTarget.hash ? cTarget.hash.join(Constant.Dot) : Constant.Empty;
59
+ const cHash = cTarget.hash ? cTarget.hash.join(Constant.Dot) : Constant.Empty;
60
60
  tokens.push(cTarget.id);
61
61
  tokens.push(entry.data.x);
62
62
  tokens.push(entry.data.y);
@@ -76,9 +76,9 @@ export default async function (type: Event, ts: number = null): Promise<void> {
76
76
  click.reset();
77
77
  break;
78
78
  case Event.Clipboard:
79
- for (let entry of clipboard.state) {
79
+ for (const entry of clipboard.state) {
80
80
  tokens = [entry.time, entry.event];
81
- let target = metadata(entry.data.target as Node, entry.event);
81
+ const target = metadata(entry.data.target as Node, entry.event);
82
82
  if (target.id > 0) {
83
83
  tokens.push(target.id);
84
84
  tokens.push(entry.data.action);
@@ -87,24 +87,26 @@ export default async function (type: Event, ts: number = null): Promise<void> {
87
87
  }
88
88
  clipboard.reset();
89
89
  break;
90
- case Event.Resize:
91
- let r = resize.data;
90
+ case Event.Resize: {
91
+ const r = resize.data;
92
92
  tokens.push(r.width);
93
93
  tokens.push(r.height);
94
94
  baseline.track(type, r.width, r.height);
95
95
  resize.reset();
96
96
  queue(tokens);
97
97
  break;
98
- case Event.Unload:
99
- let u = unload.data;
98
+ }
99
+ case Event.Unload: {
100
+ const u = unload.data;
100
101
  tokens.push(u.name);
101
102
  tokens.push(u.persisted);
102
103
  unload.reset();
103
104
  queue(tokens);
104
105
  break;
106
+ }
105
107
  case Event.Input:
106
- for (let entry of input.state) {
107
- let iTarget = metadata(entry.data.target as Node, entry.event, entry.data.value);
108
+ for (const entry of input.state) {
109
+ const iTarget = metadata(entry.data.target as Node, entry.event, entry.data.value);
108
110
  tokens = [entry.time, entry.event];
109
111
  tokens.push(iTarget.id);
110
112
  tokens.push(scrub.text(entry.data.value, "input", iTarget.privacy, false, entry.data.type));
@@ -112,11 +114,11 @@ export default async function (type: Event, ts: number = null): Promise<void> {
112
114
  }
113
115
  input.reset();
114
116
  break;
115
- case Event.Selection:
116
- let s = selection.data;
117
+ case Event.Selection: {
118
+ const s = selection.data;
117
119
  if (s) {
118
- let startTarget = metadata(s.start as Node, type);
119
- let endTarget = metadata(s.end as Node, type);
120
+ const startTarget = metadata(s.start as Node, type);
121
+ const endTarget = metadata(s.end as Node, type);
120
122
  tokens.push(startTarget.id);
121
123
  tokens.push(s.startOffset);
122
124
  tokens.push(endTarget.id);
@@ -125,9 +127,10 @@ export default async function (type: Event, ts: number = null): Promise<void> {
125
127
  queue(tokens);
126
128
  }
127
129
  break;
130
+ }
128
131
  case Event.Scroll:
129
- for (let entry of scroll.state) {
130
- let sTarget = metadata(entry.data.target as Node, entry.event);
132
+ for (const entry of scroll.state) {
133
+ const sTarget = metadata(entry.data.target as Node, entry.event);
131
134
  const top = metadata(entry.data.top as Node, entry.event);
132
135
  const bottom = metadata(entry.data.bottom as Node, entry.event);
133
136
  const sTopHash = top?.hash ? top.hash.join(Constant.Dot) : Constant.Empty;
@@ -146,9 +149,9 @@ export default async function (type: Event, ts: number = null): Promise<void> {
146
149
  scroll.reset();
147
150
  break;
148
151
  case Event.Change:
149
- for (let entry of change.state) {
152
+ for (const entry of change.state) {
150
153
  tokens = [entry.time, entry.event];
151
- let target = metadata(entry.data.target as Node, entry.event);
154
+ const target = metadata(entry.data.target as Node, entry.event);
152
155
  if (target.id > 0) {
153
156
  tokens = [entry.time, entry.event];
154
157
  tokens.push(target.id);
@@ -161,9 +164,9 @@ export default async function (type: Event, ts: number = null): Promise<void> {
161
164
  change.reset();
162
165
  break;
163
166
  case Event.Submit:
164
- for (let entry of submit.state) {
167
+ for (const entry of submit.state) {
165
168
  tokens = [entry.time, entry.event];
166
- let target = metadata(entry.data.target as Node, entry.event);
169
+ const target = metadata(entry.data.target as Node, entry.event);
167
170
  if (target.id > 0) {
168
171
  tokens.push(target.id);
169
172
  queue(tokens);
@@ -172,7 +175,7 @@ export default async function (type: Event, ts: number = null): Promise<void> {
172
175
  submit.reset();
173
176
  break;
174
177
  case Event.Timeline:
175
- for (let entry of timeline.updates) {
178
+ for (const entry of timeline.updates) {
176
179
  tokens = [entry.time, entry.event];
177
180
  tokens.push(entry.data.type);
178
181
  tokens.push(entry.data.hash);
@@ -184,12 +187,13 @@ export default async function (type: Event, ts: number = null): Promise<void> {
184
187
  }
185
188
  timeline.reset();
186
189
  break;
187
- case Event.Visibility:
188
- let v = visibility.data;
190
+ case Event.Visibility: {
191
+ const v = visibility.data;
189
192
  tokens.push(v.visible);
190
193
  queue(tokens);
191
194
  baseline.visibility(t, v.visible);
192
195
  visibility.reset();
193
196
  break;
197
+ }
194
198
  }
195
199
  }
@@ -1,13 +1,13 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { InputData, InputState, Setting } from "@clarity-types/interaction";
2
+ import { type InputData, type InputState, Setting } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import { schedule } from "@src/core/task";
6
6
  import { time } from "@src/core/time";
7
7
  import { clearTimeout, setTimeout } from "@src/core/timeout";
8
8
  import { get } from "@src/layout/dom";
9
- import encode from "./encode";
10
9
  import { target } from "@src/layout/target";
10
+ import encode from "./encode";
11
11
 
12
12
  let timeout: number = null;
13
13
  export let state: InputState[] = [];
@@ -22,11 +22,11 @@ export function observe(root: Node): void {
22
22
 
23
23
  function recompute(evt: UIEvent): void {
24
24
  recompute.dn = FunctionNames.InputRecompute;
25
- let input = target(evt) as HTMLInputElement;
26
- let value = get(input);
27
- if (input && input.type && value) {
25
+ const input = target(evt) as HTMLInputElement;
26
+ const value = get(input);
27
+ if (input?.type && value) {
28
28
  let v = input.value;
29
- let t = input.type;
29
+ const t = input.type;
30
30
  switch (input.type) {
31
31
  case "radio":
32
32
  case "checkbox":
@@ -34,10 +34,12 @@ function recompute(evt: UIEvent): void {
34
34
  break;
35
35
  }
36
36
 
37
- let data: InputData = { target: input, value: v, type: t };
37
+ const data: InputData = { target: input, value: v, type: t };
38
38
 
39
39
  // If last entry in the queue is for the same target node as the current one, remove it so we can later swap it with current data.
40
- if (state.length > 0 && (state[state.length - 1].data.target === data.target)) { state.pop(); }
40
+ if (state.length > 0 && state[state.length - 1].data.target === data.target) {
41
+ state.pop();
42
+ }
41
43
 
42
44
  state.push({ time: time(evt), event: Event.Input, data });
43
45
 
@@ -57,4 +59,4 @@ export function reset(): void {
57
59
  export function stop(): void {
58
60
  clearTimeout(timeout);
59
61
  reset();
60
- }
62
+ }
@@ -1,5 +1,5 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { PointerState, Setting } from "@clarity-types/interaction";
2
+ import { type PointerState, Setting } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import { schedule } from "@src/core/task";
@@ -34,45 +34,47 @@ export function observe(root: Node): void {
34
34
 
35
35
  function mouse(event: Event, root: Node, evt: MouseEvent): void {
36
36
  mouse.dn = FunctionNames.PointerMouse;
37
- let frame = iframe(root);
38
- let d = frame ? frame.contentDocument.documentElement : document.documentElement;
39
- let x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
40
- let y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
37
+ const frame = iframe(root);
38
+ const d = frame ? frame.contentDocument.documentElement : document.documentElement;
39
+ let x = "pageX" in evt ? Math.round(evt.pageX) : "clientX" in evt ? Math.round((evt as MouseEvent).clientX + d.scrollLeft) : null;
40
+ let y = "pageY" in evt ? Math.round(evt.pageY) : "clientY" in evt ? Math.round((evt as MouseEvent).clientY + d.scrollTop) : null;
41
41
  // In case of iframe, we adjust (x,y) to be relative to top parent's origin
42
42
  if (frame) {
43
- let distance = offset(frame);
43
+ const distance = offset(frame);
44
44
  x = x ? x + Math.round(distance.x) : x;
45
45
  y = y ? y + Math.round(distance.y) : y;
46
46
  }
47
47
 
48
48
  // Check for null values before processing this event
49
- if (x !== null && y !== null) { handler({ time: time(evt), event, data: { target: target(evt), x, y } }); }
49
+ if (x !== null && y !== null) {
50
+ handler({ time: time(evt), event, data: { target: target(evt), x, y } });
51
+ }
50
52
  }
51
53
 
52
54
  function touch(event: Event, root: Node, evt: TouchEvent): void {
53
55
  touch.dn = FunctionNames.PointerTouch;
54
- let frame = iframe(root);
55
- let d = frame ? frame.contentDocument.documentElement : document.documentElement;
56
- let touches = evt.changedTouches;
56
+ const frame = iframe(root);
57
+ const d = frame ? frame.contentDocument.documentElement : document.documentElement;
58
+ const touches = evt.changedTouches;
57
59
 
58
- let t = time(evt);
60
+ const t = time(evt);
59
61
  if (touches) {
60
62
  for (let i = 0; i < touches.length; i++) {
61
- let entry = touches[i];
62
- let x = "clientX" in entry ? Math.round(entry["clientX"] + d.scrollLeft) : null;
63
- let y = "clientY" in entry ? Math.round(entry["clientY"] + d.scrollTop) : null;
63
+ const entry = touches[i];
64
+ let x = "clientX" in entry ? Math.round(entry.clientX + d.scrollLeft) : null;
65
+ let y = "clientY" in entry ? Math.round(entry.clientY + d.scrollTop) : null;
64
66
  x = x && frame ? x + Math.round(frame.offsetLeft) : x;
65
67
  y = y && frame ? y + Math.round(frame.offsetTop) : y;
66
68
 
67
69
  // We cannot rely on identifier to determine primary touch as its value doesn't always start with 0.
68
70
  // Safari/Webkit uses the address of the UITouch object as the identifier value for each touch point.
69
- const id = "identifier" in entry ? entry["identifier"] : undefined;
71
+ const id = "identifier" in entry ? entry.identifier : undefined;
70
72
 
71
- switch(event) {
73
+ switch (event) {
72
74
  case Event.TouchStart:
73
75
  if (activeTouchPointIds.size === 0) {
74
76
  // Track presence of primary touch separately to handle scenarios when same id is repeated
75
- hasPrimaryTouch = true;
77
+ hasPrimaryTouch = true;
76
78
  primaryTouchId = id;
77
79
  }
78
80
  activeTouchPointIds.add(id);
@@ -85,11 +87,15 @@ function touch(event: Event, root: Node, evt: TouchEvent): void {
85
87
  const isPrimary = hasPrimaryTouch && primaryTouchId === id;
86
88
 
87
89
  // Check for null values before processing this event
88
- if (x !== null && y !== null) { handler({ time: t, event, data: { target: target(evt), x, y, id, isPrimary } }); }
90
+ if (x !== null && y !== null) {
91
+ handler({ time: t, event, data: { target: target(evt), x, y, id, isPrimary } });
92
+ }
89
93
 
90
94
  // Reset primary touch point id once touch event ends
91
95
  if (event === Event.TouchCancel || event === Event.TouchEnd) {
92
- if (primaryTouchId === id) { hasPrimaryTouch = false; }
96
+ if (primaryTouchId === id) {
97
+ hasPrimaryTouch = false;
98
+ }
93
99
  }
94
100
  }
95
101
  }
@@ -99,15 +105,18 @@ function handler(current: PointerState): void {
99
105
  switch (current.event) {
100
106
  case Event.MouseMove:
101
107
  case Event.MouseWheel:
102
- case Event.TouchMove:
103
- let length = state.length;
104
- let last = length > 1 ? state[length - 2] : null;
105
- if (last && similar(last, current)) { state.pop(); }
108
+ case Event.TouchMove: {
109
+ const length = state.length;
110
+ const last = length > 1 ? state[length - 2] : null;
111
+ if (last && similar(last, current)) {
112
+ state.pop();
113
+ }
106
114
  state.push(current);
107
115
 
108
116
  clearTimeout(timeout);
109
117
  timeout = setTimeout(process, Setting.LookAhead, current.event);
110
118
  break;
119
+ }
111
120
  default:
112
121
  state.push(current);
113
122
  process(current.event);
@@ -124,17 +133,19 @@ export function reset(): void {
124
133
  }
125
134
 
126
135
  function similar(last: PointerState, current: PointerState): boolean {
127
- let dx = last.data.x - current.data.x;
128
- let dy = last.data.y - current.data.y;
129
- let distance = Math.sqrt(dx * dx + dy * dy);
130
- let gap = current.time - last.time;
131
- let match = current.data.target === last.data.target;
132
- let sameId = current.data.id !== undefined ? current.data.id === last.data.id : true;
136
+ const dx = last.data.x - current.data.x;
137
+ const dy = last.data.y - current.data.y;
138
+ const distance = Math.sqrt(dx * dx + dy * dy);
139
+ const gap = current.time - last.time;
140
+ const match = current.data.target === last.data.target;
141
+ const sameId = current.data.id !== undefined ? current.data.id === last.data.id : true;
133
142
  return current.event === last.event && match && distance < Setting.Distance && gap < Setting.Interval && sameId;
134
143
  }
135
144
 
136
145
  export function stop(): void {
137
146
  clearTimeout(timeout);
138
147
  // Send out any pending pointer events in the pipeline
139
- if (state.length > 0) { process(state[state.length - 1].event); }
148
+ if (state.length > 0) {
149
+ process(state[state.length - 1].event);
150
+ }
140
151
  }
@@ -1,10 +1,10 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { ResizeData, Setting } from "@clarity-types/interaction";
2
+ import { type ResizeData, Setting } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
- import { clearTimeout, setTimeout } from "@src/core/timeout";
5
4
  import { bind } from "@src/core/event";
6
- import encode from "./encode";
7
5
  import { schedule } from "@src/core/task";
6
+ import { clearTimeout, setTimeout } from "@src/core/timeout";
7
+ import encode from "./encode";
8
8
 
9
9
  export let data: ResizeData;
10
10
  let timeout: number = null;
@@ -18,7 +18,7 @@ export function start(): void {
18
18
 
19
19
  function recompute(): void {
20
20
  recompute.dn = FunctionNames.ResizeRecompute;
21
- let de = document.documentElement;
21
+ const de = document.documentElement;
22
22
  // window.innerWidth includes width of the scrollbar and is not a true representation of the viewport width.
23
23
  // Therefore, when possible, use documentElement's clientWidth property.
24
24
  data = {
@@ -45,4 +45,4 @@ export function reset(): void {
45
45
 
46
46
  export function stop(): void {
47
47
  reset();
48
- }
48
+ }
@@ -1,14 +1,14 @@
1
1
  import { Constant, Dimension, Event } from "@clarity-types/data";
2
- import { ScrollState, Setting } from "@clarity-types/interaction";
2
+ import { type ScrollState, Setting } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import { schedule } from "@src/core/task";
6
6
  import { time } from "@src/core/time";
7
7
  import { clearTimeout, setTimeout } from "@src/core/timeout";
8
+ import * as dimension from "@src/data/dimension";
8
9
  import { iframe } from "@src/layout/dom";
9
- import { target, metadata } from "@src/layout/target";
10
+ import { metadata, target } from "@src/layout/target";
10
11
  import encode from "./encode";
11
- import * as dimension from "@src/data/dimension";
12
12
 
13
13
  export let state: ScrollState[] = [];
14
14
  let initialTop: Node = null;
@@ -21,8 +21,8 @@ export function start(): void {
21
21
  }
22
22
 
23
23
  export function observe(root: Node): void {
24
- let frame = iframe(root);
25
- let node = frame ? frame.contentWindow : (root === document ? window : root);
24
+ const frame = iframe(root);
25
+ const node = frame ? frame.contentWindow : root === document ? window : root;
26
26
  bind(node, "scroll", recompute, true);
27
27
  }
28
28
 
@@ -34,7 +34,7 @@ function recompute(event: UIEvent = null): void {
34
34
 
35
35
  // If the target is a Document node, then identify corresponding documentElement and window for this document
36
36
  if (element && element.nodeType === Node.DOCUMENT_NODE) {
37
- let frame = iframe(element);
37
+ const frame = iframe(element);
38
38
  w = frame ? frame.contentWindow : w;
39
39
  element = de = (element as Document).documentElement;
40
40
  }
@@ -42,8 +42,8 @@ function recompute(event: UIEvent = null): void {
42
42
  // Edge doesn't support scrollTop position on document.documentElement.
43
43
  // For cross browser compatibility, looking up pageYOffset on window if the scroll is on document.
44
44
  // And, if for some reason that is not available, fall back to looking up scrollTop on document.documentElement.
45
- let x = element === de && "pageXOffset" in w ? Math.round(w.pageXOffset) : Math.round((element as HTMLElement).scrollLeft);
46
- let y = element === de && "pageYOffset" in w ? Math.round(w.pageYOffset) : Math.round((element as HTMLElement).scrollTop);
45
+ const x = element === de && "pageXOffset" in w ? Math.round(w.pageXOffset) : Math.round((element as HTMLElement).scrollLeft);
46
+ const y = element === de && "pageYOffset" in w ? Math.round(w.pageYOffset) : Math.round((element as HTMLElement).scrollTop);
47
47
  const width = window.innerWidth;
48
48
  const height = window.innerHeight;
49
49
  const xPosition = width / 3;
@@ -53,18 +53,20 @@ function recompute(event: UIEvent = null): void {
53
53
  const top = getPositionNode(xPosition, startYPosition);
54
54
  const bottom = getPositionNode(xPosition, endYPosition);
55
55
 
56
- let current: ScrollState = { time: time(event), event: Event.Scroll, data: {target: element, x, y, top, bottom} };
56
+ const current: ScrollState = { time: time(event), event: Event.Scroll, data: { target: element, x, y, top, bottom } };
57
57
 
58
58
  // We don't send any scroll events if this is the first event and the current position is top (0,0)
59
- if ((event === null && x === 0 && y === 0) || (x === null || y === null)) {
59
+ if ((event === null && x === 0 && y === 0) || x === null || y === null) {
60
60
  initialTop = top;
61
61
  initialBottom = bottom;
62
62
  return;
63
63
  }
64
64
 
65
- let length = state.length;
66
- let last = length > 1 ? state[length - 2] : null;
67
- if (last && similar(last, current)) { state.pop(); }
65
+ const length = state.length;
66
+ const last = length > 1 ? state[length - 2] : null;
67
+ if (last && similar(last, current)) {
68
+ state.pop();
69
+ }
68
70
  state.push(current);
69
71
 
70
72
  clearTimeout(timeout);
@@ -74,9 +76,10 @@ function recompute(event: UIEvent = null): void {
74
76
  function getPositionNode(x: number, y: number): Node {
75
77
  let node: Node;
76
78
  if ("caretPositionFromPoint" in document) {
79
+ // biome-ignore lint/suspicious/noExplicitAny: caretPositionFromPoint is not defined on all browsers, makes typescript unhappy
77
80
  node = (document as any).caretPositionFromPoint(x, y)?.offsetNode;
78
81
  } else if ("caretRangeFromPoint" in document) {
79
- node = (document as any).caretRangeFromPoint(x, y)?.startContainer;
82
+ node = (document as Document).caretRangeFromPoint(x, y)?.startContainer;
80
83
  }
81
84
  if (!node) {
82
85
  node = document.elementFromPoint(x, y) as Node;
@@ -99,9 +102,9 @@ function process(event: Event): void {
99
102
  }
100
103
 
101
104
  function similar(last: ScrollState, current: ScrollState): boolean {
102
- let dx = last.data.x - current.data.x;
103
- let dy = last.data.y - current.data.y;
104
- return (dx * dx + dy * dy < Setting.Distance * Setting.Distance) && (current.time - last.time < Setting.Interval);
105
+ const dx = last.data.x - current.data.x;
106
+ const dy = last.data.y - current.data.y;
107
+ return dx * dx + dy * dy < Setting.Distance * Setting.Distance && current.time - last.time < Setting.Interval;
105
108
  }
106
109
 
107
110
  export function compute(): void {
@@ -1,5 +1,5 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { SelectionData, Setting } from "@clarity-types/interaction";
2
+ import { type SelectionData, Setting } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import { schedule } from "@src/core/task";
@@ -21,21 +21,25 @@ export function observe(root: Node): void {
21
21
 
22
22
  function recompute(root: Node): void {
23
23
  recompute.dn = FunctionNames.SelectionRecompute;
24
- let doc = root.nodeType === Node.DOCUMENT_NODE ? root as Document : document;
25
- let current = doc.getSelection();
24
+ const doc = root.nodeType === Node.DOCUMENT_NODE ? (root as Document) : document;
25
+ const current = doc.getSelection();
26
26
 
27
27
  // Bail out if we don't have a valid selection
28
- if (current === null) { return; }
28
+ if (current === null) {
29
+ return;
30
+ }
29
31
 
30
32
  // Bail out if we got a valid selection but not valid nodes
31
33
  // In Edge, selectionchange gets fired even on interactions like right clicks and
32
34
  // can result in null anchorNode and focusNode if there was no previous selection on page
33
35
  // Also, ignore any selections that start and end at the exact same point
34
- if ((current.anchorNode === null && current.focusNode === null) ||
35
- (current.anchorNode === current.focusNode && current.anchorOffset === current.focusOffset)) {
36
+ if (
37
+ (current.anchorNode === null && current.focusNode === null) ||
38
+ (current.anchorNode === current.focusNode && current.anchorOffset === current.focusOffset)
39
+ ) {
36
40
  return;
37
41
  }
38
- let startNode = data.start ? data.start : null;
42
+ const startNode = data.start ? data.start : null;
39
43
  if (previous !== null && data.start !== null && startNode !== current.anchorNode) {
40
44
  clearTimeout(timeout);
41
45
  process(Event.Selection);
@@ -45,7 +49,7 @@ function recompute(root: Node): void {
45
49
  start: current.anchorNode,
46
50
  startOffset: current.anchorOffset,
47
51
  end: current.focusNode,
48
- endOffset: current.focusOffset
52
+ endOffset: current.focusOffset,
49
53
  };
50
54
  previous = current;
51
55
 
@@ -1,11 +1,11 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { SubmitState } from "@clarity-types/interaction";
2
+ import type { SubmitState } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import { schedule } from "@src/core/task";
6
6
  import { time } from "@src/core/time";
7
- import encode from "./encode";
8
7
  import { target } from "@src/layout/target";
8
+ import encode from "./encode";
9
9
 
10
10
  export let state: SubmitState[] = [];
11
11
 
@@ -1,5 +1,5 @@
1
1
  import { BooleanFlag, Event } from "@clarity-types/data";
2
- import { BrowsingContext, Setting, TimelineState } from "@clarity-types/interaction";
2
+ import { BrowsingContext, Setting, type TimelineState } from "@clarity-types/interaction";
3
3
  import * as baseline from "@src/data/baseline";
4
4
  import * as envelope from "@src/data/envelope";
5
5
  import encode from "@src/interaction/encode";
@@ -16,13 +16,15 @@ export function reset(): void {
16
16
  updates = [];
17
17
  }
18
18
 
19
- export function track(time: number,
19
+ export function track(
20
+ time: number,
20
21
  event: Event,
21
22
  hash: string,
22
23
  x: number,
23
24
  y: number,
24
25
  reaction: number = BooleanFlag.True,
25
- context: number = BrowsingContext.Self): void {
26
+ context: number = BrowsingContext.Self,
27
+ ): void {
26
28
  state.push({
27
29
  time,
28
30
  event: Event.Timeline,
@@ -32,8 +34,8 @@ export function track(time: number,
32
34
  x,
33
35
  y,
34
36
  reaction,
35
- context
36
- }
37
+ context,
38
+ },
37
39
  });
38
40
 
39
41
  // Since timeline only keeps the data for configured time, we still want to continue tracking these values
@@ -45,12 +47,14 @@ export function track(time: number,
45
47
  export function compute(): void {
46
48
  const temp = [];
47
49
  updates = [];
48
- let max = envelope.data.start + envelope.data.duration;
49
- let min = Math.max(max - Setting.TimelineSpan, 0);
50
+ const max = envelope.data.start + envelope.data.duration;
51
+ const min = Math.max(max - Setting.TimelineSpan, 0);
50
52
 
51
- for (let s of state) {
53
+ for (const s of state) {
52
54
  if (s.time >= min) {
53
- if (s.time <= max) { updates.push(s); }
55
+ if (s.time <= max) {
56
+ updates.push(s);
57
+ }
54
58
  temp.push(s);
55
59
  }
56
60
  }
@@ -1,5 +1,5 @@
1
1
  import { BooleanFlag, Event } from "@clarity-types/data";
2
- import { UnloadData } from "@clarity-types/interaction";
2
+ import type { UnloadData } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import * as clarity from "@src/clarity";
5
5
  import { bind } from "@src/core/event";
@@ -1,5 +1,5 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { VisibilityData } from "@clarity-types/interaction";
2
+ import type { VisibilityData } from "@clarity-types/interaction";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import { time } from "@src/core/time";
@@ -24,4 +24,4 @@ export function reset(): void {
24
24
 
25
25
  export function stop(): void {
26
26
  reset();
27
- }
27
+ }