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