@stacksjs/stx
Version:
A performant UI Framework. Powered by Bun.
694 lines (630 loc) • 863 kB
JavaScript
#!/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