ninetwo-user-tracking 1.0.11 → 1.0.13
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/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +78 -12
- package/dist/index.mjs +78 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -14,7 +14,16 @@ interface TrackViewProps {
|
|
|
14
14
|
label?: string;
|
|
15
15
|
threshold?: number;
|
|
16
16
|
readTime?: number;
|
|
17
|
+
debug?: boolean;
|
|
17
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* TrackView
|
|
21
|
+
* - Dispara {eventName, type: 'view'} quando o elemento entra na viewport (threshold)
|
|
22
|
+
* - Dispara {eventName+'_read_confirmation', type: 'read_confirmation'} se o elemento permanecer visível por `readTime`
|
|
23
|
+
*
|
|
24
|
+
* Observação: evita usar `display: 'contents'` no wrapper porque em alguns cenários o IntersectionObserver não detecta.
|
|
25
|
+
* Se o wrapper realmente usa display: contents, tentamos observar o primeiro filho disponível.
|
|
26
|
+
*/
|
|
18
27
|
declare const TrackView: React.FC<TrackViewProps>;
|
|
19
28
|
|
|
20
29
|
declare const useAutoTrackClick: (enabled?: boolean) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,16 @@ interface TrackViewProps {
|
|
|
14
14
|
label?: string;
|
|
15
15
|
threshold?: number;
|
|
16
16
|
readTime?: number;
|
|
17
|
+
debug?: boolean;
|
|
17
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* TrackView
|
|
21
|
+
* - Dispara {eventName, type: 'view'} quando o elemento entra na viewport (threshold)
|
|
22
|
+
* - Dispara {eventName+'_read_confirmation', type: 'read_confirmation'} se o elemento permanecer visível por `readTime`
|
|
23
|
+
*
|
|
24
|
+
* Observação: evita usar `display: 'contents'` no wrapper porque em alguns cenários o IntersectionObserver não detecta.
|
|
25
|
+
* Se o wrapper realmente usa display: contents, tentamos observar o primeiro filho disponível.
|
|
26
|
+
*/
|
|
18
27
|
declare const TrackView: React.FC<TrackViewProps>;
|
|
19
28
|
|
|
20
29
|
declare const useAutoTrackClick: (enabled?: boolean) => void;
|
package/dist/index.js
CHANGED
|
@@ -219,21 +219,53 @@ var TrackView = ({
|
|
|
219
219
|
category,
|
|
220
220
|
label,
|
|
221
221
|
threshold = 0.5,
|
|
222
|
-
readTime = 5e3
|
|
222
|
+
readTime = 5e3,
|
|
223
|
+
debug = false
|
|
223
224
|
}) => {
|
|
224
225
|
const ref = (0, import_react4.useRef)(null);
|
|
225
226
|
const timerRef = (0, import_react4.useRef)(null);
|
|
226
227
|
const [hasTriggeredView, setHasTriggeredView] = (0, import_react4.useState)(false);
|
|
227
228
|
const [hasTriggeredRead, setHasTriggeredRead] = (0, import_react4.useState)(false);
|
|
228
229
|
(0, import_react4.useEffect)(() => {
|
|
229
|
-
|
|
230
|
+
const rootEl = ref.current;
|
|
231
|
+
if (!rootEl)
|
|
230
232
|
return;
|
|
231
233
|
if (hasTriggeredView && hasTriggeredRead)
|
|
232
234
|
return;
|
|
235
|
+
if (typeof window !== "undefined" && !("IntersectionObserver" in window)) {
|
|
236
|
+
if (!hasTriggeredView) {
|
|
237
|
+
pushToDataLayer({
|
|
238
|
+
event: eventName,
|
|
239
|
+
category,
|
|
240
|
+
label,
|
|
241
|
+
type: "view"
|
|
242
|
+
});
|
|
243
|
+
setHasTriggeredView(true);
|
|
244
|
+
}
|
|
245
|
+
if (!hasTriggeredRead) {
|
|
246
|
+
timerRef.current = window.setTimeout(() => {
|
|
247
|
+
pushToDataLayer({
|
|
248
|
+
event: `read_confirmation`,
|
|
249
|
+
category,
|
|
250
|
+
label,
|
|
251
|
+
type: "read_confirmation"
|
|
252
|
+
});
|
|
253
|
+
setHasTriggeredRead(true);
|
|
254
|
+
}, readTime);
|
|
255
|
+
}
|
|
256
|
+
return () => {
|
|
257
|
+
if (timerRef.current) {
|
|
258
|
+
window.clearTimeout(timerRef.current);
|
|
259
|
+
timerRef.current = null;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
233
263
|
const observer = new IntersectionObserver(
|
|
234
264
|
([entry]) => {
|
|
235
265
|
if (entry.isIntersecting) {
|
|
236
266
|
if (!hasTriggeredView) {
|
|
267
|
+
if (debug)
|
|
268
|
+
console.log("[TrackView] view ->", eventName, { category, label });
|
|
237
269
|
pushToDataLayer({
|
|
238
270
|
event: eventName,
|
|
239
271
|
category,
|
|
@@ -242,36 +274,70 @@ var TrackView = ({
|
|
|
242
274
|
});
|
|
243
275
|
setHasTriggeredView(true);
|
|
244
276
|
}
|
|
245
|
-
if (!hasTriggeredRead &&
|
|
246
|
-
timerRef.current = setTimeout(() => {
|
|
277
|
+
if (!hasTriggeredRead && timerRef.current === null) {
|
|
278
|
+
timerRef.current = window.setTimeout(() => {
|
|
279
|
+
if (debug)
|
|
280
|
+
console.log("[TrackView] read_confirmation ->", eventName, { category, label });
|
|
247
281
|
pushToDataLayer({
|
|
248
282
|
event: `${eventName}_read_confirmation`,
|
|
249
|
-
// Sufixo solicitado
|
|
250
283
|
category,
|
|
251
284
|
label,
|
|
252
285
|
type: "read_confirmation"
|
|
253
|
-
// Tipo diferenciado
|
|
254
286
|
});
|
|
255
287
|
setHasTriggeredRead(true);
|
|
288
|
+
timerRef.current = null;
|
|
256
289
|
}, readTime);
|
|
257
290
|
}
|
|
258
291
|
} else {
|
|
259
292
|
if (timerRef.current) {
|
|
260
|
-
|
|
293
|
+
if (debug)
|
|
294
|
+
console.log("[TrackView] saiu antes do readTime, cancelando timer ->", eventName);
|
|
295
|
+
window.clearTimeout(timerRef.current);
|
|
261
296
|
timerRef.current = null;
|
|
262
297
|
}
|
|
263
298
|
}
|
|
264
299
|
},
|
|
265
300
|
{ threshold }
|
|
266
301
|
);
|
|
267
|
-
|
|
302
|
+
let elementToObserve = rootEl;
|
|
303
|
+
try {
|
|
304
|
+
const cs = window.getComputedStyle(rootEl);
|
|
305
|
+
if (cs && cs.display === "contents") {
|
|
306
|
+
const firstChild = rootEl.firstElementChild;
|
|
307
|
+
if (firstChild) {
|
|
308
|
+
elementToObserve = firstChild;
|
|
309
|
+
if (debug)
|
|
310
|
+
console.log("[TrackView] wrapper display:contents \u2014 observando primeiro filho", firstChild);
|
|
311
|
+
} else {
|
|
312
|
+
if (debug)
|
|
313
|
+
console.log("[TrackView] wrapper display:contents mas sem filhos \u2014 observando wrapper", rootEl);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (e) {
|
|
317
|
+
if (debug)
|
|
318
|
+
console.warn("[TrackView] erro ao checar computedStyle", e);
|
|
319
|
+
}
|
|
320
|
+
if (elementToObserve) {
|
|
321
|
+
observer.observe(elementToObserve);
|
|
322
|
+
}
|
|
268
323
|
return () => {
|
|
269
324
|
observer.disconnect();
|
|
270
|
-
if (timerRef.current)
|
|
271
|
-
clearTimeout(timerRef.current);
|
|
325
|
+
if (timerRef.current) {
|
|
326
|
+
window.clearTimeout(timerRef.current);
|
|
327
|
+
timerRef.current = null;
|
|
328
|
+
}
|
|
272
329
|
};
|
|
273
|
-
}, [
|
|
274
|
-
|
|
330
|
+
}, [
|
|
331
|
+
hasTriggeredView,
|
|
332
|
+
hasTriggeredRead,
|
|
333
|
+
eventName,
|
|
334
|
+
category,
|
|
335
|
+
label,
|
|
336
|
+
threshold,
|
|
337
|
+
readTime,
|
|
338
|
+
debug
|
|
339
|
+
]);
|
|
340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, style: { display: "block" }, children });
|
|
275
341
|
};
|
|
276
342
|
// Annotate the CommonJS export names for ESM import in node:
|
|
277
343
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -191,21 +191,53 @@ var TrackView = ({
|
|
|
191
191
|
category,
|
|
192
192
|
label,
|
|
193
193
|
threshold = 0.5,
|
|
194
|
-
readTime = 5e3
|
|
194
|
+
readTime = 5e3,
|
|
195
|
+
debug = false
|
|
195
196
|
}) => {
|
|
196
197
|
const ref = useRef(null);
|
|
197
198
|
const timerRef = useRef(null);
|
|
198
199
|
const [hasTriggeredView, setHasTriggeredView] = useState(false);
|
|
199
200
|
const [hasTriggeredRead, setHasTriggeredRead] = useState(false);
|
|
200
201
|
useEffect4(() => {
|
|
201
|
-
|
|
202
|
+
const rootEl = ref.current;
|
|
203
|
+
if (!rootEl)
|
|
202
204
|
return;
|
|
203
205
|
if (hasTriggeredView && hasTriggeredRead)
|
|
204
206
|
return;
|
|
207
|
+
if (typeof window !== "undefined" && !("IntersectionObserver" in window)) {
|
|
208
|
+
if (!hasTriggeredView) {
|
|
209
|
+
pushToDataLayer({
|
|
210
|
+
event: eventName,
|
|
211
|
+
category,
|
|
212
|
+
label,
|
|
213
|
+
type: "view"
|
|
214
|
+
});
|
|
215
|
+
setHasTriggeredView(true);
|
|
216
|
+
}
|
|
217
|
+
if (!hasTriggeredRead) {
|
|
218
|
+
timerRef.current = window.setTimeout(() => {
|
|
219
|
+
pushToDataLayer({
|
|
220
|
+
event: `read_confirmation`,
|
|
221
|
+
category,
|
|
222
|
+
label,
|
|
223
|
+
type: "read_confirmation"
|
|
224
|
+
});
|
|
225
|
+
setHasTriggeredRead(true);
|
|
226
|
+
}, readTime);
|
|
227
|
+
}
|
|
228
|
+
return () => {
|
|
229
|
+
if (timerRef.current) {
|
|
230
|
+
window.clearTimeout(timerRef.current);
|
|
231
|
+
timerRef.current = null;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
205
235
|
const observer = new IntersectionObserver(
|
|
206
236
|
([entry]) => {
|
|
207
237
|
if (entry.isIntersecting) {
|
|
208
238
|
if (!hasTriggeredView) {
|
|
239
|
+
if (debug)
|
|
240
|
+
console.log("[TrackView] view ->", eventName, { category, label });
|
|
209
241
|
pushToDataLayer({
|
|
210
242
|
event: eventName,
|
|
211
243
|
category,
|
|
@@ -214,36 +246,70 @@ var TrackView = ({
|
|
|
214
246
|
});
|
|
215
247
|
setHasTriggeredView(true);
|
|
216
248
|
}
|
|
217
|
-
if (!hasTriggeredRead &&
|
|
218
|
-
timerRef.current = setTimeout(() => {
|
|
249
|
+
if (!hasTriggeredRead && timerRef.current === null) {
|
|
250
|
+
timerRef.current = window.setTimeout(() => {
|
|
251
|
+
if (debug)
|
|
252
|
+
console.log("[TrackView] read_confirmation ->", eventName, { category, label });
|
|
219
253
|
pushToDataLayer({
|
|
220
254
|
event: `${eventName}_read_confirmation`,
|
|
221
|
-
// Sufixo solicitado
|
|
222
255
|
category,
|
|
223
256
|
label,
|
|
224
257
|
type: "read_confirmation"
|
|
225
|
-
// Tipo diferenciado
|
|
226
258
|
});
|
|
227
259
|
setHasTriggeredRead(true);
|
|
260
|
+
timerRef.current = null;
|
|
228
261
|
}, readTime);
|
|
229
262
|
}
|
|
230
263
|
} else {
|
|
231
264
|
if (timerRef.current) {
|
|
232
|
-
|
|
265
|
+
if (debug)
|
|
266
|
+
console.log("[TrackView] saiu antes do readTime, cancelando timer ->", eventName);
|
|
267
|
+
window.clearTimeout(timerRef.current);
|
|
233
268
|
timerRef.current = null;
|
|
234
269
|
}
|
|
235
270
|
}
|
|
236
271
|
},
|
|
237
272
|
{ threshold }
|
|
238
273
|
);
|
|
239
|
-
|
|
274
|
+
let elementToObserve = rootEl;
|
|
275
|
+
try {
|
|
276
|
+
const cs = window.getComputedStyle(rootEl);
|
|
277
|
+
if (cs && cs.display === "contents") {
|
|
278
|
+
const firstChild = rootEl.firstElementChild;
|
|
279
|
+
if (firstChild) {
|
|
280
|
+
elementToObserve = firstChild;
|
|
281
|
+
if (debug)
|
|
282
|
+
console.log("[TrackView] wrapper display:contents \u2014 observando primeiro filho", firstChild);
|
|
283
|
+
} else {
|
|
284
|
+
if (debug)
|
|
285
|
+
console.log("[TrackView] wrapper display:contents mas sem filhos \u2014 observando wrapper", rootEl);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (e) {
|
|
289
|
+
if (debug)
|
|
290
|
+
console.warn("[TrackView] erro ao checar computedStyle", e);
|
|
291
|
+
}
|
|
292
|
+
if (elementToObserve) {
|
|
293
|
+
observer.observe(elementToObserve);
|
|
294
|
+
}
|
|
240
295
|
return () => {
|
|
241
296
|
observer.disconnect();
|
|
242
|
-
if (timerRef.current)
|
|
243
|
-
clearTimeout(timerRef.current);
|
|
297
|
+
if (timerRef.current) {
|
|
298
|
+
window.clearTimeout(timerRef.current);
|
|
299
|
+
timerRef.current = null;
|
|
300
|
+
}
|
|
244
301
|
};
|
|
245
|
-
}, [
|
|
246
|
-
|
|
302
|
+
}, [
|
|
303
|
+
hasTriggeredView,
|
|
304
|
+
hasTriggeredRead,
|
|
305
|
+
eventName,
|
|
306
|
+
category,
|
|
307
|
+
label,
|
|
308
|
+
threshold,
|
|
309
|
+
readTime,
|
|
310
|
+
debug
|
|
311
|
+
]);
|
|
312
|
+
return /* @__PURE__ */ jsx2("div", { ref, style: { display: "block" }, children });
|
|
247
313
|
};
|
|
248
314
|
export {
|
|
249
315
|
TrackView,
|