scradar
Version:
CSS-first scroll interaction library with progress-based animations
2 lines (1 loc) • 30.4 kB
JavaScript
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Scradar=e()}(this,function(){"use strict";function t(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const s=t.dataset.scradar,i=t.dataset.scradarConfig;if(i){if(window.scradarConfigs&&window.scradarConfigs[i]){const e=window.scradarConfigs[i];return"function"==typeof e?e(t):e}if(e.configs&&e.configs[i]){const s=e.configs[i];return"function"==typeof s?s(t):s}}if(s&&"object"==typeof s)return s;if(s)try{return JSON.parse(s.replace(/'/g,'"').replace(/([\w\d]+):/g,'"$1":').replace(/:"([^"]+)"/g,(t,e)=>e.startsWith('"')&&e.endsWith('"')?":"+e:':"'+e+'"'))}catch(e){console.error("🎯 Scradar Parse Error:",{element:t,input:s,error:e.message,suggestion:"Check your data-scradar attribute syntax.",example:'data-scradar="{visibility: true, fill: true}"'})}return{}}function e(t,e,s,i){if(!e[s]&&"peak"!==s)return;t=Array.isArray(t)?t:[t];const r=e.prefix?e.prefix+"-":"";let n;n="peak"===s?["css"]:e[s]||["css"],Array.isArray(n)?n.forEach(e=>{if("data"===e){const e=r+s.replace(/([A-Z])/g,"-$1").toLowerCase();t.forEach(t=>{t.dataset[e]=i})}else if("css"===e){const e="--"+r+s.replace(/([A-Z])/g,"-$1").toLowerCase();t.forEach(t=>{t.style.setProperty(e,i)})}}):console.error("🎯 Scradar Configuration Error:",{type:s,expected:"Array",received:typeof n,value:n,suggestion:`Use ${s}: ['css'] or ${s}: ['css', 'data']`,element:t[0]})}function s(t){return t.charAt(0).toUpperCase()+t.slice(1)}function i(t,e){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};(t=Array.isArray(t)?t:[t]).forEach(t=>{t.dispatchEvent(new CustomEvent(e,{detail:s}))})}function r(t){let e=!1;return function(){for(var s=arguments.length,i=new Array(s),r=0;r<s;r++)i[r]=arguments[r];e||(window.requestAnimationFrame(()=>{t(...i),e=!1}),e=!0)}}function n(t,e){if(t===window){const t=document.createElement("div");t.style[e]="width"===e?"100vw":"100vh",t.style.position="fixed",t.style.pointerEvents="none",document.body.append(t);const s="width"===e?t.offsetWidth:t.offsetHeight;return t.remove(),s||("width"===e?window.innerWidth:window.innerHeight)}return"width"===e?t.offsetWidth:t.offsetHeight}class a{constructor(e,s,i){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};this.el=e,this.shadowDom=i,this.settings={...s,...t(e,r)},this.init=!1,this.triggerId=null,this.container=null,this.containerSize=0,this.visibility=0,this.fill=0,this.cover=0,this.enter=0,this.exit=0,this.peak=0,this.offsetEnter=0,this.offsetExit=0,this.wasIn=!1,this.wasFull=!1,this.isFull=!1,this.currentVisibilityStep=null,this.currentFillStep=null,this.currentCoverStep=null,this.currentEnterStep=null,this.currentExitStep=null,this.#t()}#t(){this.#e(),this.#s(),this.#i(),this.#r(),this.#n(),this.update(),this.init=!0}#n(){this.container=this.settings.container?document.querySelector(this.settings.container):window,this.containerSize=this.settings.horizontal?n(this.container,"width"):n(this.container,"height")}#e(){["visibility","fill","cover","enter","exit","offsetEnter","offsetExit"].forEach(t=>{if(void 0!==this.settings[t])if(this.settings[t])if(Array.isArray(this.settings[t])){const e=this.settings[t].filter(t=>["css","data"].includes(t));this.settings[t]=e.length?e:["css"]}else!0===this.settings[t]?this.settings[t]=["css"]:"string"==typeof this.settings[t]&&(this.settings[t]=[this.settings[t]]);else delete this.settings[t]})}#s(){["visibility","fill","cover","enter","exit"].forEach(t=>{const e=`${t}Step`;Array.isArray(this.settings[e])&&(this.settings[e]=[...new Set([-9999,...this.settings[e],9999])].sort((t,e)=>t-e),this[`current${s(t)}Step`]=0)})}#i(){if(Array.isArray(this.settings.peak)&&3===this.settings.peak.length){const[t,e,s]=this.settings.peak;this.settings.peak={start:t,peak:e,end:s}}}#r(){if(!this.settings.trigger)return;const t=document.createElement("div"),e=this.settings.trigger.trim().split(" ");Object.assign(t.style,{position:"fixed",zIndex:-1,pointerEvents:"none",opacity:0,top:e[0]||"0",right:e[1]||e[0]||"0",bottom:e[2]||e[0]||"0",left:e[3]||e[1]||e[0]||"0"}),t.id="trigger_"+(Math.random()+1).toString(36).substring(2),t.setAttribute("tabindex",-1),this.triggerId=t.id,this.shadowDom.append(t)}update(){let t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(this.settings.unmount&&this.init)return;this.settings.mount||(this.settings.unmount=!0),this.settings.breakpoint&&t&&this.#a(window.innerWidth),!t&&this.containerSize||this.#o();const e=this.el.getBoundingClientRect(),s=this.settings.horizontal,i=this.containerSize,r=s?this.el.offsetWidth:this.el.offsetHeight,n=s?e.left:e.top,a=n+r,o=this.#d(n,i),d=r-o-i;this.#l(n,a,r,i,d,o),this.#c(),this.#h(),this.#g(n,a,i),this.triggerId&&this.#u(n,a)}#o(){this.container=this.settings.container?document.querySelector(this.settings.container):window,this.containerSize=this.settings.horizontal?n(this.container,"width"):n(this.container,"height")}#a(t){const e=this.el.dataset.scradar?function(t){try{return JSON.parse(t.replace(/'/g,'"').replace(/([\w\d]+):/g,'"$1":').replace(/:"([^"]+)"/g,(t,e)=>e.startsWith('"')&&e.endsWith('"')?":"+e:':"'+e+'"'))}catch(e){return console.error("🎯 Scradar Parse Error:",{input:t,error:e.message,suggestion:"Check your data-scradar attribute syntax. Use double quotes or proper JSON format.",example:"data-scradar=\"{visibility: true, fill: ['css', 'data']}\""}),{}}}(this.el.dataset.scradar):{};Object.keys(this.settings.breakpoint).map(Number).sort((t,e)=>t-e).forEach(s=>{t>=s?Object.assign(this.settings,this.settings.breakpoint[s]):Object.keys(this.settings.breakpoint[s]).forEach(t=>{void 0!==e[t]?this.settings[t]=e[t]:delete this.settings[t]})}),this.#e(),this.#s(),this.#o()}#d(t,e){if(!this.settings.delay)return 0;const s=this.el.querySelectorAll(`${this.settings.delay}:not(.disabled)`);let i=0;return s.forEach(s=>{const r=s.getBoundingClientRect(),n=this.settings.horizontal?r.width:r.height;this.settings.horizontal?r.left:r.top;const a=this.settings.horizontal?s.offsetLeft:s.offsetTop,o=Math.max(n+a+t,0);o>=0&&o<=n?i+=n-Math.max(Math.min(o,n),0):s.classList.contains("scradar__delay--end")&&o>=e&&o<=e+n&&(i+=n-Math.min(o-e,n))}),Math.max(0,i)}#l(t,e,s,i,r,n){const a=-i-s;if(this.visibility=Math.max(0,Math.min(1,e/a+1)),this.settings.fill&&(s>i?(this.fill=t<=0&&t>=-r?0:t<-r?1-(t+s)/i:-t/i,this.fill=Math.max(-1,Math.min(1,this.fill))):this.fill=Math.max(-1,Math.min(1,-t/s))),this.settings.cover&&s>i){const e=(t+n)/-r;this.cover=Math.max(0,Math.min(1,e))}else this.cover=0;if(this.settings.enter||this.settings.exit){const a=s-n;this.settings.enter&&(this.enter=e/-i*(i/a)+1),this.settings.exit&&(this.exit=(t+r)/(i+r))}if(this.settings.peak){let t;if(Array.isArray(this.settings.peak)){const[e,s,i]=this.settings.peak;t={start:e,peak:s,end:i}}else void 0!==this.settings.peak.peak&&(t=this.settings.peak);if(t){const{start:e,peak:s,end:i}=t;if(this.visibility<e||this.visibility>i)this.peak=0;else{const t=this.visibility<=s?s-e:i-s,r=this.visibility<=s?this.visibility-e:i-this.visibility;this.peak=Math.max(0,Math.min(1,r/t))}}}}#c(){!this._receiverCache&&this.settings.receiver&&(this._receiverCache=Array.from(document.querySelectorAll(this.settings.receiver)));const t=this.settings.receiver?[this.el,...this._receiverCache]:[this.el];if(this.settings.visibility&&(e(t,this.settings,"visibility",this.visibility),this.#p("visibility",this.visibility)),this.settings.fill&&(e(t,this.settings,"fill",this.fill),this.#p("fill",this.fill)),this.settings.cover&&(e(t,this.settings,"cover",this.cover),this.#p("cover",this.cover)),this.settings.enter&&(e(t,this.settings,"enter",this.enter),this.#p("enter",this.enter)),this.settings.exit&&(e(t,this.settings,"exit",this.exit),this.#p("exit",this.exit)),void 0!==this.peak&&this.settings.peak&&(e(t,this.settings,"peak",this.peak),this.#p("peak",this.peak)),this.settings.offsetEnter){const s=this.settings.horizontal?this.el.getBoundingClientRect().left:this.el.getBoundingClientRect().top;e(t,this.settings,"offsetEnter",s),this.#p("offsetEnter",s)}if(this.settings.offsetExit){const s=this.el.getBoundingClientRect(),i=this.settings.horizontal?this.containerSize-s.right:this.containerSize-s.bottom;e(t,this.settings,"offsetExit",i),this.#p("offsetExit",i)}}#p(t,e){i(this.el,`${t}Update`,{value:e})}#h(){["visibility","fill","cover","enter","exit"].forEach(t=>{const e=`${t}Step`;if(!Array.isArray(this.settings[e]))return;const r=this[t],n=this.settings[e];let a=null;for(let t=0;t<n.length-1;t++)if(r>=n[t]&&r<n[t+1]){a=t;break}const o=`current${s(t)}Step`;null!==a&&this[o]!==a&&(i(this.el,"stepChange",{type:t,step:a,prevStep:this[o],maxStep:n.length-2,isInitial:!this.init}),this.el.dataset[`${t}Step`]=a,this[o]=a)})}#g(t,e,s){const r=e>0&&t<s;if(r!==this.wasIn&&(this.el.dataset.scradarIn=r?1:0,r?i(this.el,"scrollEnter",{from:t<0?"top":"bottom",isInitial:!this.init}):this.settings.once&&this.settings.done||i(this.el,"scrollExit",{from:e<s?"top":"bottom",isInitial:!this.init}),this.settings.once&&r&&(this.settings.done=!0),this.wasIn=r),r){this.el.dataset.scradarEnter=t<=0?1:0,this.el.dataset.scradarExit=e>=s?1:0;const r=t<=0&&e>=s;r!==this.wasFull&&(r?i(this.el,"fullIn",{from:t<0?"top":"bottom",isInitial:!this.init}):i(this.el,"fullOut",{from:+this.el.dataset.scradarEnter?"bottom":"top",isInitial:!this.init}),this.wasFull=r,this.isFull=r)}else this.el.dataset.scradarEnter=0,this.el.dataset.scradarExit=0}#u(t,e){const s=this.shadowDom.getElementById(this.triggerId);if(!s)return;const r=s.getBoundingClientRect(),n=this.settings.horizontal?r.left:r.top,a=this.settings.horizontal?r.right:r.bottom,o=t<=a&&e>=n,d=1===+this.el.dataset.collision,l=1===+this.el.dataset.scradarFire;o&&!d?(this.el.dataset.collision=1,i(this.el,"collisionEnter",{from:t<=a?"top":"bottom",isInitial:!this.init}),l||(this.el.dataset.scradarFire=1,i(this.el,"fire",{from:t<=a?"top":"bottom",isInitial:!this.init}))):!o&&d&&(this.el.dataset.collision=0,i(this.el,"collisionExit",{from:e>=n?"top":"bottom",isInitial:!this.init}))}destroy(){Object.keys(this.el.dataset).forEach(t=>{(t.startsWith("scradar")||t.includes("Step")||t.includes("progress")||"collision"===t)&&delete this.el.dataset[t]});const t=this.el.style;for(let e=t.length-1;e>=0;e--){const s=t[e];s.startsWith("--")&&t.removeProperty(s)}if(this.triggerId&&this.shadowDom){const t=this.shadowDom.getElementById(this.triggerId);t&&t.remove()}}}class o{constructor(t){this.scradar=t,this.overlay=null,this.isCollapsed="true"===localStorage.getItem("scradar-debug-collapsed"),this.isTargetsCollapsed="true"===localStorage.getItem("scradar-targets-collapsed"),this.collapsedTargets=JSON.parse(localStorage.getItem("scradar-targets-individual")||"[]"),this.isHidden="true"===localStorage.getItem("scradar-debug-hidden"),this.performanceMetrics={updateCount:0,lastUpdateTime:0,avgUpdateTime:0,maxUpdateTime:0,elementsCount:0},this.init()}init(){document.getElementById("scradar-debug-overlay")||(this.overlay=document.createElement("div"),this.overlay.id="scradar-debug-overlay",this.overlay.innerHTML='\n <style>\n #scradar-debug-overlay {\n position: fixed;\n top: 10px;\n right: 10px;\n z-index: 999999;\n background: rgba(0, 0, 0, 0.85);\n color: #fff;\n padding: 15px;\n border-radius: 8px;\n font-family: \'Monaco\', \'Menlo\', monospace;\n font-size: 12px;\n min-width: 300px;\n max-width: 420px;\n max-height: 80vh;\n overflow-y: auto;\n pointer-events: all;\n user-select: text;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n transition: all 0.3s ease;\n }\n #scradar-debug-overlay.collapsed {\n min-width: 300px;\n max-width: 300px;\n max-height: 60px;\n overflow: hidden;\n }\n #scradar-debug-overlay::-webkit-scrollbar {\n width: 6px;\n }\n #scradar-debug-overlay::-webkit-scrollbar-track {\n background: rgba(255,255,255,0.1);\n }\n #scradar-debug-overlay::-webkit-scrollbar-thumb {\n background: rgba(255,255,255,0.3);\n border-radius: 3px;\n }\n #scradar-debug-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 10px;\n padding-bottom: 10px;\n border-bottom: 1px solid rgba(255,255,255,0.2);\n cursor: pointer;\n }\n #scradar-debug-title {\n font-weight: bold;\n font-size: 14px;\n color: #4fc3f7;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n #scradar-debug-toggle {\n font-size: 12px;\n color: #81c784;\n transition: transform 0.3s ease;\n }\n #scradar-debug-overlay.collapsed #scradar-debug-toggle {\n transform: rotate(-90deg);\n }\n .scradar-debug-performance {\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid rgba(76, 175, 80, 0.3);\n padding: 8px;\n border-radius: 4px;\n margin-bottom: 10px;\n }\n .scradar-debug-warning {\n background: rgba(255, 193, 7, 0.1);\n border: 1px solid rgba(255, 193, 7, 0.3);\n padding: 8px;\n border-radius: 4px;\n margin-bottom: 10px;\n color: #ffc107;\n }\n .scradar-debug-error {\n background: rgba(244, 67, 54, 0.1);\n border: 1px solid rgba(244, 67, 54, 0.3);\n padding: 8px;\n border-radius: 4px;\n margin-bottom: 10px;\n color: #f44336;\n }\n #scradar-debug-close {\n cursor: pointer;\n padding: 2px 8px;\n background: rgba(255,255,255,0.1);\n border-radius: 4px;\n transition: background 0.2s;\n }\n #scradar-debug-close:hover {\n background: rgba(255,255,255,0.2);\n }\n .scradar-debug-section {\n margin-bottom: 15px;\n }\n .scradar-debug-section-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n padding: 5px 0;\n border-bottom: 1px solid rgba(255,255,255,0.1);\n }\n .scradar-debug-section-header:hover {\n background: rgba(255,255,255,0.05);\n }\n .scradar-debug-section-content {\n transition: all 0.3s ease;\n overflow: hidden;\n }\n .scradar-debug-section-content.collapsed {\n max-height: 0;\n opacity: 0;\n }\n .scradar-debug-label {\n color: #81c784;\n font-weight: bold;\n margin-bottom: 5px;\n }\n .scradar-debug-value {\n color: #ffd54f;\n font-weight: bold;\n }\n .scradar-debug-target {\n background: rgba(255,255,255,0.05);\n padding: 8px;\n margin-bottom: 8px;\n border-radius: 4px;\n border-left: 3px solid #4fc3f7;\n }\n .scradar-debug-target-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n margin-bottom: 4px;\n }\n .scradar-debug-target-header:hover {\n background: rgba(255,255,255,0.05);\n border-radius: 2px;\n padding: 2px;\n margin: -2px;\n }\n .scradar-debug-target-title {\n color: #4fc3f7;\n font-weight: bold;\n }\n .scradar-debug-target-toggle {\n font-size: 10px;\n color: #81c784;\n transition: transform 0.3s ease;\n }\n .scradar-debug-target-content {\n transition: all 0.3s ease;\n overflow: hidden;\n }\n .scradar-debug-target-content.collapsed {\n max-height: 0;\n opacity: 0;\n }\n .scradar-debug-progress {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 8px;\n font-size: 11px;\n }\n .scradar-debug-progress-bar {\n height: 3px;\n background: rgba(255,255,255,0.1);\n border-radius: 2px;\n overflow: hidden;\n margin-top: 2px;\n }\n .scradar-debug-progress-fill {\n height: 100%;\n background: #4fc3f7;\n transition: width 0.1s;\n }\n .scradar-debug-shortcuts {\n font-size: 10px;\n color: #aaa;\n margin-top: 10px;\n padding-top: 10px;\n border-top: 1px solid rgba(255,255,255,0.1);\n }\n </style>\n <div id="scradar-debug-header">\n <div id="scradar-debug-title">\n 🎯 Scradar Debug\n <span id="scradar-debug-toggle">▼</span>\n </div>\n <div id="scradar-debug-close">✕</div>\n </div>\n <div id="scradar-debug-content">\n <div class="scradar-debug-performance">\n <div class="scradar-debug-label">⚡ Performance</div>\n <div class="scradar-debug-progress">\n <span>Elements:</span>\n <span class="scradar-debug-value" id="debug-elements">-</span>\n <span>Updates:</span>\n <span class="scradar-debug-value" id="debug-updates">-</span>\n <span>Avg Update:</span>\n <span class="scradar-debug-value" id="debug-avg">-</span>\n <span>Max Update:</span>\n <span class="scradar-debug-value" id="debug-max">-</span>\n </div>\n </div>\n \n <div class="scradar-debug-section">\n <div class="scradar-debug-section-header" id="global-header">\n <div class="scradar-debug-label">🌍 Global</div>\n <span class="scradar-debug-toggle">▼</span>\n </div>\n <div class="scradar-debug-section-content" id="global-content">\n <div class="scradar-debug-progress">\n <span>Scroll Progress:</span>\n <span class="scradar-debug-value" id="debug-progress">-</span>\n <span>Direction:</span>\n <span class="scradar-debug-value" id="debug-direction">-</span>\n <span>Boundary Target:</span>\n <span class="scradar-debug-value" id="debug-target">-</span>\n </div>\n <div class="scradar-debug-progress-bar">\n <div class="scradar-debug-progress-fill" id="debug-progress-bar"></div>\n </div>\n </div>\n </div>\n \n <div class="scradar-debug-section">\n <div class="scradar-debug-section-header" id="targets-header">\n <div class="scradar-debug-label">🎯 Targets</div>\n <span class="scradar-debug-toggle">▼</span>\n </div>\n <div class="scradar-debug-section-content" id="targets-content">\n <div id="debug-targets-list"></div>\n </div>\n </div>\n \n <div class="scradar-debug-shortcuts">\n <div>⌘+Shift+D: Toggle Debug</div>\n <div>⌘+Shift+C: Toggle Collapse</div>\n </div>\n </div>\n ',document.body.append(this.overlay),this.isCollapsed&&(this.overlay.classList.add("collapsed"),this.overlay.querySelector("#scradar-debug-toggle").textContent="▶"),this.isTargetsCollapsed&&(this.overlay.querySelector("#targets-content").classList.add("collapsed"),this.overlay.querySelector("#targets-header .scradar-debug-toggle").textContent="▶"),this.isHidden&&(this.overlay.style.display="none"),this.overlay.querySelector("#scradar-debug-close").addEventListener("click",()=>{this.overlay.style.display="none",this.isHidden=!0,localStorage.setItem("scradar-debug-hidden","true")}),this.overlay.querySelector("#scradar-debug-header").addEventListener("click",()=>{this.toggleCollapse()}),this.overlay.querySelector("#global-header").addEventListener("click",()=>{this.toggleSection("global")}),this.overlay.querySelector("#targets-header").addEventListener("click",()=>{this.toggleSection("targets")}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.shiftKey&&("D"===t.key?(this.isHidden=!this.isHidden,this.overlay.style.display=this.isHidden?"none":"block",localStorage.setItem("scradar-debug-hidden",this.isHidden)):"C"===t.key&&this.toggleCollapse())}),this.update())}toggleCollapse(){this.isCollapsed=!this.isCollapsed,this.overlay.classList.toggle("collapsed",this.isCollapsed),this.overlay.querySelector("#scradar-debug-toggle").textContent=this.isCollapsed?"▶":"▼",localStorage.setItem("scradar-debug-collapsed",this.isCollapsed)}toggleSection(t){const e=this.overlay.querySelector(`#${t}-content`),s=this.overlay.querySelector(`#${t}-header .scradar-debug-toggle`);"targets"===t?(this.isTargetsCollapsed=!this.isTargetsCollapsed,e.classList.toggle("collapsed",this.isTargetsCollapsed),s.textContent=this.isTargetsCollapsed?"▶":"▼",localStorage.setItem("scradar-targets-collapsed",this.isTargetsCollapsed)):(e.classList.toggle("collapsed"),s.textContent=e.classList.contains("collapsed")?"▶":"▼")}toggleTarget(t){const e=this.overlay.querySelector(`#target-${t}-content`),s=this.overlay.querySelector(`#target-${t}-toggle`),i=e.classList.contains("collapsed");e.classList.toggle("collapsed",!i),s.textContent=i?"▼":"▶",i?this.collapsedTargets=this.collapsedTargets.filter(e=>e!==t):this.collapsedTargets.push(t),localStorage.setItem("scradar-targets-individual",JSON.stringify(this.collapsedTargets))}update(){if(!this.overlay||"none"===this.overlay.style.display)return;const t=performance.now(),e=+(document.documentElement.dataset.scradarProgress||0),s=+(document.documentElement.dataset.scradarScroll||0),i=document.documentElement.dataset.scradarTarget||"-";this.performanceMetrics.elementsCount=this.scradar.elements.length;const r=this.scradar.elements.filter(t=>+t.dataset.scradarIn).length;this.overlay.querySelector("#debug-elements").textContent=`${this.performanceMetrics.elementsCount} (${r} active)`,this.overlay.querySelector("#debug-updates").textContent=this.performanceMetrics.updateCount,this.overlay.querySelector("#debug-avg").textContent=`${this.performanceMetrics.avgUpdateTime.toFixed(2)}ms`,this.overlay.querySelector("#debug-max").textContent=`${this.performanceMetrics.maxUpdateTime.toFixed(2)}ms`,this.overlay.querySelector("#debug-progress").textContent=e.toFixed(3),this.overlay.querySelector("#debug-direction").textContent=1===s?"↓ Down":-1===s?"↑ Up":"• Stop",this.overlay.querySelector("#debug-target").textContent=i,this.overlay.querySelector("#debug-progress-bar").style.width=100*e+"%";const n=this.overlay.querySelector("#debug-targets-list");let a="";this.scradar.elements.forEach((t,e)=>{const s=t.scradar;if(!s)return;const i=`target-${e}`,r=t.dataset.scradarTitle||t.dataset.scradarConfig||t.className||t.tagName.toLowerCase(),n=+t.dataset.scradarIn,o=this.collapsedTargets.includes(i);a+=`\n <div class="scradar-debug-target">\n <div class="scradar-debug-target-header" onclick="window.scradarDebug.toggleTarget('${i}')">\n <div class="scradar-debug-target-title">\n #${e+1} ${r} ${n?"🐵":"🙈"}\n </div>\n <span class="scradar-debug-target-toggle" id="target-${i}-toggle">${o?"▶":"▼"}</span>\n </div>\n <div class="scradar-debug-target-content" id="target-${i}-content" ${o?'class="collapsed"':""}>\n <div class="scradar-debug-progress">\n ${void 0!==s.visibility?`\n <span>visibility:</span>\n <span class="scradar-debug-value">${s.visibility.toFixed(3)}</span>\n `:""}\n ${void 0!==s.fill?`\n <span>fill:</span>\n <span class="scradar-debug-value">${s.fill.toFixed(3)}</span>\n `:""}\n ${void 0!==s.cover?`\n <span>cover:</span>\n <span class="scradar-debug-value">${s.cover.toFixed(3)}</span>\n `:""}\n ${void 0!==s.enter?`\n <span>enter:</span>\n <span class="scradar-debug-value">${s.enter.toFixed(3)}</span>\n `:""}\n ${void 0!==s.exit?`\n <span>exit:</span>\n <span class="scradar-debug-value">${s.exit.toFixed(3)}</span>\n `:""}\n ${void 0!==s.peak&&0!==s.peak?`\n <span>peak:</span>\n <span class="scradar-debug-value">${s.peak.toFixed(3)}</span>\n `:""}\n ${null!==s.currentVisibilityStep?`\n <span>step:</span>\n <span class="scradar-debug-value">${s.currentVisibilityStep}</span>\n `:""}\n </div>\n ${void 0!==s.visibility?`\n <div class="scradar-debug-progress-bar">\n <div class="scradar-debug-progress-fill" style="width: ${100*s.visibility}%"></div>\n </div>\n `:""}\n </div>\n </div>\n `}),n.innerHTML=a;const o=performance.now()-t;this.performanceMetrics.updateCount++,this.performanceMetrics.lastUpdateTime=o,this.performanceMetrics.avgUpdateTime=(this.performanceMetrics.avgUpdateTime*(this.performanceMetrics.updateCount-1)+o)/this.performanceMetrics.updateCount,o>this.performanceMetrics.maxUpdateTime&&(this.performanceMetrics.maxUpdateTime=o)}destroy(){this.overlay&&(this.overlay.remove(),this.overlay=null)}}class d{static version="1.0.3";static defaults={target:".scradar",root:null,trigger:null,prefix:"",visibility:!1,fill:!1,cover:!1,enter:!1,exit:!1,offsetEnter:!1,offsetExit:!1,peak:null,once:!1,totalProgress:!0,boundary:!1,momentum:!1,horizontal:!1,container:null,receiver:null,delay:null,breakpoint:null,debug:!1};static configs={};#m=[];#b;#f;#v=null;#y=null;#w=null;#x=null;#S=null;#k=null;#E=!1;#C=null;#T=0;#M={step:0,deltaY:0,firstValue:0,timer:null,isMomentum:!1};#$=null;#I=!1;#z=null;#D=null;constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};"object"!=typeof t||null===t||t.nodeType||(e=t,t=null),this.#b={...d.defaults,...e},"string"==typeof t&&(this.#b.target=t),this.#f=this.#b.root?document.querySelector(this.#b.root):window,this.#t()}#t(){if(this.#E)return;const t=this.#b.target||".scradar";this.#m=Array.from(document.querySelectorAll(t));const e=document.createElement("div");e.id="scradarTriggerWrapper",e.style.display="none",document.body.append(e),this.#k=e.attachShadow({mode:"open"}),this.#m.forEach(t=>{t.scradar=new a(t,this.#b,this.#k,{configs:d.configs})}),this.#S=new IntersectionObserver(this.#H.bind(this),{root:this.#f===window?null:this.#f,threshold:[0,1e-5,.99999,1]}),this.#m.forEach(t=>this.#S.observe(t)),this.#v=r(this.#A.bind(this)),this.#y=r(this.#q.bind(this)),this.#w=r(this.#L.bind(this)),this.#x=this.#P.bind(this);(this.#f===window?window:this.#f).addEventListener("scroll",this.#v,{passive:!0}),window.addEventListener("resize",this.#y),window.addEventListener("wheel",this.#w,{passive:!0}),document.addEventListener("keydown",this.#x),this.#b.debug&&(this.#z=new o(this),window.scradarDebug=this.#z),this.update()}#H(t){t.forEach(t=>{const e=t.target.scradar;e&&(0===t.intersectionRatio||e.settings.done?e.settings.mount=!1:(e.settings.mount=!0,e.settings.unmount=!1))})}#A(){if(this.#E)return;const t=this.#f===window?window.scrollY:this.#f.scrollTop,e=window.innerHeight;if(null!==this.#C&&(t>this.#C?1!==this.#T&&(this.#T=1,document.documentElement.dataset.scradarScroll=1,i(window,"scrollTurn",{scroll:1})):t<this.#C?-1!==this.#T&&(this.#T=-1,document.documentElement.dataset.scradarScroll=-1,i(window,"scrollTurn",{scroll:-1})):(this.#T=0,document.documentElement.dataset.scradarScroll=0)),Math.abs(this.#C-t)>300&&0===t)return this.#C=0,void this.update();if(this.#C=t,this.#b.totalProgress){const s=t/(document.documentElement.scrollHeight-e);document.documentElement.dataset.scradarProgress=s,this.progress=s}this.#m.forEach(t=>t.scradar&&t.scradar.update()),this.#b.boundary&&this.#O(),this.#z&&this.#z.update()}#q(){this.#E||(this.#m.forEach(t=>t.scradar&&t.scradar.update(!0)),this.#z&&this.#z.update())}#L(t){this.#E||(this.#M.deltaY=t.deltaY,this.#M.step++,clearTimeout(this.#M.timer),this.#M.step>10&&Math.abs(this.#M.deltaY)<=10||Math.abs(this.#M.deltaY)<=2?(this.#M.step=0,this.#M.firstValue=this.#M.deltaY,this.#M.isMomentum=!1):1===this.#M.step&&Math.abs(this.#M.deltaY)>Math.abs(this.#M.firstValue)&&(this.#M.isMomentum=!0,i(window,"momentum",{status:this.#M.deltaY>0?1:-1})),this.#M.timer=setTimeout(()=>{this.#M.step=0,this.#M.isMomentum=!1},80))}#P(t){(t.metaKey&&("ArrowUp"===t.key||"ArrowDown"===t.key)||"Tab"===t.key||"Home"===t.key||"End"===t.key)&&(this.#I=!0,this.#$=this.#f===window?window.scrollY:this.#f.scrollTop,this.#U())}#U(){if(null!==this.#$){const t=this.#f===window?window.scrollY:this.#f.scrollTop;this.#I||this.#$!==t?(this.#I=!1,this.#$=t,r(this.#U.bind(this))()):(this.update(),this.#$=null)}}#O(){const t="number"==typeof this.#b.boundary?this.#b.boundary:.5,e=window.innerHeight*t,s=this.#m.filter(t=>t.dataset.scradarTitle&&1===+t.dataset.scradarIn);if(s.length){const t=1===s.length?s[0]:s.sort((t,s)=>{const i=t.getBoundingClientRect(),r=s.getBoundingClientRect();return Math.abs(i.top+i.height/2-e)-Math.abs(r.top+r.height/2-e)})[0];this.#D=t.dataset.scradarTitle,document.documentElement.dataset.scradarTarget=this.#D}else this.#D&&(document.documentElement.dataset.scradarTarget="# "+this.#D)}get elements(){return this.#m}get scroll(){return this.#T}update(){this.#E||(this.#m.forEach(t=>{t.scradar&&(t.scradar.settings.unmount=!1,t.scradar.update())}),this.#z&&this.#z.update())}destroy(){if(this.#E)return;(this.#f===window?window:this.#f).removeEventListener("scroll",this.#v),window.removeEventListener("resize",this.#y),window.removeEventListener("wheel",this.#w),document.removeEventListener("keydown",this.#x),this.#S&&this.#S.disconnect(),this.#k&&this.#k.host&&this.#k.host.remove(),this.#m.forEach(t=>{t.scradar&&(t.scradar.destroy(),delete t.scradar)}),this.#z&&this.#z.destroy(),this.#m=[],this.#E=!0}}return d});