@zaplier/sdk 1.7.4 โ 1.7.6
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.cjs +264 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +264 -55
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +264 -55
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/auto-tracker.d.ts +19 -1
- package/dist/src/modules/auto-tracker.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -19566,58 +19566,19 @@ class AutoTracker {
|
|
|
19566
19566
|
console.log("[๐ AutoTracker] Click delegation handler added");
|
|
19567
19567
|
}
|
|
19568
19568
|
}
|
|
19569
|
-
//
|
|
19569
|
+
// MODERN APPROACH: IntersectionObserver + Scroll Fallback (2025 Best Practice)
|
|
19570
19570
|
if (this.config.trackScrolls) {
|
|
19571
|
-
const scrollHandler = this.createEnhancedScrollHandler();
|
|
19572
|
-
this.delegationHandlers.set('scroll', scrollHandler);
|
|
19573
|
-
// Always use document for scroll events (window doesn't work with removeEventListener)
|
|
19574
|
-
document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
|
|
19575
19571
|
if (this.config.debug) {
|
|
19576
|
-
console.log("[
|
|
19577
|
-
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
console.log("[๐ AutoTracker] ๐งช MANUAL SCROLL TEST - Handler should trigger");
|
|
19587
|
-
scrollHandler(new Event('scroll'));
|
|
19588
|
-
};
|
|
19589
|
-
// Expose test function globally for manual testing
|
|
19590
|
-
if (typeof window !== 'undefined') {
|
|
19591
|
-
window.testScrollHandler = testHandler;
|
|
19592
|
-
console.log("[๐ AutoTracker] ๐งช Manual test available: window.testScrollHandler()");
|
|
19593
|
-
}
|
|
19594
|
-
// Immediate test of element detection
|
|
19595
|
-
setTimeout(() => {
|
|
19596
|
-
const scrollElements = this.getCachedScrollElements();
|
|
19597
|
-
console.log(`[๐ AutoTracker] ๐ Initial scroll elements check: ${scrollElements.length} found`);
|
|
19598
|
-
if (scrollElements.length > 0) {
|
|
19599
|
-
Array.from(scrollElements).forEach((element, index) => {
|
|
19600
|
-
console.log(`[๐ AutoTracker] Element ${index + 1}:`, {
|
|
19601
|
-
id: element.id || 'no-id',
|
|
19602
|
-
trackEvent: element.getAttribute('data-track-scroll'),
|
|
19603
|
-
threshold: element.getAttribute('data-scroll-threshold') || '0.5',
|
|
19604
|
-
tagName: element.tagName,
|
|
19605
|
-
rect: element.getBoundingClientRect(),
|
|
19606
|
-
isVisible: element.getBoundingClientRect().height > 0
|
|
19607
|
-
});
|
|
19608
|
-
});
|
|
19609
|
-
}
|
|
19610
|
-
// Also test manually trigger one element
|
|
19611
|
-
if (scrollElements.length > 0) {
|
|
19612
|
-
const firstElement = scrollElements[0];
|
|
19613
|
-
if (firstElement) {
|
|
19614
|
-
console.log(`[๐ AutoTracker] ๐งช Testing manual trigger on first element:`, firstElement.getAttribute('data-track-scroll'));
|
|
19615
|
-
setTimeout(() => {
|
|
19616
|
-
console.log("[๐ AutoTracker] ๐งช Manual trigger test executed");
|
|
19617
|
-
}, 500);
|
|
19618
|
-
}
|
|
19619
|
-
}
|
|
19620
|
-
}, 100);
|
|
19572
|
+
console.log("[๐ AutoTracker] Setting up modern scroll tracking with IntersectionObserver");
|
|
19573
|
+
}
|
|
19574
|
+
// PRIMARY: Modern IntersectionObserver approach (recommended 2025)
|
|
19575
|
+
this.setupIntersectionObserverScrollTracking();
|
|
19576
|
+
// FALLBACK: Traditional scroll listener for edge cases
|
|
19577
|
+
this.setupFallbackScrollListener();
|
|
19578
|
+
if (this.config.debug) {
|
|
19579
|
+
console.log("[๐ AutoTracker] โ
Modern scroll tracking setup complete:");
|
|
19580
|
+
console.log("[๐ AutoTracker] ๐ Primary: IntersectionObserver (modern, performant)");
|
|
19581
|
+
console.log("[๐ AutoTracker] ๐ Fallback: Traditional scroll listener (compatibility)");
|
|
19621
19582
|
}
|
|
19622
19583
|
}
|
|
19623
19584
|
// Setup debounced mutation observer for dynamic content
|
|
@@ -19751,7 +19712,209 @@ class AutoTracker {
|
|
|
19751
19712
|
return null;
|
|
19752
19713
|
}
|
|
19753
19714
|
/**
|
|
19754
|
-
*
|
|
19715
|
+
* Modern IntersectionObserver-based scroll tracking (2025 Best Practice)
|
|
19716
|
+
* More performant and reliable than traditional scroll listeners
|
|
19717
|
+
*/
|
|
19718
|
+
setupIntersectionObserverScrollTracking() {
|
|
19719
|
+
if (typeof window === 'undefined' || !('IntersectionObserver' in window)) {
|
|
19720
|
+
if (this.config.debug) {
|
|
19721
|
+
console.log("[โ ๏ธ AutoTracker] IntersectionObserver not available, using fallback only");
|
|
19722
|
+
}
|
|
19723
|
+
return;
|
|
19724
|
+
}
|
|
19725
|
+
// Get all scroll elements
|
|
19726
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19727
|
+
if (scrollElements.length === 0) {
|
|
19728
|
+
if (this.config.debug) {
|
|
19729
|
+
console.log("[๐ AutoTracker] No scroll elements found for IntersectionObserver");
|
|
19730
|
+
}
|
|
19731
|
+
return;
|
|
19732
|
+
}
|
|
19733
|
+
// Create observer with multiple thresholds for precise tracking
|
|
19734
|
+
const observerOptions = {
|
|
19735
|
+
root: null, // Use viewport as root
|
|
19736
|
+
rootMargin: '0px',
|
|
19737
|
+
threshold: [0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0] // Multiple thresholds for accuracy
|
|
19738
|
+
};
|
|
19739
|
+
const observer = new IntersectionObserver((entries) => {
|
|
19740
|
+
entries.forEach((entry) => {
|
|
19741
|
+
const element = entry.target;
|
|
19742
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
19743
|
+
const customThreshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19744
|
+
const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19745
|
+
if (!eventName || hasTriggered)
|
|
19746
|
+
return;
|
|
19747
|
+
const visibilityRatio = entry.intersectionRatio;
|
|
19748
|
+
if (this.config.debug) {
|
|
19749
|
+
console.log(`[๐ IntersectionObserver] Element "${eventName}":`, {
|
|
19750
|
+
elementId: element.id || 'no-id',
|
|
19751
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19752
|
+
threshold: customThreshold,
|
|
19753
|
+
isIntersecting: entry.isIntersecting,
|
|
19754
|
+
shouldTrigger: visibilityRatio >= customThreshold
|
|
19755
|
+
});
|
|
19756
|
+
}
|
|
19757
|
+
// Trigger event when visibility threshold is met
|
|
19758
|
+
if (visibilityRatio >= customThreshold) {
|
|
19759
|
+
element.setAttribute('data-scroll-triggered', 'true');
|
|
19760
|
+
const metadata = this.extractMetadata(element);
|
|
19761
|
+
this.trackEvent(eventName, {
|
|
19762
|
+
type: 'scroll',
|
|
19763
|
+
method: 'IntersectionObserver',
|
|
19764
|
+
element: element.tagName.toLowerCase(),
|
|
19765
|
+
threshold: customThreshold,
|
|
19766
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19767
|
+
enhanced: true,
|
|
19768
|
+
modern: true,
|
|
19769
|
+
...metadata,
|
|
19770
|
+
});
|
|
19771
|
+
if (this.config.debug) {
|
|
19772
|
+
console.log(`[๐ฏ IntersectionObserver] Event "${eventName}" triggered! (${Math.round(visibilityRatio * 100)}% visible)`);
|
|
19773
|
+
}
|
|
19774
|
+
// Unobserve after triggering (one-time trigger)
|
|
19775
|
+
observer.unobserve(element);
|
|
19776
|
+
}
|
|
19777
|
+
});
|
|
19778
|
+
}, observerOptions);
|
|
19779
|
+
// Observe all scroll elements
|
|
19780
|
+
scrollElements.forEach((element) => {
|
|
19781
|
+
observer.observe(element);
|
|
19782
|
+
if (this.config.debug) {
|
|
19783
|
+
console.log(`[๐๏ธ IntersectionObserver] Now observing: ${element.getAttribute('data-track-scroll')} (${element.id || 'no-id'})`);
|
|
19784
|
+
}
|
|
19785
|
+
});
|
|
19786
|
+
// Store observer for cleanup
|
|
19787
|
+
this.intersectionObserver = observer;
|
|
19788
|
+
if (this.config.debug) {
|
|
19789
|
+
console.log(`[โ
IntersectionObserver] Setup complete - observing ${scrollElements.length} elements`);
|
|
19790
|
+
}
|
|
19791
|
+
}
|
|
19792
|
+
/**
|
|
19793
|
+
* Fallback scroll listener for compatibility (React/Next.js issues)
|
|
19794
|
+
*/
|
|
19795
|
+
setupFallbackScrollListener() {
|
|
19796
|
+
if (typeof window === 'undefined')
|
|
19797
|
+
return;
|
|
19798
|
+
const fallbackHandler = this.createThrottledScrollHandler();
|
|
19799
|
+
// Try multiple attachment strategies for React/Next.js compatibility
|
|
19800
|
+
const attachStrategies = [
|
|
19801
|
+
() => window.addEventListener('scroll', fallbackHandler, { passive: true }),
|
|
19802
|
+
() => document.addEventListener('scroll', fallbackHandler, { passive: true }),
|
|
19803
|
+
() => window.addEventListener('scroll', fallbackHandler, { passive: true, capture: true }),
|
|
19804
|
+
() => {
|
|
19805
|
+
// Delayed attachment for React hydration
|
|
19806
|
+
setTimeout(() => {
|
|
19807
|
+
window.addEventListener('scroll', fallbackHandler, { passive: true });
|
|
19808
|
+
}, 100);
|
|
19809
|
+
},
|
|
19810
|
+
() => {
|
|
19811
|
+
// Document ready state check
|
|
19812
|
+
if (document.readyState === 'complete') {
|
|
19813
|
+
window.addEventListener('scroll', fallbackHandler, { passive: true });
|
|
19814
|
+
}
|
|
19815
|
+
else {
|
|
19816
|
+
window.addEventListener('load', () => {
|
|
19817
|
+
window.addEventListener('scroll', fallbackHandler, { passive: true });
|
|
19818
|
+
});
|
|
19819
|
+
}
|
|
19820
|
+
}
|
|
19821
|
+
];
|
|
19822
|
+
// Try each strategy
|
|
19823
|
+
attachStrategies.forEach((strategy, index) => {
|
|
19824
|
+
try {
|
|
19825
|
+
strategy();
|
|
19826
|
+
if (this.config.debug) {
|
|
19827
|
+
console.log(`[๐ AutoTracker] Fallback scroll strategy ${index + 1} attached`);
|
|
19828
|
+
}
|
|
19829
|
+
}
|
|
19830
|
+
catch (error) {
|
|
19831
|
+
if (this.config.debug) {
|
|
19832
|
+
console.log(`[โ ๏ธ AutoTracker] Fallback strategy ${index + 1} failed:`, error);
|
|
19833
|
+
}
|
|
19834
|
+
}
|
|
19835
|
+
});
|
|
19836
|
+
this.delegationHandlers.set('scroll', fallbackHandler);
|
|
19837
|
+
// Test scroll detection after setup
|
|
19838
|
+
if (this.config.debug) {
|
|
19839
|
+
setTimeout(() => {
|
|
19840
|
+
console.log("[๐งช AutoTracker] Testing fallback scroll in 2 seconds...");
|
|
19841
|
+
// Add one-time debug listener
|
|
19842
|
+
const testListener = () => {
|
|
19843
|
+
console.log("[โ
AutoTracker] Fallback scroll listener working!");
|
|
19844
|
+
};
|
|
19845
|
+
window.addEventListener('scroll', testListener, { once: true, passive: true });
|
|
19846
|
+
// Trigger test scroll
|
|
19847
|
+
const originalScrollY = window.scrollY;
|
|
19848
|
+
window.scrollBy(0, 1);
|
|
19849
|
+
setTimeout(() => window.scrollTo(0, originalScrollY), 50);
|
|
19850
|
+
}, 2000);
|
|
19851
|
+
}
|
|
19852
|
+
}
|
|
19853
|
+
/**
|
|
19854
|
+
* Create throttled scroll handler (optimized for performance)
|
|
19855
|
+
*/
|
|
19856
|
+
createThrottledScrollHandler() {
|
|
19857
|
+
let lastKnownScrollPosition = 0;
|
|
19858
|
+
let ticking = false;
|
|
19859
|
+
return () => {
|
|
19860
|
+
lastKnownScrollPosition = window.scrollY;
|
|
19861
|
+
if (!ticking) {
|
|
19862
|
+
// Use setTimeout throttling (MDN recommended 2025)
|
|
19863
|
+
setTimeout(() => {
|
|
19864
|
+
if (this.config.debug) {
|
|
19865
|
+
console.log(`[๐ AutoTracker] Fallback scroll handler triggered (scrollY: ${lastKnownScrollPosition})`);
|
|
19866
|
+
}
|
|
19867
|
+
this.processFallbackScroll(lastKnownScrollPosition);
|
|
19868
|
+
ticking = false;
|
|
19869
|
+
}, 20); // 20ms throttle (MDN recommendation)
|
|
19870
|
+
ticking = true;
|
|
19871
|
+
}
|
|
19872
|
+
};
|
|
19873
|
+
}
|
|
19874
|
+
/**
|
|
19875
|
+
* Process scroll for fallback handler (when IntersectionObserver fails)
|
|
19876
|
+
*/
|
|
19877
|
+
processFallbackScroll(scrollPosition) {
|
|
19878
|
+
// Only process if IntersectionObserver didn't handle it
|
|
19879
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]:not([data-scroll-triggered="true"])');
|
|
19880
|
+
if (scrollElements.length === 0)
|
|
19881
|
+
return;
|
|
19882
|
+
scrollElements.forEach((element) => {
|
|
19883
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
19884
|
+
const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19885
|
+
if (!eventName)
|
|
19886
|
+
return;
|
|
19887
|
+
const rect = element.getBoundingClientRect();
|
|
19888
|
+
const windowHeight = window.innerHeight;
|
|
19889
|
+
const elementHeight = rect.height;
|
|
19890
|
+
if (elementHeight <= 0)
|
|
19891
|
+
return;
|
|
19892
|
+
const visibleTop = Math.max(rect.top, 0);
|
|
19893
|
+
const visibleBottom = Math.min(rect.bottom, windowHeight);
|
|
19894
|
+
const visibleHeight = Math.max(0, visibleBottom - visibleTop);
|
|
19895
|
+
const visibilityRatio = visibleHeight / elementHeight;
|
|
19896
|
+
if (visibilityRatio >= threshold) {
|
|
19897
|
+
element.setAttribute('data-scroll-triggered', 'true');
|
|
19898
|
+
const metadata = this.extractMetadata(element);
|
|
19899
|
+
this.trackEvent(eventName, {
|
|
19900
|
+
type: 'scroll',
|
|
19901
|
+
method: 'fallback_scroll',
|
|
19902
|
+
element: element.tagName.toLowerCase(),
|
|
19903
|
+
threshold,
|
|
19904
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19905
|
+
scrollPosition,
|
|
19906
|
+
fallback: true,
|
|
19907
|
+
...metadata,
|
|
19908
|
+
});
|
|
19909
|
+
if (this.config.debug) {
|
|
19910
|
+
console.log(`[๐ฏ Fallback] Event "${eventName}" triggered! (${Math.round(visibilityRatio * 100)}% visible)`);
|
|
19911
|
+
}
|
|
19912
|
+
}
|
|
19913
|
+
});
|
|
19914
|
+
}
|
|
19915
|
+
/**
|
|
19916
|
+
* LEGACY: Create enhanced scroll handler with better performance
|
|
19917
|
+
* @deprecated Use IntersectionObserver approach instead
|
|
19755
19918
|
*/
|
|
19756
19919
|
createEnhancedScrollHandler() {
|
|
19757
19920
|
return () => {
|
|
@@ -20030,11 +20193,25 @@ class AutoTracker {
|
|
|
20030
20193
|
*/
|
|
20031
20194
|
stop() {
|
|
20032
20195
|
if (this.config.debug) {
|
|
20033
|
-
console.log('[AutoTracker] Stopping auto tracking and cleaning up...');
|
|
20196
|
+
console.log('[๐ AutoTracker] Stopping enhanced auto tracking and cleaning up...');
|
|
20034
20197
|
}
|
|
20035
|
-
// Remove delegation handlers
|
|
20198
|
+
// Remove delegation handlers from correct targets
|
|
20036
20199
|
this.delegationHandlers.forEach((handler, eventType) => {
|
|
20037
|
-
|
|
20200
|
+
if (eventType === 'click') {
|
|
20201
|
+
const delegationTarget = this.getOptimalDelegationTarget();
|
|
20202
|
+
delegationTarget.removeEventListener('click', handler);
|
|
20203
|
+
}
|
|
20204
|
+
else if (eventType === 'scroll') {
|
|
20205
|
+
// Remove from both window and document (as we added to both)
|
|
20206
|
+
window.removeEventListener('scroll', handler);
|
|
20207
|
+
document.removeEventListener('scroll', handler);
|
|
20208
|
+
if (this.config.debug) {
|
|
20209
|
+
console.log('[๐ AutoTracker] Removed scroll listeners from window and document');
|
|
20210
|
+
}
|
|
20211
|
+
}
|
|
20212
|
+
else {
|
|
20213
|
+
document.removeEventListener(eventType, handler);
|
|
20214
|
+
}
|
|
20038
20215
|
});
|
|
20039
20216
|
this.delegationHandlers.clear();
|
|
20040
20217
|
// Disconnect observers
|
|
@@ -20049,6 +20226,9 @@ class AutoTracker {
|
|
|
20049
20226
|
// Clear caches
|
|
20050
20227
|
this.observedElements.clear();
|
|
20051
20228
|
this.isInitialized = false;
|
|
20229
|
+
if (this.config.debug) {
|
|
20230
|
+
console.log('[๐ AutoTracker] Enhanced cleanup completed');
|
|
20231
|
+
}
|
|
20052
20232
|
}
|
|
20053
20233
|
/**
|
|
20054
20234
|
* Legacy method - now handled by intelligent mutation observer
|
|
@@ -20419,6 +20599,33 @@ class AutoTracker {
|
|
|
20419
20599
|
source: 'manual_diagnostic',
|
|
20420
20600
|
timestamp: Date.now()
|
|
20421
20601
|
});
|
|
20602
|
+
},
|
|
20603
|
+
testIntersectionObserver: () => {
|
|
20604
|
+
console.log(`[๐งช AutoTracker] Testing IntersectionObserver setup`);
|
|
20605
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
20606
|
+
console.log(`Found ${scrollElements.length} scroll elements for IntersectionObserver`);
|
|
20607
|
+
if (this.intersectionObserver && scrollElements.length > 0) {
|
|
20608
|
+
const firstElement = scrollElements[0];
|
|
20609
|
+
if (firstElement) {
|
|
20610
|
+
console.log('Testing first element:', firstElement.getAttribute('data-track-scroll'));
|
|
20611
|
+
// Temporarily remove triggered state for testing
|
|
20612
|
+
firstElement.removeAttribute('data-scroll-triggered');
|
|
20613
|
+
// Re-observe for testing
|
|
20614
|
+
this.intersectionObserver.observe(firstElement);
|
|
20615
|
+
console.log('Re-observing element for test...');
|
|
20616
|
+
}
|
|
20617
|
+
}
|
|
20618
|
+
},
|
|
20619
|
+
testScrollFallback: () => {
|
|
20620
|
+
console.log(`[๐งช AutoTracker] Testing scroll fallback mechanism`);
|
|
20621
|
+
const handler = this.delegationHandlers.get('scroll');
|
|
20622
|
+
if (handler) {
|
|
20623
|
+
console.log('Triggering fallback scroll handler...');
|
|
20624
|
+
handler(new Event('scroll'));
|
|
20625
|
+
}
|
|
20626
|
+
else {
|
|
20627
|
+
console.log('No scroll handler found in delegation handlers');
|
|
20628
|
+
}
|
|
20422
20629
|
}
|
|
20423
20630
|
};
|
|
20424
20631
|
// Expose tests globally for easy access
|
|
@@ -20473,7 +20680,9 @@ class AutoTracker {
|
|
|
20473
20680
|
usage: {
|
|
20474
20681
|
triggerScrollHandler: 'window.autoTrackerTests.triggerScrollHandler()',
|
|
20475
20682
|
forceScrollEvent: 'window.autoTrackerTests.forceScrollEvent("[data-track-scroll]")',
|
|
20476
|
-
testTrackEvent: 'window.autoTrackerTests.testTrackEvent("my_event")'
|
|
20683
|
+
testTrackEvent: 'window.autoTrackerTests.testTrackEvent("my_event")',
|
|
20684
|
+
testIntersectionObserver: 'window.autoTrackerTests.testIntersectionObserver()',
|
|
20685
|
+
testScrollFallback: 'window.autoTrackerTests.testScrollFallback()'
|
|
20477
20686
|
},
|
|
20478
20687
|
description: 'Use these functions in the browser console to manually test the AutoTracker'
|
|
20479
20688
|
}
|