@arthurreira/analytics 0.21.0 → 0.22.0
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.
- package/dist/client.js +34 -14
- package/dist/index.js +28 -12
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -41,6 +41,12 @@ function getConnectionType() {
|
|
|
41
41
|
const nav = navigator;
|
|
42
42
|
return nav.connection?.effectiveType ?? null;
|
|
43
43
|
}
|
|
44
|
+
function resolveInteractiveTarget(el) {
|
|
45
|
+
const interactive = el.closest(
|
|
46
|
+
'a, button, [role="button"], input, select, textarea, label, summary'
|
|
47
|
+
);
|
|
48
|
+
return interactive ?? el;
|
|
49
|
+
}
|
|
44
50
|
function resolveElementHref(element) {
|
|
45
51
|
if (element.tagName.toLowerCase() === "a") {
|
|
46
52
|
return element.href || null;
|
|
@@ -48,6 +54,15 @@ function resolveElementHref(element) {
|
|
|
48
54
|
const anchor = element.closest("a");
|
|
49
55
|
return anchor ? anchor.href || null : null;
|
|
50
56
|
}
|
|
57
|
+
function safeClassName(el) {
|
|
58
|
+
const cn = el.className;
|
|
59
|
+
return typeof cn === "string" ? cn || null : null;
|
|
60
|
+
}
|
|
61
|
+
function cleanLabel(raw, maxLen) {
|
|
62
|
+
if (!raw) return null;
|
|
63
|
+
const cleaned = raw.replace(/\s+/g, " ").trim().slice(0, maxLen);
|
|
64
|
+
return cleaned || null;
|
|
65
|
+
}
|
|
51
66
|
function isExternalHref(href) {
|
|
52
67
|
if (!href) return null;
|
|
53
68
|
if (typeof window === "undefined") return null;
|
|
@@ -135,23 +150,24 @@ async function trackPageview(apiUrl, apiKey, sessionId, path, routeName) {
|
|
|
135
150
|
});
|
|
136
151
|
}
|
|
137
152
|
async function trackClick(apiUrl, apiKey, sessionId, path, e, element) {
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
const
|
|
153
|
+
const target = resolveInteractiveTarget(element);
|
|
154
|
+
const href = resolveElementHref(target);
|
|
155
|
+
const ariaLabel = target.getAttribute("aria-label");
|
|
156
|
+
const rawText = target.innerText ?? target.textContent ?? void 0;
|
|
157
|
+
const eventName = cleanLabel(ariaLabel, 60) ?? cleanLabel(rawText, 60) ?? target.tagName.toLowerCase();
|
|
142
158
|
await sendEvent(apiUrl, apiKey, {
|
|
143
159
|
...BASE_FIELDS(sessionId, "click", path, eventName, "interaction"),
|
|
144
160
|
x_position: e.clientX,
|
|
145
161
|
y_position: e.clientY,
|
|
146
|
-
element_id:
|
|
147
|
-
element_class:
|
|
148
|
-
element_text:
|
|
149
|
-
tag_name:
|
|
162
|
+
element_id: target.id || null,
|
|
163
|
+
element_class: safeClassName(target),
|
|
164
|
+
element_text: cleanLabel(rawText, 100),
|
|
165
|
+
tag_name: target.tagName.toLowerCase(),
|
|
150
166
|
element_href: href,
|
|
151
|
-
element_role:
|
|
152
|
-
element_aria_label:
|
|
153
|
-
element_type:
|
|
154
|
-
element_name:
|
|
167
|
+
element_role: target.getAttribute("role") || null,
|
|
168
|
+
element_aria_label: ariaLabel || null,
|
|
169
|
+
element_type: target.type || null,
|
|
170
|
+
element_name: target.name || null,
|
|
155
171
|
is_external_link: isExternalHref(href),
|
|
156
172
|
modifier_keys: {
|
|
157
173
|
alt: e.altKey,
|
|
@@ -542,6 +558,10 @@ function Analytics({ apiKey, apiUrl, wsUrl, routeName }) {
|
|
|
542
558
|
const { trackPageview: trackPageview2, trackClick: trackClick2, trackScroll: trackScroll2, trackCopy: trackCopy2, trackException: trackException2, trackWebVital: trackWebVital2 } = useAnalytics(apiUrl, apiKey, pathname, wsUrl, routeName);
|
|
543
559
|
const lastTracked = useRef2(null);
|
|
544
560
|
const lastScrollDepth = useRef2(0);
|
|
561
|
+
const trackWebVitalRef = useRef2(trackWebVital2);
|
|
562
|
+
useEffect2(() => {
|
|
563
|
+
trackWebVitalRef.current = trackWebVital2;
|
|
564
|
+
});
|
|
545
565
|
useEffect2(() => {
|
|
546
566
|
if (lastTracked.current === pathname) return;
|
|
547
567
|
lastTracked.current = pathname;
|
|
@@ -551,14 +571,14 @@ function Analytics({ apiKey, apiUrl, wsUrl, routeName }) {
|
|
|
551
571
|
useEffect2(() => {
|
|
552
572
|
if (typeof window === "undefined") return;
|
|
553
573
|
const report = (name, value, rating) => {
|
|
554
|
-
|
|
574
|
+
trackWebVitalRef.current({ name, value, rating });
|
|
555
575
|
};
|
|
556
576
|
onLCP((m) => report("lcp_ms", Math.round(m.value), m.rating));
|
|
557
577
|
onCLS((m) => report("cls_score", m.value, m.rating));
|
|
558
578
|
onINP((m) => report("inp_ms", Math.round(m.value), m.rating));
|
|
559
579
|
onTTFB((m) => report("ttfb_ms", Math.round(m.value), m.rating));
|
|
560
580
|
onFCP((m) => report("fcp_ms", Math.round(m.value), m.rating));
|
|
561
|
-
}, [
|
|
581
|
+
}, []);
|
|
562
582
|
useEffect2(() => {
|
|
563
583
|
if (typeof window === "undefined") return;
|
|
564
584
|
const handler = (e) => trackClick2(e, e.target);
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,12 @@ function getConnectionType() {
|
|
|
42
42
|
const nav = navigator;
|
|
43
43
|
return nav.connection?.effectiveType ?? null;
|
|
44
44
|
}
|
|
45
|
+
function resolveInteractiveTarget(el) {
|
|
46
|
+
const interactive = el.closest(
|
|
47
|
+
'a, button, [role="button"], input, select, textarea, label, summary'
|
|
48
|
+
);
|
|
49
|
+
return interactive ?? el;
|
|
50
|
+
}
|
|
45
51
|
function resolveElementHref(element) {
|
|
46
52
|
if (element.tagName.toLowerCase() === "a") {
|
|
47
53
|
return element.href || null;
|
|
@@ -49,6 +55,15 @@ function resolveElementHref(element) {
|
|
|
49
55
|
const anchor = element.closest("a");
|
|
50
56
|
return anchor ? anchor.href || null : null;
|
|
51
57
|
}
|
|
58
|
+
function safeClassName(el) {
|
|
59
|
+
const cn = el.className;
|
|
60
|
+
return typeof cn === "string" ? cn || null : null;
|
|
61
|
+
}
|
|
62
|
+
function cleanLabel(raw, maxLen) {
|
|
63
|
+
if (!raw) return null;
|
|
64
|
+
const cleaned = raw.replace(/\s+/g, " ").trim().slice(0, maxLen);
|
|
65
|
+
return cleaned || null;
|
|
66
|
+
}
|
|
52
67
|
function isExternalHref(href) {
|
|
53
68
|
if (!href) return null;
|
|
54
69
|
if (typeof window === "undefined") return null;
|
|
@@ -136,23 +151,24 @@ async function trackPageview(apiUrl, apiKey, sessionId, path, routeName) {
|
|
|
136
151
|
});
|
|
137
152
|
}
|
|
138
153
|
async function trackClick(apiUrl, apiKey, sessionId, path, e, element) {
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
154
|
+
const target = resolveInteractiveTarget(element);
|
|
155
|
+
const href = resolveElementHref(target);
|
|
156
|
+
const ariaLabel = target.getAttribute("aria-label");
|
|
157
|
+
const rawText = target.innerText ?? target.textContent ?? void 0;
|
|
158
|
+
const eventName = cleanLabel(ariaLabel, 60) ?? cleanLabel(rawText, 60) ?? target.tagName.toLowerCase();
|
|
143
159
|
await sendEvent(apiUrl, apiKey, {
|
|
144
160
|
...BASE_FIELDS(sessionId, "click", path, eventName, "interaction"),
|
|
145
161
|
x_position: e.clientX,
|
|
146
162
|
y_position: e.clientY,
|
|
147
|
-
element_id:
|
|
148
|
-
element_class:
|
|
149
|
-
element_text:
|
|
150
|
-
tag_name:
|
|
163
|
+
element_id: target.id || null,
|
|
164
|
+
element_class: safeClassName(target),
|
|
165
|
+
element_text: cleanLabel(rawText, 100),
|
|
166
|
+
tag_name: target.tagName.toLowerCase(),
|
|
151
167
|
element_href: href,
|
|
152
|
-
element_role:
|
|
153
|
-
element_aria_label:
|
|
154
|
-
element_type:
|
|
155
|
-
element_name:
|
|
168
|
+
element_role: target.getAttribute("role") || null,
|
|
169
|
+
element_aria_label: ariaLabel || null,
|
|
170
|
+
element_type: target.type || null,
|
|
171
|
+
element_name: target.name || null,
|
|
156
172
|
is_external_link: isExternalHref(href),
|
|
157
173
|
modifier_keys: {
|
|
158
174
|
alt: e.altKey,
|