clarity-js 0.8.10-beta → 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 +3581 -3019
  6. package/build/clarity.min.js +1 -1
  7. package/build/clarity.module.js +3581 -3019
  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 +44 -36
  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 +2 -2
  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,5 +1,5 @@
1
- import { Code, Event, Severity } from "@clarity-types/data";
2
- import { LogData } from "@clarity-types/diagnostic";
1
+ import { type Code, Event, type Severity } from "@clarity-types/data";
2
+ import type { LogData } from "@clarity-types/diagnostic";
3
3
  import encode from "./encode";
4
4
 
5
5
  let history: { [key: number]: string[] } = {};
@@ -10,15 +10,21 @@ export function start(): void {
10
10
  }
11
11
 
12
12
  export function log(code: Code, severity: Severity, name: string = null, message: string = null, stack: string = null): void {
13
- let key = name ? `${name}|${message}`: "";
13
+ const key = name ? `${name}|${message}` : "";
14
14
  // While rare, it's possible for code to fail repeatedly during the lifetime of the same page
15
15
  // In those cases, we only want to log the failure once and not spam logs with redundant information.
16
- if (code in history && history[code].indexOf(key) >= 0) { return; }
16
+ if (code in history && history[code].indexOf(key) >= 0) {
17
+ return;
18
+ }
17
19
 
18
20
  data = { code, name, message, stack, severity };
19
21
 
20
22
  // Maintain history of errors in memory to avoid sending redundant information
21
- if (code in history) { history[code].push(key); } else { history[code] = [key]; }
23
+ if (code in history) {
24
+ history[code].push(key);
25
+ } else {
26
+ history[code] = [key];
27
+ }
22
28
 
23
29
  encode(Event.Log);
24
30
  }
@@ -1,5 +1,5 @@
1
1
  import { Event, Setting } from "@clarity-types/data";
2
- import { ScriptErrorData } from "@clarity-types/diagnostic";
2
+ import type { ScriptErrorData } from "@clarity-types/diagnostic";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
4
  import { bind } from "@src/core/event";
5
5
  import encode from "./encode";
@@ -14,20 +14,24 @@ export function start(): void {
14
14
 
15
15
  function handler(error: ErrorEvent): boolean {
16
16
  handler.dn = FunctionNames.ScriptHandler;
17
- let e = error["error"] || error;
17
+ const e = error.error || error;
18
18
  // While rare, it's possible for code to fail repeatedly during the lifetime of the same page
19
19
  // In those cases, we only want to log the failure first few times and not spam logs with redundant information.
20
- if (!(e.message in history)) { history[e.message] = 0; }
21
- if (history[e.message]++ >= Setting.ScriptErrorLimit) { return true; }
20
+ if (!(e.message in history)) {
21
+ history[e.message] = 0;
22
+ }
23
+ if (history[e.message]++ >= Setting.ScriptErrorLimit) {
24
+ return true;
25
+ }
22
26
 
23
27
  // Send back information only if the handled error has valid information
24
- if (e && e.message) {
28
+ if (e?.message) {
25
29
  data = {
26
30
  message: e.message,
27
- line: error["lineno"],
28
- column: error["colno"],
31
+ line: error.lineno,
32
+ column: error.colno,
29
33
  stack: e.stack,
30
- source: error["filename"]
34
+ source: error.filename,
31
35
  };
32
36
 
33
37
  encode(Event.ScriptError);
package/src/global.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as queue from "@src/queue";
2
2
 
3
3
  // Process anything that was queued up before the script loaded
4
- (function(): void {
4
+ ((): void => {
5
5
  queue.process();
6
6
  })();
@@ -1,7 +1,7 @@
1
- export let state = [];
2
- export let sheetAdoptionState = [];
3
- export let sheetUpdateState = [];
4
- export let data = null;
1
+ export const state = [];
2
+ export const sheetAdoptionState = [];
3
+ export const sheetUpdateState = [];
4
+ export const data = null;
5
5
 
6
6
  /* Intentionally blank module with empty code */
7
7
 
@@ -1,6 +1,6 @@
1
- import { Privacy } from "@clarity-types/core";
2
- import { Event, Token } from "@clarity-types/data";
3
- import { Constant, NodeInfo } from "@clarity-types/layout";
1
+ import type { Privacy } from "@clarity-types/core";
2
+ import { Event, type Token } from "@clarity-types/data";
3
+ import { Constant, type NodeInfo } from "@clarity-types/layout";
4
4
  import * as scrub from "@src/core/scrub";
5
5
  import { time } from "@src/core/time";
6
6
  import * as baseline from "@src/data/baseline";
@@ -10,34 +10,39 @@ import * as snapshot from "@src/insight/snapshot";
10
10
  import * as doc from "@src/layout/document";
11
11
 
12
12
  export default async function (type: Event): Promise<void> {
13
- let eventTime = time()
14
- let tokens: Token[] = [eventTime, type];
13
+ const eventTime = time();
14
+ const tokens: Token[] = [eventTime, type];
15
15
  switch (type) {
16
- case Event.Document:
17
- let d = doc.data;
16
+ case Event.Document: {
17
+ const d = doc.data;
18
18
  tokens.push(d.width);
19
19
  tokens.push(d.height);
20
20
  baseline.track(type, d.width, d.height);
21
21
  queue(tokens);
22
22
  break;
23
- case Event.Snapshot:
24
- let values = snapshot.values;
23
+ }
24
+ case Event.Snapshot: {
25
+ const values = snapshot.values;
25
26
  // Only encode and queue DOM updates if we have valid updates to report back
26
27
  if (values.length > 0) {
27
- for (let value of values) {
28
- let privacy = value.metadata.privacy;
29
- let data: NodeInfo = value.data;
30
- for (let key of ["tag", "attributes", "value"]) {
28
+ for (const value of values) {
29
+ const privacy = value.metadata.privacy;
30
+ const data: NodeInfo = value.data;
31
+ for (const key of ["tag", "attributes", "value"]) {
31
32
  if (data[key]) {
32
33
  switch (key) {
33
34
  case "tag":
34
35
  tokens.push(value.id);
35
- if (value.parent) { tokens.push(value.parent); }
36
- if (value.previous) { tokens.push(value.previous); }
36
+ if (value.parent) {
37
+ tokens.push(value.parent);
38
+ }
39
+ if (value.previous) {
40
+ tokens.push(value.previous);
41
+ }
37
42
  tokens.push(data[key]);
38
43
  break;
39
44
  case "attributes":
40
- for (let attr in data[key]) {
45
+ for (const attr in data[key]) {
41
46
  if (data[key][attr] !== undefined) {
42
47
  tokens.push(attribute(attr, data[key][attr], privacy));
43
48
  }
@@ -53,9 +58,10 @@ export default async function (type: Event): Promise<void> {
53
58
  queue(tokenize(tokens), true);
54
59
  }
55
60
  break;
61
+ }
56
62
  }
57
63
  }
58
64
 
59
65
  function attribute(key: string, value: string, privacy: Privacy): string {
60
66
  return `${key}=${scrub.text(value, key.indexOf(Constant.DataAttribute) === 0 ? Constant.DataAttribute : key, privacy)}`;
61
- }
67
+ }
@@ -1,12 +1,12 @@
1
- import { OffsetDistance, Privacy } from "@clarity-types/core";
1
+ import { type OffsetDistance, Privacy } from "@clarity-types/core";
2
2
  import { Event } from "@clarity-types/data";
3
- import { Constant, NodeInfo, NodeValue, TargetMetadata } from "@clarity-types/layout";
4
- import * as doc from "@src/layout/document";
3
+ import { Constant, type NodeInfo, type NodeValue, type TargetMetadata } from "@clarity-types/layout";
4
+ import config from "@src/core/config";
5
5
  import encode from "@src/insight/encode";
6
6
  import * as interaction from "@src/interaction";
7
- import config from "@src/core/config";
7
+ import * as doc from "@src/layout/document";
8
8
  export let values: NodeValue[] = [];
9
- let index: number = 1;
9
+ let index = 1;
10
10
  let idMap: WeakMap<Node, number> = null; // Maps node => id.
11
11
 
12
12
  export function start(): void {
@@ -21,24 +21,34 @@ export function stop(): void {
21
21
  doc.stop();
22
22
  }
23
23
 
24
- export function compute(): void { /* Intentionally Blank */ }
25
- export function iframe(): boolean { return false; }
26
- export function offset(): OffsetDistance { return { x: 0, y: 0 }; }
27
- export function hashText(): void { /* Intentionally Blank */ }
24
+ export function compute(): void {
25
+ /* Intentionally Blank */
26
+ }
27
+ export function iframe(): boolean {
28
+ return false;
29
+ }
30
+ export function offset(): OffsetDistance {
31
+ return { x: 0, y: 0 };
32
+ }
33
+ export function hashText(): void {
34
+ /* Intentionally Blank */
35
+ }
28
36
 
29
37
  export function target(evt: UIEvent): Node {
30
- let path = evt.composed && evt.composedPath ? evt.composedPath() : null;
31
- let node = (path && path.length > 0 ? path[0] : evt.target) as Node;
38
+ const path = evt.composed && evt.composedPath ? evt.composedPath() : null;
39
+ const node = (path && path.length > 0 ? path[0] : evt.target) as Node;
32
40
  return node.nodeType === Node.DOCUMENT_NODE ? (node as Document).documentElement : node;
33
41
  }
34
42
 
35
43
  export function metadata(node: Node): TargetMetadata {
36
- let output: TargetMetadata = { id: 0, hash: null, privacy: config.conversions ? Privacy.Sensitive : Privacy.Snapshot };
37
- if (node) { output.id = idMap.has(node) ? idMap.get(node) : getId(node); }
44
+ const output: TargetMetadata = { id: 0, hash: null, privacy: config.conversions ? Privacy.Sensitive : Privacy.Snapshot };
45
+ if (node) {
46
+ output.id = idMap.has(node) ? idMap.get(node) : getId(node);
47
+ }
38
48
  return output;
39
49
  }
40
50
 
41
- export function snapshot(): void {
51
+ export function snapshot(): void {
42
52
  values = [];
43
53
  traverse(document);
44
54
  encode(Event.Snapshot);
@@ -49,46 +59,50 @@ function reset(): void {
49
59
  }
50
60
 
51
61
  function traverse(root: Node): void {
52
- let queue = [root];
62
+ const queue = [root];
53
63
  while (queue.length > 0) {
54
- let attributes = null, tag = null, value = null;
55
- let node = queue.shift();
64
+ let attributes = null;
65
+ let tag = null;
66
+ let value = null;
67
+ const node = queue.shift();
56
68
  let next = node.firstChild;
57
- let parent = node.parentElement ? node.parentElement : (node.parentNode ? node.parentNode : null);
69
+ const parent = node.parentElement ? node.parentElement : node.parentNode ? node.parentNode : null;
58
70
 
59
71
  while (next) {
60
72
  queue.push(next);
61
73
  next = next.nextSibling;
62
74
  }
63
-
75
+
64
76
  // Process the node
65
- let type = node.nodeType;
77
+ const type = node.nodeType;
66
78
  switch (type) {
67
- case Node.DOCUMENT_TYPE_NODE:
68
- let doctype = node as DocumentType;
79
+ case Node.DOCUMENT_TYPE_NODE: {
80
+ const doctype = node as DocumentType;
69
81
  tag = Constant.DocumentTag;
70
- attributes = { name: doctype.name, publicId: doctype.publicId, systemId: doctype.systemId }
82
+ attributes = { name: doctype.name, publicId: doctype.publicId, systemId: doctype.systemId };
71
83
  break;
72
- case Node.TEXT_NODE:
84
+ }
85
+ case Node.TEXT_NODE:
73
86
  value = node.nodeValue;
74
87
  tag = idMap.get(parent) ? Constant.TextTag : tag;
75
88
  break;
76
- case Node.ELEMENT_NODE:
77
- let element = node as HTMLElement;
89
+ case Node.ELEMENT_NODE: {
90
+ const element = node as HTMLElement;
78
91
  attributes = getAttributes(element);
79
92
  tag = ["NOSCRIPT", "SCRIPT", "STYLE"].indexOf(element.tagName) < 0 ? element.tagName : tag;
80
93
  break;
94
+ }
81
95
  }
82
- add(node, parent, { tag, attributes, value });
96
+ add(node, parent, { tag, attributes, value });
83
97
  }
84
98
  }
85
99
 
86
100
  /* Helper Functions - Snapshot Traversal */
87
101
  function getAttributes(element: HTMLElement): { [key: string]: string } {
88
- let output = {};
89
- let attributes = element.attributes;
102
+ const output = {};
103
+ const attributes = element.attributes;
90
104
  if (attributes && attributes.length > 0) {
91
- for (let i = 0; i < attributes.length; i++) {
105
+ for (let i = 0; i < attributes.length; i++) {
92
106
  output[attributes[i].name] = attributes[i].value;
93
107
  }
94
108
  }
@@ -96,20 +110,26 @@ function getAttributes(element: HTMLElement): { [key: string]: string } {
96
110
  }
97
111
 
98
112
  function getId(node: Node): number {
99
- if (node === null) { return null; }
100
- if (idMap.has(node)) { return idMap.get(node); }
113
+ if (node === null) {
114
+ return null;
115
+ }
116
+ if (idMap.has(node)) {
117
+ return idMap.get(node);
118
+ }
101
119
  idMap.set(node, index);
102
120
  return index++;
103
121
  }
104
122
 
105
123
  function add(node: Node, parent: Node, data: NodeInfo): void {
106
124
  if (node && data && data.tag) {
107
- let id = getId(node);
108
- let parentId = parent ? idMap.get(parent) : null;
109
- let previous = node.previousSibling ? idMap.get(node.previousSibling) : null;
110
- let metadata = { active: true, suspend: false, privacy: Privacy.Snapshot, position: null, fraud: null, size: null };
125
+ const id = getId(node);
126
+ const parentId = parent ? idMap.get(parent) : null;
127
+ const previous = node.previousSibling ? idMap.get(node.previousSibling) : null;
128
+ const metadata = { active: true, suspend: false, privacy: Privacy.Snapshot, position: null, fraud: null, size: null };
111
129
  values.push({ id, parent: parentId, previous, children: [], data, selector: null, hash: null, region: null, metadata });
112
130
  }
113
131
  }
114
132
 
115
- export function get(_node: Node): NodeValue {return null;}
133
+ export function get(_node: Node): NodeValue {
134
+ return null;
135
+ }
@@ -1,5 +1,6 @@
1
1
  import { Constant, Event, Setting } from "@clarity-types/data";
2
- import { ChangeState } from "@clarity-types/interaction";
2
+ import type { ChangeState } from "@clarity-types/interaction";
3
+ import { Mask } from "@clarity-types/layout";
3
4
  import { FunctionNames } from "@clarity-types/performance";
4
5
  import config from "@src/core/config";
5
6
  import { bind } from "@src/core/event";
@@ -8,7 +9,6 @@ import { schedule } from "@src/core/task";
8
9
  import { time } from "@src/core/time";
9
10
  import { target } from "@src/layout/target";
10
11
  import encode from "./encode";
11
- import { Mask } from "@clarity-types/layout";
12
12
 
13
13
  export let state: ChangeState[] = [];
14
14
 
@@ -22,13 +22,16 @@ export function observe(root: Node): void {
22
22
 
23
23
  function recompute(evt: UIEvent): void {
24
24
  recompute.dn = FunctionNames.ChangeRecompute;
25
- let element = target(evt) as HTMLInputElement;
25
+ const element = target(evt) as HTMLInputElement;
26
26
  if (element) {
27
- let value = element.value;
28
- let checksum = value && value.length >= Setting.WordLength && config.fraud && Mask.Exclude.indexOf(element.type) === -1 ? hash(value, Setting.ChecksumPrecision) : Constant.Empty;
27
+ const value = element.value;
28
+ const checksum =
29
+ value && value.length >= Setting.WordLength && config.fraud && Mask.Exclude.indexOf(element.type) === -1
30
+ ? hash(value, Setting.ChecksumPrecision)
31
+ : Constant.Empty;
29
32
  state.push({ time: time(evt), event: Event.Change, data: { target: target(evt), type: element.type, value, checksum } });
30
33
  schedule(encode.bind(this, Event.Change));
31
- }
34
+ }
32
35
  }
33
36
 
34
37
  export function reset(): void {
@@ -1,6 +1,6 @@
1
1
  import { BooleanFlag, Constant, Event, Setting } from "@clarity-types/data";
2
- import { BrowsingContext, ClickState, TextInfo } from "@clarity-types/interaction";
3
- import { Box } from "@clarity-types/layout";
2
+ import { BrowsingContext, type ClickState, type TextInfo } from "@clarity-types/interaction";
3
+ import type { Box } from "@clarity-types/layout";
4
4
  import { FunctionNames } from "@clarity-types/performance";
5
5
  import { bind } from "@src/core/event";
6
6
  import { schedule } from "@src/core/task";
@@ -23,41 +23,43 @@ export function observe(root: Node): void {
23
23
 
24
24
  function handler(event: Event, root: Node, evt: MouseEvent): void {
25
25
  handler.dn = FunctionNames.ClickHandler;
26
- let frame = iframe(root);
27
- let d = frame ? frame.contentDocument.documentElement : document.documentElement;
28
- let x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
29
- let y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
26
+ const frame = iframe(root);
27
+ const d = frame ? frame.contentDocument.documentElement : document.documentElement;
28
+ let x = "pageX" in evt ? Math.round(evt.pageX) : "clientX" in evt ? Math.round((evt as MouseEvent).clientX + d.scrollLeft) : null;
29
+ let y = "pageY" in evt ? Math.round(evt.pageY) : "clientY" in evt ? Math.round((evt as MouseEvent).clientY + d.scrollTop) : null;
30
30
  // In case of iframe, we adjust (x,y) to be relative to top parent's origin
31
31
  if (frame) {
32
- let distance = offset(frame);
32
+ const distance = offset(frame);
33
33
  x = x ? x + Math.round(distance.x) : x;
34
34
  y = y ? y + Math.round(distance.y) : y;
35
35
  }
36
36
 
37
- let t = target(evt);
37
+ const t = target(evt);
38
38
  // Find nearest anchor tag (<a/>) parent if current target node is part of one
39
39
  // If present, we use the returned link element to populate text and link properties below
40
- let a = link(t);
40
+ const a = link(t);
41
41
 
42
42
  // Get layout rectangle for the target element
43
- let l = layout(t as Element);
43
+ const l = layout(t as Element);
44
44
 
45
45
  // Reference: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
46
46
  // This property helps differentiate between a keyboard navigation vs. pointer click
47
47
  // In case of a keyboard navigation, we use center of target element as (x,y)
48
48
  if (evt.detail === 0 && l) {
49
- x = Math.round(l.x + (l.w / 2));
50
- y = Math.round(l.y + (l.h / 2));
49
+ x = Math.round(l.x + l.w / 2);
50
+ y = Math.round(l.y + l.h / 2);
51
51
  }
52
52
 
53
- let eX = l ? Math.max(Math.floor(((x - l.x) / l.w) * Setting.ClickPrecision), 0) : 0;
54
- let eY = l ? Math.max(Math.floor(((y - l.y) / l.h) * Setting.ClickPrecision), 0) : 0;
53
+ const eX = l ? Math.max(Math.floor(((x - l.x) / l.w) * Setting.ClickPrecision), 0) : 0;
54
+ const eY = l ? Math.max(Math.floor(((y - l.y) / l.h) * Setting.ClickPrecision), 0) : 0;
55
55
 
56
56
  // Check for null values before processing this event
57
57
  if (x !== null && y !== null) {
58
58
  const textInfo = text(t);
59
59
  state.push({
60
- time: time(evt), event, data: {
60
+ time: time(evt),
61
+ event,
62
+ data: {
61
63
  target: t,
62
64
  x,
63
65
  y,
@@ -71,16 +73,17 @@ function handler(event: Event, root: Node, evt: MouseEvent): void {
71
73
  hash: null,
72
74
  trust: evt.isTrusted ? BooleanFlag.True : BooleanFlag.False,
73
75
  isFullText: textInfo.isFullText,
74
- }
76
+ },
75
77
  });
76
78
  schedule(encode.bind(this, event));
77
79
  }
78
80
  }
79
81
 
80
- function link(node: Node): HTMLAnchorElement {
82
+ function link(inputNode: Node): HTMLAnchorElement {
83
+ let node = inputNode;
81
84
  while (node && node !== document) {
82
85
  if (node.nodeType === Node.ELEMENT_NODE) {
83
- let element = node as HTMLElement;
86
+ const element = node as HTMLElement;
84
87
  if (element.tagName === "A") {
85
88
  return element as HTMLAnchorElement;
86
89
  }
@@ -95,11 +98,11 @@ function text(element: Node): TextInfo {
95
98
  let isFullText = false;
96
99
  if (element) {
97
100
  // Grab text using "textContent" for most HTMLElements, however, use "value" for HTMLInputElements and "alt" for HTMLImageElement.
98
- let t = element.textContent || String((element as HTMLInputElement).value || '') || (element as HTMLImageElement).alt;
101
+ const t = element.textContent || String((element as HTMLInputElement).value || "") || (element as HTMLImageElement).alt;
99
102
  if (t) {
100
103
  // Replace multiple occurrence of space characters with a single white space
101
104
  // Also, trim any spaces at the beginning or at the end of string
102
- const trimmedText = t.replace(/\s+/g, Constant.Space).trim();
105
+ const trimmedText = t.replace(/\s+/g, Constant.Space).trim();
103
106
  // Finally, send only first few characters as specified by the Setting
104
107
  output = trimmedText.substring(0, Setting.ClickText);
105
108
  isFullText = output.length === trimmedText.length;
@@ -111,7 +114,7 @@ function text(element: Node): TextInfo {
111
114
 
112
115
  function reaction(element: Node): BooleanFlag {
113
116
  if (element.nodeType === Node.ELEMENT_NODE) {
114
- let tag = (element as HTMLElement).tagName.toLowerCase();
117
+ const tag = (element as HTMLElement).tagName.toLowerCase();
115
118
  if (UserInputTags.indexOf(tag) >= 0) {
116
119
  return BooleanFlag.False;
117
120
  }
@@ -121,10 +124,10 @@ function reaction(element: Node): BooleanFlag {
121
124
 
122
125
  function layout(element: Element): Box {
123
126
  let box: Box = null;
124
- let de = document.documentElement;
127
+ const de = document.documentElement;
125
128
  if (typeof element.getBoundingClientRect === "function") {
126
129
  // getBoundingClientRect returns rectangle relative positioning to viewport
127
- let rect = element.getBoundingClientRect();
130
+ const rect = element.getBoundingClientRect();
128
131
 
129
132
  if (rect && rect.width > 0 && rect.height > 0) {
130
133
  // Add viewport's scroll position to rectangle to get position relative to document origin
@@ -135,7 +138,7 @@ function layout(element: Element): Box {
135
138
  x: Math.floor(rect.left + ("pageXOffset" in window ? window.pageXOffset : de.scrollLeft)),
136
139
  y: Math.floor(rect.top + ("pageYOffset" in window ? window.pageYOffset : de.scrollTop)),
137
140
  w: Math.floor(rect.width),
138
- h: Math.floor(rect.height)
141
+ h: Math.floor(rect.height),
139
142
  };
140
143
  }
141
144
  }
@@ -143,11 +146,14 @@ function layout(element: Element): Box {
143
146
  }
144
147
 
145
148
  function context(a: HTMLAnchorElement): BrowsingContext {
146
- if (a && a.hasAttribute(Constant.Target)) {
149
+ if (a?.hasAttribute(Constant.Target)) {
147
150
  switch (a.getAttribute(Constant.Target)) {
148
- case Constant.Blank: return BrowsingContext.Blank;
149
- case Constant.Parent: return BrowsingContext.Parent;
150
- case Constant.Top: return BrowsingContext.Top;
151
+ case Constant.Blank:
152
+ return BrowsingContext.Blank;
153
+ case Constant.Parent:
154
+ return BrowsingContext.Parent;
155
+ case Constant.Top:
156
+ return BrowsingContext.Top;
151
157
  }
152
158
  }
153
159
  return BrowsingContext.Self;
@@ -1,11 +1,11 @@
1
1
  import { Event } from "@clarity-types/data";
2
- import { Clipboard, ClipboardState } from "@clarity-types/interaction";
2
+ import { Clipboard, type ClipboardState } 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: ClipboardState[] = [];
11
11