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 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
- if (!ref.current)
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 && !timerRef.current) {
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
- clearTimeout(timerRef.current);
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
- observer.observe(ref.current);
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
- }, [hasTriggeredView, hasTriggeredRead, eventName, category, label, threshold, readTime]);
274
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, style: { display: "contents" }, children });
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
- if (!ref.current)
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 && !timerRef.current) {
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
- clearTimeout(timerRef.current);
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
- observer.observe(ref.current);
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
- }, [hasTriggeredView, hasTriggeredRead, eventName, category, label, threshold, readTime]);
246
- return /* @__PURE__ */ jsx2("div", { ref, style: { display: "contents" }, children });
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ninetwo-user-tracking",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "User tracking abstraction for React/Nextjs with GTM",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",