UNPKG

@stacksjs/stx

Version:

A performant UI Framework. Powered by Bun.

1,116 lines (1,007 loc) 476 kB
// @bun var t3=Object.defineProperty;var t=(Z,$)=>{for(var Y in $)t3(Z,Y,{get:$[Y],enumerable:!0,configurable:!0,set:(J)=>$[Y]=()=>J})};var I=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var KZ=import.meta.require;var UZ;var a7=I(()=>{UZ={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",underscore:"\x1B[4m",blink:"\x1B[5m",reverse:"\x1B[7m",hidden:"\x1B[8m",black:"\x1B[30m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",white:"\x1B[37m",gray:"\x1B[90m",bgBlack:"\x1B[40m",bgRed:"\x1B[41m",bgGreen:"\x1B[42m",bgYellow:"\x1B[43m",bgBlue:"\x1B[44m",bgMagenta:"\x1B[45m",bgCyan:"\x1B[46m",bgWhite:"\x1B[47m",bgGray:"\x1B[100m"}});import Z0 from"fs";import _Z from"path";async function e7(Z){try{let $=await import(Z);if($&&$.CSSGenerator)return{CSSGenerator:$.CSSGenerator,config:$.config,build:$.build,defaultConfig:$.defaultConfig}}catch{}return null}function $1(){let Z=[],$=process.env.HOME||process.env.USERPROFILE||"",Y=process.cwd();while(Y!==_Z.dirname(Y))Z.push(_Z.join(Y,"node_modules","@cwcss","crosswind","dist","index.js")),Z.push(_Z.join(Y,"node_modules","@cwcss","crosswind","src","index.ts")),Z.push(_Z.join(Y,"node_modules","@stacksjs","crosswind","dist","index.js")),Y=_Z.dirname(Y);if($){let J=[_Z.join($,"Code","Tools","crosswind","packages","crosswind","dist","index.js"),_Z.join($,"Code","Tools","crosswind","packages","crosswind","src","index.ts"),_Z.join($,"repos","stacks-org","crosswind","packages","crosswind","dist","index.js"),_Z.join($,"repos","stacks-org","crosswind","packages","crosswind","src","index.ts"),_Z.join($,"Code","Tools","stx","packages","stx","node_modules","@cwcss","crosswind","dist","index.js"),_Z.join($,"Code","Tools","stx","packages","stx","node_modules","@stacksjs","crosswind","dist","index.js")];Z.push(...J)}return Z.push(_Z.join(process.cwd(),"..","crosswind","packages","crosswind","dist","index.js")),Z.push(_Z.join(process.cwd(),"..","crosswind","packages","crosswind","src","index.ts")),Z}async function Y1(){if(t7)return Q4;t7=!0;try{let Z=["@cwcss/crosswind","@cwcss/crosswind/dist/index.js","@stacksjs/crosswind","@stacksjs/crosswind/dist/index.js"];for(let Y of Z){let J=await e7(Y);if(J)return Q4=J,console.log(`${UZ.green}[Crosswind]${UZ.reset} CSS engine loaded`),Q4}let $=$1();for(let Y of $)if(Z0.existsSync(Y)){let J=await e7(Y);if(J)return Q4=J,console.log(`${UZ.green}[Crosswind]${UZ.reset} CSS engine loaded from ${_Z.dirname(_Z.dirname(Y))}`),Q4}throw Error("Crosswind CSSGenerator not found in any location")}catch{return console.warn(`${UZ.yellow}[Crosswind] CSS engine not available, Tailwind styles will not be generated${UZ.reset}`),console.warn(`${UZ.yellow}Run 'bun add @stacksjs/crosswind' to enable CSS generation${UZ.reset}`),null}}async function J1(Z){let $=["crosswind.config.ts","crosswind.config.js","crosswind.config.mjs"];for(let Y of $){let J=_Z.join(Z,Y);if(Z0.existsSync(J))try{let G=await import(J),X=G.default||G;return console.log(`${UZ.green}[Crosswind]${UZ.reset} Loaded config from ${Y}`),X}catch(G){console.warn(`${UZ.yellow}[Crosswind]${UZ.reset} Failed to load ${Y}:`,G)}}return null}function X1(Z){let $=/class\s*=\s*["']([^"']+)["']/gi,Y=new Set,J=$.exec(Z);while(J!==null){let G=J[1];for(let X of G.split(/\s+/))if(X.trim())Y.add(X.trim());J=$.exec(Z)}return Y}async function G1(Z){try{let $=await Y1();if(!$)return"";let Y=X1(Z);if(Y.size===0)return"";if(!L5)L5=await J1(process.cwd());let J=$.defaultConfig||$.config,G=L5||{},X=J.theme||{},K=(G.theme||{}).extend||{},q={...X};if(Object.keys(K).length>0)q.extend=K;let _=[...J.safelist||[],...G.safelist||[]],j={...J,...G,content:[],output:"",preflight:!0,minify:!1,theme:q,safelist:_},B=new $.CSSGenerator(j);for(let W of _)B.generate(W);for(let W of Y)B.generate(W);return B.toCSS(!0,!1)}catch($){return console.warn("Failed to generate Crosswind CSS:",$),""}}async function $0(Z){let $=await G1(Z);if(!$)return Z;let Y=`<style data-crosswind="generated"> ${$} </style>`;if(Z.includes("</head>"))return Z.replace("</head>",`${Y} </head>`);if(Z.includes("<body"))return Z.replace(/<body([^>]*)>/,`<body$1> ${Y}`);return Y+Z}var Q4=null,t7=!1,L5=null;var Y0=I(()=>{a7()});function J0(Z,$,Y,J){let G=Z;G=G.replace(/@a11y\(\s*['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"]\s*)?\)/g,(Q,K,q)=>{let j={"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: ${q||j} -->`});let X=/@screenReader\(([^@]*)\)@endScreenReader/g;return G=G.replace(X,(Q,K)=>{return`<span class="sr-only">${K.trim()}</span>`}),G=G.replace(/@ariaDescribe\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]\s*\)/g,(Q,K,q)=>{return`<span id="${`desc-${K}`}" class="sr-only">${q}</span>`}),G}var X0,G0;var F5=I(()=>{X0={name:"a11y",handler:(Z,$,Y,J)=>{if(!$.length)return Z;let G=$[0].replace(/['"]/g,""),X=$.length>1?$[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"}[G]||"Make this element accessible";return`<!-- a11y-hint: ${X||K} -->${Z}`},hasEndTag:!1},G0={name:"screenReader",handler:(Z)=>{return`<span class="sr-only">${Z}</span>`},hasEndTag:!0}});function Q0(){return` // STX Lifecycle Runtime (function() { if (typeof window === 'undefined') return; const instances = new Map(); let currentInstance = null; let idCounter = 0; function generateId() { return 'stx-' + (++idCounter) + '-' + Date.now().toString(36); } function createInstance(element) { const instance = { id: generateId(), element: element, mountHooks: [], destroyHooks: [], updateHooks: [], refs: new Map(), watchers: [], isMounted: false }; instances.set(instance.id, instance); return instance; } window.STX = window.STX || {}; // Lifecycle hooks window.STX.onMount = function(hook) { if (currentInstance) currentInstance.mountHooks.push(hook); }; window.STX.onDestroy = function(hook) { if (currentInstance) currentInstance.destroyHooks.push(hook); }; window.STX.onUpdate = function(hook) { if (currentInstance) currentInstance.updateHooks.push(hook); }; // Aliases window.STX.onMounted = window.STX.onMount; window.STX.onUnmounted = window.STX.onDestroy; window.STX.onUpdated = window.STX.onUpdate; // Refs window.STX.ref = function(initialValue) { const r = { value: initialValue || null }; Object.defineProperty(r, 'current', { get: function() { return this.value; } }); if (currentInstance) { currentInstance.refs.set('ref-' + currentInstance.refs.size, r); } return r; }; // Watch window.STX.watch = function(source, callback, options) { options = options || {}; let oldValue; let cleanup; let isActive = true; function run() { if (!isActive) return; const newValue = source(); if (oldValue !== newValue || options.immediate) { if (cleanup) cleanup(); cleanup = callback(newValue, oldValue); oldValue = newValue; } } if (options.immediate) { run(); } else { oldValue = source(); } const intervalId = setInterval(run, 16); function stop() { isActive = false; clearInterval(intervalId); if (cleanup) cleanup(); } if (currentInstance) { currentInstance.watchers.push({ stop: stop }); currentInstance.destroyHooks.push(stop); } return stop; }; // Computed window.STX.computed = function(getter) { let cached; let dirty = true; return { get value() { if (dirty) { cached = getter(); dirty = false; queueMicrotask(function() { dirty = true; }); } return cached; } }; }; // Component management window.STX.setupComponent = function(element, setup) { const instance = createInstance(element); currentInstance = instance; try { setup(); } finally { currentInstance = null; } return instance; }; window.STX.mountComponent = function(instance) { if (instance.isMounted) return; instance.isMounted = true; instance.mountHooks.forEach(function(hook) { try { const cleanup = hook(); if (typeof cleanup === 'function') { instance.destroyHooks.push(cleanup); } } catch (e) { console.error('[stx] onMount error:', e); } }); }; window.STX.destroyComponent = function(instance) { if (!instance.isMounted) return; instance.watchers.forEach(function(w) { w.stop(); }); instance.destroyHooks.forEach(function(hook) { try { hook(); } catch (e) { console.error('[stx] onDestroy error:', e); } }); instance.refs.forEach(function(ref) { ref.value = null; }); instance.isMounted = false; instances.delete(instance.id); }; // ========================================================================== // Vue-Style Refs System - No document.** required! // ========================================================================== // Internal: Query for ref elements without exposing document API function queryRef(name, root) { return (root || document).querySelector('[data-stx-ref="' + name + '"], [data-ref="' + name + '"]'); } function queryAllRefs(root) { return (root || document).querySelectorAll('[data-stx-ref], [data-ref]'); } // Auto-bind refs from ref attributes (Vue-style) window.STX.bindRefs = function(root, refs) { if (!root) return; queryAllRefs(root).forEach(function(el) { var refName = el.getAttribute('data-stx-ref') || el.getAttribute('data-ref'); if (refs[refName]) { refs[refName].value = el; } }); }; // Vue-style useRefs() - returns object with all refs as direct elements // Usage: const { input, button, container } = STX.useRefs() window.STX.useRefs = function(root) { var refs = {}; queryAllRefs(root).forEach(function(el) { var refName = el.getAttribute('data-stx-ref') || el.getAttribute('data-ref'); if (refName) { refs[refName] = el; } }); return refs; }; // Get a single ref by name - Vue's useTemplateRef equivalent // Usage: const input = STX.useRef('input') window.STX.useRef = function(name, root) { return queryRef(name, root); }; // Two-way binding helper for form elements // Usage: STX.model(inputEl, state, 'username') window.STX.model = function(el, state, key) { if (!el || !state) return; var isCheckbox = el.type === 'checkbox'; var isRadio = el.type === 'radio'; var isSelect = el.tagName === 'SELECT'; // Set initial value if (isCheckbox) { el.checked = !!state[key]; } else if (isRadio) { el.checked = el.value === state[key]; } else { el.value = state[key] || ''; } // Listen for changes var eventType = isCheckbox || isRadio ? 'change' : 'input'; el.addEventListener(eventType, function() { if (isCheckbox) { state[key] = el.checked; } else if (isRadio) { if (el.checked) state[key] = el.value; } else { state[key] = el.value; } }); // Return cleanup function return function() { el.removeEventListener(eventType, arguments.callee); }; }; // Batch event binding helper - cleaner than manual addEventListener // Usage: STX.on({ click: [btn1, btn2], input: [textField] }, handler) window.STX.on = function(el, event, handler) { if (!el) return function() {}; el.addEventListener(event, handler); return function() { el.removeEventListener(event, handler); }; }; // Bind multiple events at once // Usage: STX.events(refs.btn, { click: handleClick, mouseenter: handleHover }) window.STX.events = function(el, eventMap) { if (!el) return function() {}; var cleanups = []; Object.keys(eventMap).forEach(function(event) { el.addEventListener(event, eventMap[event]); cleanups.push(function() { el.removeEventListener(event, eventMap[event]); }); }); return function() { cleanups.forEach(function(c) { c(); }); }; }; // ========================================================================== // DOM Helpers - Eliminate document.* usage // ========================================================================== // Global keyboard event listener // Usage: STX.onKey('Escape', () => closeModal()) window.STX.onKey = function(key, handler, options) { var listener = function(e) { if (e.key === key) { handler(e); } }; document.addEventListener('keydown', listener, options); return function() { document.removeEventListener('keydown', listener, options); }; }; // Create element helper // Usage: STX.el('div', { class: 'foo' }, 'text content') window.STX.el = function(tag, attrs, content) { var el = document.createElement(tag); if (attrs) { Object.keys(attrs).forEach(function(key) { if (key === 'class') { el.className = attrs[key]; } else if (key.startsWith('on')) { el.addEventListener(key.slice(2).toLowerCase(), attrs[key]); } else { el.setAttribute(key, attrs[key]); } }); } if (content) { if (typeof content === 'string') { el.textContent = content; } else if (Array.isArray(content)) { content.forEach(function(child) { el.appendChild(child); }); } else { el.appendChild(content); } } return el; }; // Get currently focused element // Usage: const focused = STX.activeElement() window.STX.activeElement = function() { return document.activeElement; }; // Escape HTML helper // Usage: const safe = STX.escapeHtml(userInput) window.STX.escapeHtml = function(text) { var div = document.createElement('div'); div.textContent = text; return div.innerHTML; }; // MutationObserver for automatic lifecycle management const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // Handle removed nodes mutation.removedNodes.forEach(function(node) { if (node.nodeType === 1 && node.__stx_instance__) { window.STX.destroyComponent(node.__stx_instance__); } }); }); }); // Start observing when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { observer.observe(document.body, { childList: true, subtree: true }); }); } else { observer.observe(document.body, { childList: true, subtree: true }); } console.log('[stx] Lifecycle runtime initialized'); })(); `}function A5(Z){return Symbol(Z)}var xG,vG,fG;var K0=I(()=>{xG=A5("theme"),vG=A5("router"),fG=A5("i18n")});import*as _0 from"crypto";function q0(Z){let $=/\$(\w+)\./g,Y=[],J;while((J=$.exec(Z))!==null)if(!Y.includes(J[1]))Y.push(J[1]);return Y}function Q1(){return`stx-${_0.randomBytes(4).toString("hex")}`}function K1(Z){return/\$\w+\./.test(Z)}function q1(Z){let $=[],Y=new Set,J=/<(\w+)([^>]*?)(\s*\/?>)/g,G=Z;return G=G.replace(J,(X,Q,K,q)=>{if(["script","style","template"].includes(Q.toLowerCase()))return X;let _=[],j=!1,B=K,W=/(\w+(?:-\w+)*)\s*=\s*"([^"]*\{\{[^}]*\$\w+[^}]*\}\}[^"]*)"/g,U=[...K.matchAll(W)];for(let L of U){let F=L[0],O=L[1],A=L[2];if(K1(A)){j=!0;let M=A.match(/\{\{\s*([\s\S]+?)\s*\}\}/);if(M){let V=M[1];if(_.push({attr:O,expr:V,fullMatch:F,originalAttr:O}),q0(V).forEach((N)=>Y.add(N)),O==="text")B=B.replace(F,"");else if(O==="class")B=B.replace(F,'class=""');else if(O==="disabled"||O==="hidden")B=B.replace(F,"");else B=B.replace(F,`${O}=""`)}}}if(!j)return X;let z=B.match(/\bid\s*=\s*"([^"]+)"/),H;if(z)H=z[1];else H=Q1(),B=` id="${H}"${B}`;for(let L of _)$.push({elementId:H,attribute:L.attr,expression:L.expr,stores:q0(L.expr)});return`<${Q}${B}${q}`}),{html:G,bindings:$,stores:Y}}function _1(Z,$){if(Z.length===0)return"";let Y=Array.from($),J=` <script> (function() { 'use strict'; // Wait for stores to be available function initBindings() { var stores = window.VoideStores; if (!stores) { setTimeout(initBindings, 10); return; } // Store references for expressions var $state = {}; `;for(let G of Y)J+=` $state.${G} = stores.${G} ? stores.${G}.get() : {}; `;J+=` // Binding update functions function updateBindings() { `;for(let G of Z){let{elementId:X,attribute:Q,expression:K}=G,q=K.replace(/\$(\w+)\./g,"$state.$1.");if(Q==="text")J+=` (function() { var el = document.getElementById('${X}'); if (el) { try { el.textContent = ${q}; } catch(e) { console.error('Binding error:', e); } } })(); `;else if(Q==="html")J+=` (function() { var el = document.getElementById('${X}'); if (el) { try { el.innerHTML = ${q}; } catch(e) { console.error('Binding error:', e); } } })(); `;else if(Q==="class")J+=` (function() { var el = document.getElementById('${X}'); if (el) { try { var value = ${q}; if (typeof value === 'string') { // Dynamic class string - merge with existing static classes var staticClasses = el.getAttribute('data-static-class') || el.className; if (!el.hasAttribute('data-static-class')) { el.setAttribute('data-static-class', el.className); } el.className = (el.getAttribute('data-static-class') + ' ' + value).trim(); } else if (typeof value === 'object') { // Object syntax: { 'class-name': condition } for (var cls in value) { if (value[cls]) { el.classList.add(cls); } else { el.classList.remove(cls); } } } } catch(e) { console.error('Binding error:', e); } } })(); `;else if(Q==="show")J+=` (function() { var el = document.getElementById('${X}'); if (el) { try { el.style.display = (${q}) ? '' : 'none'; } catch(e) { console.error('Binding error:', e); } } })(); `;else if(Q==="if")J+=` (function() { var el = document.getElementById('${X}'); if (el) { try { el.style.visibility = (${q}) ? 'visible' : 'hidden'; } catch(e) { console.error('Binding error:', e); } } })(); `;else J+=` (function() { var el = document.getElementById('${X}'); if (el) { try { var value = ${q}; if (value === false || value === null || value === undefined) { el.removeAttribute('${Q}'); } else if (value === true) { el.setAttribute('${Q}', ''); } else { el.setAttribute('${Q}', value); } } catch(e) { console.error('Binding error:', e); } } })(); `}J+=` } // Subscribe to stores and update on changes `;for(let G of Y)J+=` if (stores.${G}) { stores.${G}.subscribe(function(state) { $state.${G} = state; updateBindings(); }); } `;return J+=` // Initial update updateBindings(); } // Start when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initBindings); } else { initBindings(); } })(); </script> `,J}function j0(Z){let{html:$,bindings:Y,stores:J}=q1(Z);if(Y.length===0)return Z;let G=_1(Y,J);if($.includes("</body>"))return $.replace("</body>",`${G}</body>`);return $+G}var B0=()=>{};function j1(Z){let $=Z.analytics;if(!$?.enabled)return"";switch($.driver){case"fathom":return B1($);case"google-analytics":return W1($);case"plausible":return z1($);case"self-hosted":return U1($);case"custom":return H1($);default:return""}}function B1(Z){let $=Z.fathom;if(!$?.siteId)return"";let Y=$.scriptUrl||"https://cdn.usefathom.com/script.js",J=$.defer!==!1?" defer":"",G=[`data-site="${HZ($.siteId)}"`];if($.honorDnt)G.push('data-honor-dnt="true"');if($.spa)G.push('data-spa="auto"');if($.canonical)G.push(`data-canonical="${HZ($.canonical)}"`);if($.auto===!1)G.push('data-auto="false"');return` <!-- Fathom Analytics --> <script src="${HZ(Y)}" ${G.join(" ")}${J}></script> `}function W1(Z){let $=Z.googleAnalytics;if(!$?.measurementId)return"";let Y=HZ($.measurementId),J=$.debug?`gtag('config', '${Y}', { 'debug_mode': true });`:"";return` <!-- Google Analytics --> <script async src="https://www.googletagmanager.com/gtag/js?id=${Y}"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${Y}'); ${J} </script> `}function z1(Z){let $=Z.plausible;if(!$?.domain)return"";let Y=$.scriptUrl||"https://plausible.io/js/script.js",J=[`data-domain="${HZ($.domain)}"`],G=Y,X=[];if($.trackLocalhost)X.push("local");if($.hashMode)X.push("hash");if(X.length>0&&Y==="https://plausible.io/js/script.js")G=`https://plausible.io/js/script.${X.join(".")}.js`;return` <!-- Plausible Analytics --> <script defer data-domain="${HZ($.domain)}" src="${HZ(G)}"></script> `}function U1(Z){let $=Z.selfHosted;if(!$?.siteId||!$?.apiEndpoint)return"";let Y=HZ($.siteId),J=HZ($.apiEndpoint),G=$.honorDnt?'if(n.doNotTrack==="1")return;':"",X=$.trackHashChanges?"w.addEventListener('hashchange',pv);":"",Q=$.trackOutboundLinks?` d.addEventListener('click',function(e){ var a=e.target.closest('a'); if(a&&a.hostname!==location.hostname){ t('outbound',{url:a.href}); } });`:"";return` <!-- Self-Hosted Analytics --> <script data-site="${Y}" data-api="${J}" defer> (function(){ 'use strict'; var d=document,w=window,n=navigator,s=d.currentScript; var site=s.dataset.site,api=s.dataset.api; ${G} var q=[],sid=Math.random().toString(36).slice(2); function t(e,p){ var x=new XMLHttpRequest(); x.open('POST',api+'/collect',true); x.setRequestHeader('Content-Type','application/json'); x.send(JSON.stringify({ s:site,sid:sid,e:e,p:p||{}, u:location.href,r:d.referrer,t:d.title, sw:screen.width,sh:screen.height })); } function pv(){t('pageview');} ${X} ${Q} if(d.readyState==='complete')pv(); else w.addEventListener('load',pv); w.stxAnalytics={track:function(n,v){t('event',{name:n,value:v});}}; })(); </script> `}function H1(Z){let $=Z.custom;if(!$)return"";if($.inlineScript)return` <!-- Custom Analytics --> <script> ${$.inlineScript} </script> `;if(!$.scriptUrl)return"";let Y=[];if($.scriptId)Y.push(`id="${HZ($.scriptId)}"`);if($.attributes)for(let[G,X]of Object.entries($.attributes))Y.push(`${HZ(G)}="${HZ(X)}"`);return` <!-- Custom Analytics --> <script${Y.length>0?` ${Y.join(" ")}`:""} src="${HZ($.scriptUrl)}" defer></script> `}function W0(Z,$){let Y=j1($);if(!Y)return Z;if(!Z.includes("</head>")){if(Z.includes("</body>"))return Z.replace("</body>",`${Y}</body>`);return Z+Y}return Z.replace("</head>",`${Y}</head>`)}function HZ(Z){return Z.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var z0=()=>{};function U0(Z){let $=Z.heatmap;if(!$?.enabled)return"";let Y={...O1,...$};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 H0(Z,$){let Y=U0($);if(!Y)return Z;if(Z.includes("</body>"))return Z.replace("</body>",`${Y}</body>`);return Z+Y}function L1(Z){let $={},Y=Z.match(/(\w+)=["']?([^"'\s]+)["']?/g)||[];for(let J of Y){let[G,X]=J.split("="),Q=X?.replace(/["']/g,"");switch(G){case"endpoint":$.endpoint=Q;break;case"samplingRate":$.samplingRate=Number.parseInt(Q,10);break;case"batchSize":$.batchSize=Number.parseInt(Q,10);break;case"trackMouse":$.trackMouse=Q==="true";break;case"trackClicks":$.trackClicks=Q==="true";break;case"trackScroll":$.trackScroll=Q==="true";break;case"honorDnt":$.honorDnt=Q==="true";break;case"debugOverlay":$.debugOverlay=Q==="true";break}}return $}var O1,O0;var R5=I(()=>{O1={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};O0={name:"heatmap",hasEndTag:!1,description:"Inject privacy-compliant heatmap tracking script",handler:async(Z,$,Y,J)=>{let G=Y.__stx_config||{};if($.length>0){let X=L1($.join(" "));G.heatmap={...G.heatmap,...X,enabled:!0}}return U0(G)}}});function F1(Z,$={}){let{duration:Y,delay:J,ease:G,direction:X,custom:Q}={...IZ,...$};if(Z==="custom"&&Q)return Q;switch(Z){case"fade":return`${X==="in"?"opacity: 0; animation: fadeIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":X==="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`${X==="in"?"transform: translateY(20px); opacity: 0; animation: slideIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":X==="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`${X==="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;":X==="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`${X==="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;":X==="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`${X==="in"?"transform: rotate(-90deg); opacity: 0; animation: rotateIn var(--stx-transition-duration, 300ms) var(--stx-transition-ease, ease) var(--stx-transition-delay, 0ms) forwards;":X==="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 A1(){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 R1(Z){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(Z))}function N1(Z=0.1,$="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: '${$}', threshold: ${Z} }; 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 V1(){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 M1(Z,$,Y={}){let{staggerDelay:J=50,sequence:G=!1}=Y;return` <script data-stx-scoped> // Animation Group: ${Z} (function() { const elements = ${JSON.stringify($)}; const staggerDelay = ${J}; const sequence = ${G}; 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 N0(Z,$,Y,J){let G=Z;if(J.animation?.enabled===!1)return G;let X=Y.includes("test")&&Y.includes("animation");if(!R1(G)&&!X)return G;if(!G.includes('<style id="stx-animation-base">')){let K=V1();G=G.replace("</head>",`${K} </head>`)}if(G.includes("stx-observe")){if(!G.includes("Intersection Observer for scroll animations")){let q=N1();G=G.replace("</body>",`${q} </body>`)}}return G}var IZ,L0,F0,A0,R0;var N5=I(()=>{IZ={duration:300,delay:0,ease:"ease",direction:"both"};L0={name:"transition",handler:(Z,$,Y,J)=>{if($.length<1)return`<div class="stx-error">@transition directive requires at least a transition type</div>${Z}`;let G=$[0],X=$.length>1?Number.parseInt($[1],10)||IZ.duration:IZ.duration,Q=$.length>2?$[2]||IZ.ease:IZ.ease,K=$.length>3?Number.parseInt($[3],10)||IZ.delay:IZ.delay,q=