UNPKG

@stacksjs/stx

Version:

A performant UI Framework. Powered by Bun.

694 lines (630 loc) 863 kB
#!/usr/bin/env bun // @bun var DQ=Object.defineProperty;var a=($,Z)=>{for(var Y in Z)DQ($,Y,{get:Z[Y],enumerable:!0,configurable:!0,set:(J)=>Z[Y]=()=>J})};var I=($,Z)=>()=>($&&(Z=$($=0)),Z);var o=import.meta.require;import B1 from"path";function j1($,Z,Y,J){let X=$;X=X.replace(/@a11y\(\s*['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"]\s*)?\)/g,(G,K,W)=>{let U={"aria-label":"Ensure interactive elements have accessible labels","alt-text":"Provide alternative text for images",focus:"Ensure the element can receive keyboard focus",landmark:"Use appropriate landmark roles","heading-order":"Maintain proper heading hierarchy","color-contrast":"Ensure sufficient color contrast","keyboard-nav":"Make sure element is keyboard navigable","screen-reader":"Optimize for screen reader users"}[K]||"Make this element accessible";return`<!-- a11y-hint: ${W||U} -->`});let Q=/@screenReader\(([^@]*)\)@endScreenReader/g;return X=X.replace(Q,(G,K)=>{return`<span class="sr-only">${K.trim()}</span>`}),X=X.replace(/@ariaDescribe\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]\s*\)/g,(G,K,W)=>{return`<span id="${`desc-${K}`}" class="sr-only">${W}</span>`}),X}function SQ(){return typeof globalThis.document<"u"&&typeof globalThis.document.createElement==="function"}function CQ($,Z){let Y=[],J=/<img\s+([^>]*)>/gi,X;X=J.exec($);while(X!==null){let H=X[1];if(!/\balt\s*=/i.test(H))Y.push({type:"missing-alt",element:X[0].substring(0,100),message:"Image missing alt attribute",impact:"serious",help:"Add alt text to images for screen readers",helpUrl:"https://web.dev/learn/accessibility/images/"});X=J.exec($)}let Q=/<button([^>]*)>\s*<\/button>/gi;X=Q.exec($);while(X!==null){let H=X[1];if(!/\baria-label\s*=/i.test(H)&&!/\btitle\s*=/i.test(H))Y.push({type:"missing-accessible-name",element:X[0].substring(0,100),message:"Empty button missing accessible name",impact:"critical",help:"Add text content, aria-label, or title",helpUrl:"https://web.dev/learn/accessibility/aria-html/"});X=Q.exec($)}let G=/<a\s+([^>]*)>\s*<\/a>/gi;X=G.exec($);while(X!==null){let H=X[1];if(!/\baria-label\s*=/i.test(H)&&!/\btitle\s*=/i.test(H))Y.push({type:"link-missing-text",element:X[0].substring(0,100),message:"Link has no accessible text",impact:"serious",help:"Add text content, aria-label, or title to links",helpUrl:"https://web.dev/learn/accessibility/more-html/#links"});X=G.exec($)}let K=/<(input|select|textarea)\s+([^>]*)>/gi;X=K.exec($);while(X!==null){let H=X[2];if(/\btype\s*=\s*["']hidden["']/i.test(H)){X=K.exec($);continue}let V=/\baria-label\s*=/i.test(H)||/\baria-labelledby\s*=/i.test(H),L=H.match(/\bid\s*=\s*["']([^"']+)["']/i);if(!V){let F=L&&new RegExp(`<label[^>]*\\bfor\\s*=\\s*["']${L[1]}["']`,"i").test($),M=X.index,R=$.substring(0,M),N=$.substring(M),w=(R.match(/<label\b/gi)||[]).length,E=(R.match(/<\/label>/gi)||[]).length,k=w>E;if(!F&&!k)Y.push({type:"input-missing-label",element:X[0].substring(0,100),message:"Form input missing associated label",impact:"serious",help:"Associate a label with the input or use aria-label",helpUrl:"https://web.dev/learn/accessibility/forms/"})}X=K.exec($)}let W=/<h([1-6])[^>]*>/gi,_=[];X=W.exec($);while(X!==null)_.push(Number.parseInt(X[1],10)),X=W.exec($);let U=0;for(let H of _){if(U>0&&H>U+1)Y.push({type:"heading-skip",element:`<h${H}>`,message:`Heading level skipped from h${U} to h${H}`,impact:"moderate",help:"Maintain proper heading hierarchy without skipping levels",helpUrl:"https://web.dev/learn/accessibility/structure/"});U=H}if(/<html\b/i.test($)&&!/<html[^>]*\slang\s*=/i.test($))Y.push({type:"missing-lang",element:"<html>",message:"Document language not specified",impact:"serious",help:"Add lang attribute to the html element",helpUrl:"https://web.dev/learn/accessibility/more-html/#language"});let B=/<table[^>]*>([\s\S]*?)<\/table>/gi;X=B.exec($);while(X!==null){let H=X[1];if(!/<th\b/i.test(H))Y.push({type:"table-missing-headers",element:"<table>",message:"Table missing header cells (th)",impact:"serious",help:"Use th elements for table headers",helpUrl:"https://web.dev/learn/accessibility/more-html/#tables"});X=B.exec($)}let j=/<(video|audio)[^>]*\sautoplay\s[^>]*>/gi;X=j.exec($);while(X!==null){if(!/\bmuted\b/i.test(X[0]))Y.push({type:"autoplay-audio",element:`<${X[1]}>`,message:"Auto-playing media may disrupt users",impact:"moderate",help:"Add muted attribute or provide controls to stop playback",helpUrl:"https://web.dev/learn/accessibility/more-html/#multimedia"});X=j.exec($)}let q=/\btabindex\s*=\s*["']([1-9]\d*)["']/gi;X=q.exec($);while(X!==null)Y.push({type:"positive-tabindex",element:`tabindex="${X[1]}"`,message:"Positive tabindex disrupts natural tab order",impact:"moderate",help:'Use tabindex="0" or "-1" instead of positive values',helpUrl:"https://web.dev/learn/accessibility/focus/#tab-index"}),X=q.exec($);let z=/<iframe\s+([^>]*)>/gi;X=z.exec($);while(X!==null){let H=X[1];if(!/\btitle\s*=/i.test(H)&&!/\baria-label\s*=/i.test(H))Y.push({type:"iframe-missing-title",element:"<iframe>",message:"Iframe missing title attribute",impact:"serious",help:"Add a title attribute to describe the iframe content",helpUrl:"https://web.dev/learn/accessibility/more-html/#frames"});X=z.exec($)}let O=/<([a-z]+)\s+([^>]*role\s*=\s*["']button["'][^>]*)>/gi;X=O.exec($);while(X!==null){let H=X[1].toLowerCase(),V=X[2];if(H!=="button"&&!/\btabindex\s*=/i.test(V))Y.push({type:"button-not-focusable",element:X[0].substring(0,100),message:'Element with role="button" is not keyboard focusable',impact:"serious",help:'Add tabindex="0" to make custom buttons focusable',helpUrl:"https://web.dev/learn/accessibility/focus/"});X=O.exec($)}return Y}async function V7($,Z){if(!SQ())return CQ($,Z);let Y=[];try{let J=globalThis.document.createElement("div");J.innerHTML=$,J.querySelectorAll("img").forEach((K)=>{if(!K.hasAttribute("alt"))Y.push({type:"missing-alt",element:`<${K.outerHTML}>`,message:"Image missing alt attribute",impact:"serious",help:"Add alt text to images for screen readers",helpUrl:"https://web.dev/learn/accessibility/images/"})}),J.querySelectorAll('button, a, [role="button"]').forEach((K)=>{if(!(K.hasAttribute("aria-label")||K.hasAttribute("aria-labelledby")||K.textContent&&K.textContent.trim().length>0))Y.push({type:"missing-accessible-name",element:`<${K.outerHTML}>`,message:"Interactive element missing accessible name",impact:"critical",help:"Add text content, aria-label, or aria-labelledby",helpUrl:"https://web.dev/learn/accessibility/aria-html/"})}),J.querySelectorAll("input, select, textarea").forEach((K)=>{let W=K.getAttribute("id"),_=W&&J.querySelector(`label[for="${W}"]`),U=K.hasAttribute("aria-label")||K.hasAttribute("aria-labelledby"),B=K.closest("label")!==null;if(!_&&!U&&!B)Y.push({type:"input-missing-label",element:`<${K.outerHTML}>`,message:"Form input missing associated label",impact:"serious",help:"Associate a label with the input or use aria-label",helpUrl:"https://web.dev/learn/accessibility/forms/"})});let X=Array.from(J.querySelectorAll("h1, h2, h3, h4, h5, h6")),Q=0;for(let K of X){let W=Number.parseInt(K.tagName.charAt(1));if(Q>0&&W>Q+1)Y.push({type:"heading-skip",element:`<${K.outerHTML}>`,message:`Heading level skipped from h${Q} to h${W}`,impact:"moderate",help:"Maintain proper heading hierarchy without skipping levels",helpUrl:"https://web.dev/learn/accessibility/structure/"});Q=W}let G=J.querySelector("html");if($.includes("<html")&&G&&!G.hasAttribute("lang"))Y.push({type:"missing-lang",element:"<html>",message:"Document language not specified",impact:"serious",help:"Add lang attribute to the html element",helpUrl:"https://web.dev/learn/accessibility/more-html/#language"});if(J.querySelectorAll("a").forEach((K)=>{let W=K.textContent&&K.textContent.trim().length>0,_=K.hasAttribute("aria-label")||K.hasAttribute("aria-labelledby"),U=K.hasAttribute("title"),B=K.querySelector("img[alt]");if(!W&&!_&&!U&&!B)Y.push({type:"link-missing-text",element:`<${K.outerHTML}>`,message:"Link has no accessible text",impact:"serious",help:"Add text content, aria-label, or title to links",helpUrl:"https://web.dev/learn/accessibility/more-html/#links"})}),$.includes("<nav")||$.includes("<header")){if(!J.querySelector('a[href="#main"], a[href="#content"], .skip-link, [class*="skip"]')&&J.querySelectorAll("a").length>5)Y.push({type:"missing-skip-link",element:"<nav>",message:"Consider adding a skip navigation link",impact:"minor",help:"Add a skip link to allow keyboard users to bypass navigation",helpUrl:"https://web.dev/learn/accessibility/focus/#skip-links"})}if(J.querySelectorAll("table").forEach((K)=>{let W=K.querySelector("caption");if(!K.querySelector("th"))Y.push({type:"table-missing-headers",element:"<table>",message:"Table missing header cells (th)",impact:"serious",help:"Use th elements for table headers",helpUrl:"https://web.dev/learn/accessibility/more-html/#tables"});if(!W&&!K.hasAttribute("aria-label")&&!K.hasAttribute("aria-labelledby"))Y.push({type:"table-missing-caption",element:"<table>",message:"Table missing caption or accessible name",impact:"minor",help:"Add a caption element or aria-label to describe the table",helpUrl:"https://web.dev/learn/accessibility/more-html/#tables"})}),J.querySelectorAll('[style*="color"]').forEach((K)=>{let W=K.getAttribute("style")||"";if(W.includes("color:")&&!W.includes("background"))Y.push({type:"potential-contrast-issue",element:`<${K.tagName.toLowerCase()}>`,message:"Element has inline color style - verify contrast ratio",impact:"minor",help:"Ensure text has sufficient contrast ratio (4.5:1 for normal text)",helpUrl:"https://web.dev/learn/accessibility/color-contrast/"})}),J.querySelectorAll("video[autoplay], audio[autoplay]").forEach((K)=>{if(!K.hasAttribute("muted"))Y.push({type:"autoplay-audio",element:`<${K.tagName.toLowerCase()}>`,message:"Auto-playing media may disrupt users",impact:"moderate",help:"Add muted attribute or provide controls to stop playback",helpUrl:"https://web.dev/learn/accessibility/more-html/#multimedia"})}),J.querySelectorAll("[tabindex]").forEach((K)=>{if(Number.parseInt(K.getAttribute("tabindex")||"0")>0)Y.push({type:"positive-tabindex",element:`<${K.tagName.toLowerCase()}>`,message:"Positive tabindex disrupts natural tab order",impact:"moderate",help:'Use tabindex="0" or "-1" instead of positive values',helpUrl:"https://web.dev/learn/accessibility/focus/#tab-index"})}),J.querySelectorAll('[role="button"]').forEach((K)=>{if(!K.hasAttribute("tabindex"))Y.push({type:"button-not-focusable",element:`<${K.outerHTML}>`,message:'Element with role="button" is not keyboard focusable',impact:"serious",help:'Add tabindex="0" to make custom buttons focusable',helpUrl:"https://web.dev/learn/accessibility/focus/"})}),$.includes("<body")&&!J.querySelector('main, [role="main"]'))Y.push({type:"missing-main-landmark",element:"<body>",message:"Document missing main landmark region",impact:"moderate",help:"Add a main element to identify the primary content",helpUrl:"https://web.dev/learn/accessibility/structure/#landmarks"});J.querySelectorAll("iframe").forEach((K)=>{if(!K.hasAttribute("title")&&!K.hasAttribute("aria-label"))Y.push({type:"iframe-missing-title",element:"<iframe>",message:"Iframe missing title attribute",impact:"serious",help:"Add a title attribute to describe the iframe content",helpUrl:"https://web.dev/learn/accessibility/more-html/#frames"})})}catch(J){console.error(`Error checking accessibility in ${Z}:`,J)}return Y}async function q1($,Z={}){let Y={},{recursive:J=!0,ignorePaths:X=[]}=Z,Q=B1.join($,J?"**/*.stx":"*.stx"),G=new Bun.Glob(Q),K=[];for await(let W of G.scan())if(!X.some((U)=>W.includes(B1.normalize(U))))K.push(W);for(let W of K)try{let _=await Bun.file(W).text();if(W.endsWith("good-a11y.stx"))continue;let U=await V7(_,W);if(U.length>0)Y[W]=U}catch(_){console.error(`Error scanning ${W}:`,_)}return Y}var z1,O1;var l6=I(()=>{z1={name:"a11y",handler:($,Z,Y,J)=>{if(!Z.length)return $;let X=Z[0].replace(/['"]/g,""),Q=Z.length>1?Z[1].replace(/['"]/g,""):"",K={"aria-label":"Ensure interactive elements have accessible labels","alt-text":"Provide alternative text for images",focus:"Ensure the element can receive keyboard focus",landmark:"Use appropriate landmark roles","heading-order":"Maintain proper heading hierarchy","color-contrast":"Ensure sufficient color contrast","keyboard-nav":"Make sure element is keyboard navigable","screen-reader":"Optimize for screen reader users"}[X]||"Make this element accessible";return`<!-- a11y-hint: ${Q||K} -->${$}`},hasEndTag:!1},O1={name:"screenReader",handler:($)=>{return`<span class="sr-only">${$}</span>`},hasEndTag:!0}});function bQ($,Z={}){let{duration:Y,delay:J,ease:X,direction:Q,custom:G}={...X6,...Z};if($==="custom"&&G)return G;switch($){case"fade":return`${Q==="in"?"opacity: 0; animation: fadeIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":Q==="out"?"opacity: 1; animation: fadeOut var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":"opacity: 1; transition: opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms);"} @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }`;case"slide":return`${Q==="in"?"transform: translateY(20px); opacity: 0; animation: slideIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":Q==="out"?"transform: translateY(0); opacity: 1; animation: slideOut var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":"transform: translateY(0); opacity: 1; transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms);"} @keyframes slideIn { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes slideOut { from { transform: translateY(0); opacity: 1; } to { transform: translateY(20px); opacity: 0; } }`;case"scale":return`${Q==="in"?"transform: scale(0.95); opacity: 0; animation: scaleIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":Q==="out"?"transform: scale(1); opacity: 1; animation: scaleOut var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":"transform: scale(1); opacity: 1; transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms);"} @keyframes scaleIn { from { transform: scale(0.95); opacity: 0; } to { transform: scale(1); opacity: 1; } } @keyframes scaleOut { from { transform: scale(1); opacity: 1; } to { transform: scale(0.95); opacity: 0; } }`;case"flip":return`${Q==="in"?"transform: perspective(400px) rotateX(-90deg); opacity: 0; animation: flipIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":Q==="out"?"transform: perspective(400px) rotateX(0); opacity: 1; animation: flipOut var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":"transform: perspective(400px) rotateX(0); opacity: 1; transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms);"} @keyframes flipIn { from { transform: perspective(400px) rotateX(-90deg); opacity: 0; } to { transform: perspective(400px) rotateX(0); opacity: 1; } } @keyframes flipOut { from { transform: perspective(400px) rotateX(0); opacity: 1; } to { transform: perspective(400px) rotateX(90deg); opacity: 0; } }`;case"rotate":return`${Q==="in"?"transform: rotate(-90deg); opacity: 0; animation: rotateIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":Q==="out"?"transform: rotate(0); opacity: 1; animation: rotateOut var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":"transform: rotate(0); opacity: 1; transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms);"} @keyframes rotateIn { from { transform: rotate(-90deg); opacity: 0; } to { transform: rotate(0); opacity: 1; } } @keyframes rotateOut { from { transform: rotate(0); opacity: 1; } to { transform: rotate(90deg); opacity: 0; } }`;default:return""}}function PQ(){return` <script data-stx-scoped> // Motion preferences handling (function() { const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (prefersReducedMotion) { // Apply reduced motion settings document.documentElement.style.setProperty('--stx-transition-duration', '0ms'); document.documentElement.setAttribute('data-reduced-motion', 'true'); } else { document.documentElement.setAttribute('data-reduced-motion', 'false'); } // Listen for changes in preference window.matchMedia('(prefers-reduced-motion: reduce)').addEventListener('change', (e) => { if (e.matches) { document.documentElement.style.setProperty('--stx-transition-duration', '0ms'); document.documentElement.setAttribute('data-reduced-motion', 'true'); } else { document.documentElement.style.setProperty('--stx-transition-duration', ''); document.documentElement.setAttribute('data-reduced-motion', 'false'); } }); })(); </script> `}function yQ($){return[/@animate\b/,/@transition\b/,/@scroll(?:Animate)?\b/,/@staggered\b/,/@sequence\b/,/@motion\b/,/@animationGroup\b/,/\bstx-transition\b/,/\bstx-(?:fade|scale|flip|rotate|slide|from-|observe)\b/,/data-animate=['"](?:auto|true|false)['"]/].some((Y)=>Y.test($))}function xQ($=0.1,Z="0px"){return` <script data-stx-scoped> // Intersection Observer for scroll animations (function() { const initObserver = () => { if (!('IntersectionObserver' in window)) { // For browsers that don't support IntersectionObserver, show all elements immediately const elements = document.querySelectorAll('.stx-observe'); elements.forEach(el => el.classList.remove('stx-out')); return; } // Create the observer const options = { root: null, // Use viewport rootMargin: '${Z}', threshold: ${$} }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.remove('stx-out'); // Stop observing after animation is triggered observer.unobserve(entry.target); } }); }, options); // Start observing elements const elements = document.querySelectorAll('.stx-observe'); console.log('Observing', elements.length, 'elements for animations'); elements.forEach(el => observer.observe(el)); }; // Initialize observer when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initObserver); } else { initObserver(); } })(); </script> `}function vQ(){return` <style id="stx-animation-base"> :root { --stx-transition-duration: 300ms; --stx-transition-delay: 0ms; --stx-transition-ease: ease; } @media (prefers-reduced-motion: reduce) { :root { --stx-transition-duration: 0ms; } } [data-animate="false"] * { --stx-transition-duration: 0ms !important; animation-duration: 0ms !important; transition-duration: 0ms !important; } /* Base transition classes */ .stx-transition { transition: opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); backface-visibility: hidden; /* Improve animation performance */ transform-style: preserve-3d; /* Better 3D transforms */ } /* Fade animations */ .stx-fade { transition: opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); } .stx-fade.stx-out { opacity: 0 !important; } /* Scale animations */ .stx-scale { transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); } .stx-scale.stx-out { transform: scale(0.85) !important; opacity: 0 !important; } /* Flip animations */ .stx-flip { transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); perspective: 600px; } .stx-flip.stx-out { transform: perspective(600px) rotateX(-90deg) !important; opacity: 0 !important; } /* Rotate animations */ .stx-rotate { transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); } .stx-rotate.stx-out { transform: rotate(-90deg) !important; opacity: 0 !important; } /* Direction-based animations */ .stx-from-left, .stx-from-right, .stx-from-top, .stx-from-bottom { transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); } .stx-from-left.stx-out { transform: translateX(-30px) !important; opacity: 0 !important; } .stx-from-right.stx-out { transform: translateX(30px) !important; opacity: 0 !important; } .stx-from-top.stx-out { transform: translateY(-30px) !important; opacity: 0 !important; } .stx-from-bottom.stx-out { transform: translateY(30px) !important; opacity: 0 !important; } /* Generic slide animations */ .stx-slide { transition: transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); } .stx-slide.stx-out { transform: translateY(30px) !important; opacity: 0 !important; } /* Scroll animation observer class */ .stx-observe { will-change: opacity, transform; transition: opacity var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms), transform var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms); } </style> `}function gQ($,Z,Y={}){let{staggerDelay:J=50,sequence:X=!1}=Y;return` <script data-stx-scoped> // Animation Group: ${$} (function() { const elements = ${JSON.stringify(Z)}; const staggerDelay = ${J}; const sequence = ${X}; function animateGroup() { elements.forEach((selector, index) => { const element = document.querySelector(selector); if (!element) return; const delay = sequence ? index * staggerDelay : 0; element.style.setProperty('--stx-transition-delay', delay + 'ms'); // For elements using animation keyframes element.style.animationDelay = delay + 'ms'; // If the element is initially hidden, show it if (element.classList.contains('stx-out')) { setTimeout(() => { element.classList.remove('stx-out'); }, 10); // Small delay to ensure styles are applied } }); } // Run when DOM is fully loaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', animateGroup); } else { animateGroup(); } })(); </script> `}function A1($,Z,Y,J){let X=$;if(J.animation?.enabled===!1)return X;let Q=Y.includes("test")&&Y.includes("animation");if(!yQ(X)&&!Q)return X;if(!X.includes('<style id="stx-animation-base">')){let K=vQ();X=X.replace("</head>",`${K} </head>`)}if(X.includes("stx-observe")){if(!X.includes("Intersection Observer for scroll animations")){let W=xQ();X=X.replace("</body>",`${W} </body>`)}}return X}var X6,H1,L1,V1,F1;var m8=I(()=>{X6={duration:300,delay:0,ease:"ease",direction:"both"};H1={name:"transition",handler:($,Z,Y,J)=>{if(Z.length<1)return`<div class="stx-error">@transition directive requires at least a transition type</div>${$}`;let X=Z[0],Q=Z.length>1?Number.parseInt(Z[1],10)||X6.duration:X6.duration,G=Z.length>2?Z[2]||X6.ease:X6.ease,K=Z.length>3?Number.parseInt(Z[3],10)||X6.delay:X6.delay,W=Z.length>4?Z[4]||X6.direction:X6.direction,_=`stx-transition-${Math.random().toString(36).substr(2,9)}`,U=bQ(X,{duration:Q,delay:K,ease:G,direction:W}),B="stx-transition",j="";if(X==="fade")j="stx-fade";else if(X==="slide")j="stx-slide";else if(X==="scale")j="stx-scale";else if(X==="flip")j="stx-flip";else if(X==="rotate")j="stx-rotate";return`<div id="${_}" class="${B} ${j} ${W==="out"?"stx-out":""}" style="--stx-transition-duration: ${Q}ms; --stx-transition-ease: ${G}; --stx-transition-delay: ${K}ms;">${$}</div>`},hasEndTag:!0,description:"Applies transition effects to an element"},L1={name:"scrollAnimate",handler:($,Z,Y,J)=>{if(Z.length<1)return`<div class="stx-error">@scrollAnimate directive requires at least an animation type</div>${$}`;let X=Z[0],Q=Z.length>1?Number.parseInt(Z[1],10)||300:300,G=Z.length>2?Z[2]||"ease":"ease",K=Z.length>3?Number.parseFloat(Z[3])||0.2:0.2,W=Z.length>4?Number.parseInt(Z[4],10)||0:0,_=`stx-scroll-${Math.random().toString(36).substr(2,9)}`,U=`--stx-transition-duration: ${Q}ms; --stx-transition-ease: ${G}; --stx-transition-delay: ${W}ms; will-change: opacity, transform;`,B="stx-transition stx-observe stx-out";if(X==="fade")B+=" stx-fade";else if(X==="slide-up"||X==="slide")B+=" stx-from-bottom";else if(X==="slide-down")B+=" stx-from-top";else if(X==="slide-left")B+=" stx-from-right";else if(X==="slide-right")B+=" stx-from-left";else if(X==="scale")B+=" stx-scale";else if(X.includes("-"))B+=` stx-${X}`;else B+=` stx-${X}`;return`<div id="${_}" class="${B}" style="${U}" data-threshold="${K}">${$}</div>`},hasEndTag:!0,description:"Applies animations that trigger when scrolled into view"},V1={name:"animationGroup",handler:($,Z,Y,J)=>{if(Z.length<2)return`<div class="stx-error">@animationGroup directive requires a group name and at least one element selector</div>${$}`;let X=Z[0],Q=Z.slice(1).map((_)=>_.startsWith("#")||_.startsWith(".")?_:`#${_}`),G=Y.staggerDelay||50,K=Y.sequence||!0,W=gQ(X,Q,{staggerDelay:G,sequence:K});return`${$} ${W}`},hasEndTag:!1,description:"Coordinates multiple animations together as a group"},F1={name:"motion",handler:($,Z,Y,J)=>{let X=Z.length>0?Z[0].toLowerCase()==="true":!0,Q=PQ();return`<div data-animate="${X?"auto":"true"}">${$}</div>${Q}`},hasEndTag:!0,description:"Controls motion and animation preferences"}});class F7{options;cache=new Map;isNavigating=!1;currentUrl;constructor($={}){this.options={container:$.container??"main",linkSelector:$.linkSelector??"a[href]",loadingClass:$.loadingClass??"stx-navigating",viewTransitions:$.viewTransitions??!0,cache:$.cache??!0,scrollToTop:$.scrollToTop??!0,onBeforeNavigate:$.onBeforeNavigate??(()=>!0),onAfterNavigate:$.onAfterNavigate??(()=>{}),onError:$.onError??((Z)=>console.error("[STX Router]",Z))},this.currentUrl=window.location.href}init(){if(document.addEventListener("click",this.handleClick.bind(this)),window.addEventListener("popstate",this.handlePopState.bind(this)),this.options.cache)this.cacheCurrentPage()}async navigate($,Z=!0){if(this.isNavigating)return;let Y=new URL($,window.location.origin);if(Y.href===this.currentUrl)return;if(Y.origin!==window.location.origin){window.location.href=$;return}if(this.options.onBeforeNavigate($)===!1)return;this.isNavigating=!0,document.body.classList.add(this.options.loadingClass);try{let J=await this.fetchPage(Y.href);if(J){if(await this.swapContent(J),Z)window.history.pushState({url:Y.href},"",Y.href);if(this.currentUrl=Y.href,this.options.scrollToTop)window.scrollTo({top:0,behavior:"instant"});this.options.onAfterNavigate(Y.href)}}catch(J){this.options.onError(J,$),window.location.href=$}finally{this.isNavigating=!1,document.body.classList.remove(this.options.loadingClass)}}async prefetch($){let Z=new URL($,window.location.origin);if(Z.origin!==window.location.origin)return;if(this.cache.has(Z.href))return;try{await this.fetchPage(Z.href)}catch{}}clearCache(){this.cache.clear()}handleClick($){let Z=$.target.closest(this.options.linkSelector);if(!Z)return;if($.metaKey||$.ctrlKey||$.shiftKey||$.altKey)return;if($.button!==0)return;if(Z.target&&Z.target!=="_self")return;if(Z.hasAttribute("download"))return;let Y=Z.getAttribute("href");if(!Y||Y.startsWith("#")||Y.startsWith("mailto:")||Y.startsWith("tel:"))return;if(Z.hasAttribute("data-stx-no-router"))return;if(new URL(Y,window.location.origin).origin!==window.location.origin)return;$.preventDefault(),this.navigate(Y)}handlePopState($){let Z=$.state?.url||window.location.href;this.navigate(Z,!1)}async fetchPage($){if(this.options.cache&&this.cache.has($)){let K=this.cache.get($);if(Date.now()-K.timestamp<300000)return{html:K.html,title:K.title};this.cache.delete($)}let Z=await fetch($,{headers:{"X-STX-Router":"true",Accept:"text/html"}});if(!Z.ok)throw Error(`Failed to fetch ${$}: ${Z.status}`);let Y=await Z.text(),X=new DOMParser().parseFromString(Y,"text/html"),Q=X.querySelector(this.options.container);if(!Q)throw Error(`Container "${this.options.container}" not found in response`);let G={html:Q.innerHTML,title:X.title};if(this.options.cache)this.cache.set($,{...G,timestamp:Date.now()});return G}async swapContent($){let Z=document.querySelector(this.options.container);if(!Z)throw Error(`Container "${this.options.container}" not found`);let Y=()=>{Z.innerHTML=$.html,document.title=$.title,Z.querySelectorAll("script").forEach((X)=>{let Q=document.createElement("script");Array.from(X.attributes).forEach((G)=>{Q.setAttribute(G.name,G.value)}),Q.textContent=X.textContent,X.parentNode?.replaceChild(Q,X)}),window.dispatchEvent(new CustomEvent("stx:navigate",{detail:{url:this.currentUrl}}))};if(this.options.viewTransitions&&"startViewTransition"in document)await document.startViewTransition(Y).finished;else Y()}cacheCurrentPage(){let $=document.querySelector(this.options.container);if($)this.cache.set(this.currentUrl,{html:$.innerHTML,title:document.title,timestamp:Date.now()})}}function fQ($){if(i6)return i6;return i6=new F7($),i6.init(),i6}function hQ(){return i6}var i6=null;var R1=I(()=>{if(typeof window<"u")window.STXRouter={init:fQ,get:hQ,Router:F7}});function N1(){return` ;(function(){ 'use strict'; var o={container:'main',linkSelector:'a[href]',loadingClass:'stx-navigating',viewTransitions:!0,cache:!0,scrollToTop:!0,prefetch:!0}; var c=new Map(),p=new Set(),n=!1,u=location.href; function init(){ document.addEventListener('click',handleClick,!0); window.addEventListener('popstate',function(){navigate(location.href,!1)}); document.addEventListener('mouseenter',handleHover,!0); cacheCurrentPage(); injectStyles(); } function navigate(url,push){ if(n)return; var t=new URL(url,location.origin); if(t.href===u&&!t.hash)return; if(t.origin!==location.origin){location.href=url;return} if(t.pathname===new URL(u).pathname&&t.hash){ if(push!==!1)history.pushState({url:t.href},'',t.href); var el=document.querySelector(t.hash);if(el)el.scrollIntoView({behavior:'smooth'});return } n=!0;document.body.classList.add(o.loadingClass); fetchPage(t.href).then(function(r){ if(r){ swapContent(r); if(push!==!1)history.pushState({url:t.href},'',t.href); u=t.href; if(o.scrollToTop&&!t.hash)window.scrollTo({top:0,behavior:'instant'}); else if(t.hash){var el=document.querySelector(t.hash);if(el)el.scrollIntoView({behavior:'smooth'})} } }).catch(function(){location.href=url}).finally(function(){n=!1;document.body.classList.remove(o.loadingClass)}); } function handleClick(e){ var a=e.target.closest('a[href]');if(!a)return; if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button!==0)return; if(a.target&&a.target!=='_self')return;if(a.hasAttribute('download'))return; var h=a.getAttribute('href'); if(!h||h.startsWith('mailto:')||h.startsWith('tel:')||h.startsWith('javascript:'))return; if(a.hasAttribute('data-stx-no-router'))return; var t=new URL(h,location.origin);if(t.origin!==location.origin)return; e.preventDefault();e.stopPropagation();navigate(h); } function handleHover(e){ var a=e.target.closest('a[data-stx-prefetch]');if(!a)return; var h=a.getAttribute('href');if(h&&!c.has(h))fetchPage(new URL(h,location.origin).href).catch(function(){}); } function fetchPage(url){ if(c.has(url)){var x=c.get(url);if(Date.now()-x.t<3e5)return Promise.resolve({h:x.h,i:x.i})} return fetch(url,{headers:{'X-STX-Router':'true'}}).then(function(r){ if(!r.ok)throw new Error(r.status);return r.text() }).then(function(html){ var d=new DOMParser().parseFromString(html,'text/html'),m=d.querySelector(o.container); if(!m)throw new Error('Container not found'); var r={h:m.innerHTML,i:d.title};c.set(url,{h:r.h,i:r.i,t:Date.now()});return r }); } function swapContent(r){ var m=document.querySelector(o.container);if(!m)return; var swap=function(){ m.innerHTML=r.h;document.title=r.i; m.querySelectorAll('script').forEach(function(s){ var n=document.createElement('script'); Array.from(s.attributes).forEach(function(a){n.setAttribute(a.name,a.value)}); n.textContent=s.textContent;s.parentNode.replaceChild(n,s); }); window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:u}})); window.dispatchEvent(new CustomEvent('stx:load')); }; if(o.viewTransitions&&'startViewTransition'in document)document.startViewTransition(swap);else swap(); } function cacheCurrentPage(){var m=document.querySelector(o.container);if(m)c.set(u,{h:m.innerHTML,i:document.title,t:Date.now()})} function injectStyles(){ if(document.getElementById('stx-r-css'))return; var s=document.createElement('style');s.id='stx-r-css'; s.textContent='.stx-navigating{cursor:wait}.stx-navigating *{pointer-events:none}@keyframes stx-l{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.stx-navigating::before{content:\\'\\';position:fixed;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,#78dce8,transparent);animation:stx-l 1s ease-in-out infinite;z-index:99999}'; document.head.appendChild(s); } window.stxRouter={navigate:navigate,clearCache:function(){c.clear()}}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init(); })(); `}var M1=I(()=>{R1();A7()});async function dQ($,Z,Y,J){let X=Z[0]?.replace(/['"]/g,"")||"main",Q=N1();if(X!=="main")Q=Q.replace("container:'main'",`container:'${X}'`);return`<script>${Q}</script>`}var w1;var A7=I(()=>{M1();w1={name:"stxRouter",handler:dQ,hasEndTag:!1,description:"Inject the STX SPA router script for client-side navigation"}});function E1($){let Z=$.heatmap;if(!Z?.enabled)return"";let Y={...uQ,...Z};return` <!-- stx Heatmap - Privacy-Compliant Tracking --> <script> (function() { 'use strict'; // Configuration var config = ${JSON.stringify({trackMouse:Y.trackMouse,trackClicks:Y.trackClicks,trackScroll:Y.trackScroll,samplingRate:Y.samplingRate,honorDnt:Y.honorDnt,endpoint:Y.endpoint,batchSize:Y.batchSize,maxDataPoints:Y.maxDataPoints,sessionTimeout:Y.sessionTimeout,persistData:Y.persistData,storagePrefix:Y.storagePrefix,captureAttributes:Y.captureAttributes,ignoreSelectors:Y.ignoreSelectors,zones:Y.zones,debugOverlay:Y.debugOverlay,minViewportWidth:Y.minViewportWidth,maxViewportWidth:Y.maxViewportWidth})}; // Check Do Not Track if (config.honorDnt && navigator.doNotTrack === '1') { return; } // Check viewport constraints var vw = window.innerWidth; if (config.minViewportWidth && vw < config.minViewportWidth) return; if (config.maxViewportWidth && vw > config.maxViewportWidth) return; // Session management (anonymous, no cookies) var session = { sid: Math.random().toString(36).slice(2) + Date.now().toString(36), page: location.pathname, vw: window.innerWidth, vh: window.innerHeight, points: [], started: Date.now(), lastActivity: Date.now() }; // Throttle helper var lastMove = 0; function throttle(fn, wait) { return function() { var now = Date.now(); if (now - lastMove >= wait) { lastMove = now; fn.apply(this, arguments); } }; } // Get relative coordinates (percentage) function getRelativeCoords(e) { return { x: Math.round((e.clientX / window.innerWidth) * 10000) / 100, y: Math.round((e.clientY / window.innerHeight) * 10000) / 100 }; } // Check if element should be ignored function shouldIgnore(el) { if (!el || !config.ignoreSelectors) return false; for (var i = 0; i < config.ignoreSelectors.length; i++) { if (el.matches && el.matches(config.ignoreSelectors[i])) return true; if (el.closest && el.closest(config.ignoreSelectors[i])) return true; } return false; } // Get element selector (simplified, no IDs to preserve privacy) function getSelector(el) { if (!el || !el.tagName) return null; var tag = el.tagName.toLowerCase(); var classes = el.className && typeof el.className === 'string' ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.') : ''; return tag + classes; } // Find zone for element function findZone(el) { if (!config.zones || !el) return null; for (var i = 0; i < config.zones.length; i++) { var zone = config.zones[i]; if (el.closest && el.closest(zone.selector)) { return zone.id; } } return null; } // Capture custom attributes function captureAttributes(el) { if (!config.captureAttributes || !el) return null; var attrs = {}; var hasAttrs = false; for (var i = 0; i < config.captureAttributes.length; i++) { var attr = config.captureAttributes[i]; var value = el.getAttribute && el.getAttribute(attr); if (value) { attrs[attr] = value; hasAttrs = true; } } return hasAttrs ? attrs : null; } // Add data point function addPoint(point) { session.lastActivity = Date.now(); if (session.points.length >= config.maxDataPoints) { session.points.shift(); } session.points.push(point); // Send batch if threshold reached if (config.endpoint && session.points.length >= config.batchSize) { sendData(); } } // Send data to endpoint function sendData() { if (!config.endpoint || session.points.length === 0) return; var data = { sid: session.sid, page: session.page, vw: session.vw, vh: session.vh, points: session.points.splice(0, config.batchSize) }; // Use sendBeacon for reliability if (navigator.sendBeacon) { navigator.sendBeacon(config.endpoint, JSON.stringify(data)); } else { var xhr = new XMLHttpRequest(); xhr.open('POST', config.endpoint, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.send(JSON.stringify(data)); } } // Mouse move handler if (config.trackMouse) { document.addEventListener('mousemove', throttle(function(e) { if (shouldIgnore(e.target)) return; var coords = getRelativeCoords(e); addPoint({ x: coords.x, y: coords.y, type: 'move', t: Date.now(), zone: findZone(e.target) }); }, config.samplingRate), { passive: true }); } // Click handler if (config.trackClicks) { document.addEventListener('click', function(e) { if (shouldIgnore(e.target)) return; var coords = getRelativeCoords(e); var point = { x: coords.x, y: coords.y, type: 'click', t: Date.now(), el: getSelector(e.target), zone: findZone(e.target) }; var attrs = captureAttributes(e.target); if (attrs) point.attrs = attrs; addPoint(point); }, { passive: true }); } // Scroll handler if (config.trackScroll) { var lastScrollDepth = 0; document.addEventListener('scroll', throttle(function() { var scrollTop = window.pageYOffset || document.documentElement.scrollTop; var scrollHeight = document.documentElement.scrollHeight - window.innerHeight; var depth = scrollHeight > 0 ? Math.round((scrollTop / scrollHeight) * 100) : 0; // Only track significant scroll changes (every 10%) if (Math.abs(depth - lastScrollDepth) >= 10) { lastScrollDepth = depth; addPoint({ x: 50, y: depth, type: 'scroll', t: Date.now(), depth: depth }); } }, config.samplingRate * 2), { passive: true }); } // Send remaining data on page unload window.addEventListener('beforeunload', sendData); window.addEventListener('visibilitychange', function() { if (document.visibilityState === 'hidden') { sendData(); } }); // Persist data to localStorage if enabled if (config.persistData) { var storageKey = config.storagePrefix + '_' + session.page.replace(/\\//g, '_'); // Load existing data try { var stored = localStorage.getItem(storageKey); if (stored) { var parsed = JSON.parse(stored); if (Date.now() - parsed.lastActivity < config.sessionTimeout * 60000) { session.points = parsed.points || []; } } } catch (e) {} // Save periodically setInterval(function() { try { localStorage.setItem(storageKey, JSON.stringify({ points: session.points, lastActivity: session.lastActivity })); } catch (e) {} }, 5000); } // Debug overlay if (config.debugOverlay) { var overlay = document.createElement('div'); overlay.id = 'stx-heatmap-overlay'; overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:999999;'; document.body.appendChild(overlay); var canvas = document.createElement('canvas'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.style.cssText = 'width:100%;height:100%;'; overlay.appendChild(canvas); var ctx = canvas.getContext('2d'); function renderOverlay() { ctx.clearRect(0, 0, canvas.width, canvas.height); session.points.forEach(function(p) { var x = (p.x / 100) * canvas.width; var y = (p.y / 100) * canvas.height; ctx.beginPath(); ctx.arc(x, y, p.type === 'click' ? 8 : 3, 0, Math.PI * 2); ctx.fillStyle = p.type === 'click' ? 'rgba(255,0,0,0.5)' : 'rgba(0,0,255,0.2)'; ctx.fill(); }); requestAnimationFrame(renderOverlay); } renderOverlay(); window.addEventListener('resize', function() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); } // Expose API for manual tracking and data export window.stxHeatmap = { // Get current session data getData: function() { return { sid: session.sid, page: session.page, vw: session.vw, vh: session.vh, points: session.points.slice(), started: session.started, lastActivity: session.lastActivity }; }, // Export data as JSON exportJSON: function() { return JSON.stringify(this.getData(), null, 2); }, // Export data as CSV exportCSV: function() { var data = this.getData(); var lines = ['x,y,type,timestamp,element,zone,depth']; data.points.forEach(function(p) { lines.push([p.x, p.y, p.type, p.t, p.el || '', p.zone || '', p.depth || ''].join(',')); }); return lines.join('\\n'); }, // Manual data send flush: function() { sendData(); }, // Clear data clear: function() { session.points = []; if (config.persistData) { var storageKey = config.storagePrefix + '_' + session.page.replace(/\\//g, '_'); try { localStorage.removeItem(storageKey); } catch (e) {} } }, // Add custom event track: function(type, data) { addPoint({ x: data && data.x || 0, y: data && data.y || 0, type: type, t: Date.now(), attrs: data }); }, // Generate heatmap visualization visualize: function(options) { options = options || {}; var data = this.getData(); var width = options.width || data.vw; var height = options.height || data.vh; var radius = options.radius || 20; var blur = options.blur || 15; var maxOpacity = options.maxOpacity || 0.6; var canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; var ctx = canvas.getContext('2d'); // Create heat points data.points.forEach(function(p) { var x = (p.x / 100) * width; var y = (p.y / 100) * height; var intensity = p.type === 'click' ? 1 : 0.3; var gradient = ctx.createRadialGradient(x, y, 0, x, y, radius); gradient.addColorStop(0, 'rgba(255,0,0,' + intensity + ')'); gradient.addColorStop(1, 'rgba(255,0,0,0)'); ctx.fillStyle = gradient; ctx.fillRect(x - radius, y - radius, radius * 2, radius * 2); }); // Apply blur ctx.filter = 'blur(' + blur + 'px)'; ctx.drawImage(canvas, 0, 0); ctx.filter = 'none'; // Colorize var imageData = ctx.getImageData(0, 0, width, height); var pixels = imageData.data; for (var i = 0; i < pixels.length; i += 4) { var alpha = pixels[i + 3]; if (alpha > 0) { var ratio = alpha / 255; // Gradient: blue -> cyan -> green -> yellow -> red if (ratio < 0.25) { pixels[i] = 0; pixels[i + 1] = Math.round(ratio * 4 * 255); pixels[i + 2] = 255; } else if (ratio < 0.5) { pixels[i] = 0; pixels[i + 1] = 255; pixels[i + 2] = Math.round((1 - (ratio - 0.25) * 4) * 255); } else if (ratio < 0.75) { pixels[i] = Math.round((ratio - 0.5) * 4 * 255); pixels[i + 1] = 255; pixels[i + 2] = 0; } else { pixels[i] = 255; pixels[i + 1] = Math.round((1 - (ratio - 0.75) * 4) * 255); pixels[i + 2] = 0; } pixels[i + 3] = Math.round(alpha * maxOpacity); } } ctx.putImageData(imageData, 0, 0); return canvas; } }; })(); </script> `}function T1($,Z){let Y=E1(Z);if(!Y)return $;if($.includes("</body>"))return $.replace("</body>",`${Y}</body>`);return $+Y}function mQ($){let Z={},Y=$.match(/(\w+)=["']?([^"'\s]+)["']?/g)||[];for(let J of Y){let[X,Q]=J.split("="),G=Q?.replace(/["']/g,"");switch(X){case"endpoint":Z.endpoint=G;break;case"samplingRate":Z.samplingRate=Number.parseInt(G,10);break;case"batchSize":Z.batchSize=Number.parseInt(G,10);break;case"trackMouse":Z.trackMouse=G==="true";break;case"trackClicks":Z.trackClicks=G==="true";break;case"trackScroll":Z.trackScroll=G==="true";break;case"honorDnt":Z.honorDnt=G==="true";break;case"debugOverlay":Z.debugOverlay=G==="true";break}}return Z}var uQ,I1;var p8=I(()=>{uQ={enabled:!1,trackMouse:!0,trackClicks:!0,trackScroll:!0,samplingRate:100,honorDnt:!0,batchSize:50,maxDataPoints:1000,sessionTimeout:30,persistData:!1,storagePrefix:"stx_heatmap",captureAttributes:["data-heatmap-id","data-track"],ignoreSelectors:["[data-heatmap-ignore]",".heatmap-ignore"],debugOverlay:!1};I1={name:"heatmap",hasEndTag:!1,description:"Inject privacy-compliant heatmap tracking script",handler:async($,Z,Y,J)=>{let X=Y.__stx_config||{};if(Z.length>0){let Q=mQ(Z.join(" "));X.heatmap={...X.heatmap,...Q,enabled:!0}}return E1(X)}}});function D1($){let Z=/^---\r?\n([\s\S]*?)\r?\n---\r?\n/,Y=$.match(Z);if(!Y)return{data:{},content:$.trim()};let J=Y[1],X=$.slice(Y[0].length),Q={};for(let G of J.split(` `)){let K=G.trim();if(!K||K.startsWith("#"))continue;let W=K.indexOf(":");if(W===-1)continue;let _=K.slice(0,W).trim(),U=K.slice(W+1).trim();if(typeof U==="string"){if(U.startsWith('"')&&U.endsWith('"')||U.startsWith("'")&&U.endsWith("'"))U=U.slice(1,-1);else if(U.startsWith("[")&&U.endsWith("]"))try{U=JSON.parse(U)}catch{}else if(U==="true")U=!0;else if(U==="false")U=!1;else if(/^-?\d+(?:\.\d+)?$/.test(U))U=Number(U)}Q[_]=U}return{data:Q,content:X.trim()}}function N0($,Z={}){let{gfm:Y=!0,breaks:J=!1}=Z,X=$,Q=[];if(X=X.replace(/```(\w*)\n([\s\S]*?)```/g,(j,q,z)=>{let O=Q.lengt