@li2/analytics 0.3.1-beta.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- "use strict";var li2Analytics=(()=>{var g=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var U=(a,t)=>{for(var e in t)g(a,e,{get:t[e],enumerable:!0})},R=(a,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of H(t))!L.call(a,i)&&i!==e&&g(a,i,{get:()=>t[i],enumerable:!(o=S(t,i))||o.enumerable});return a};var D=a=>R(g({},"__esModule",{value:!0}),a);var I={};U(I,{ToolbarManager:()=>f});async function x(a){let t=new URL(`${a.apiUrl}/api/v1/track/heatmap/clicks`);t.searchParams.set("page_path",a.pagePath),t.searchParams.set("from",a.from),t.searchParams.set("to",a.to),t.searchParams.set("target_width",String(a.targetWidth)),a.deviceType&&t.searchParams.set("device_type",a.deviceType);let e=await fetch(t.toString(),{headers:{"X-Li2-Key":a.publishableKey}});if(!e.ok)throw new Error(`Heatmap API error: ${e.status}`);return(await e.json()).data.heatmap}var b=[[0,[0,0,255,128]],[.25,[0,255,255,200]],[.5,[0,255,0,220]],[.75,[255,255,0,240]],[1,[255,0,0,255]]];function _(a){if(a<=0)return[0,0,0,0];let t=Math.min(1,Math.max(0,a));for(let e=0;e<b.length-1;e++){let[o,i]=b[e],[d,l]=b[e+1];if(t>=o&&t<=d){let s=(t-o)/(d-o);return[Math.round(i[0]+(l[0]-i[0])*s),Math.round(i[1]+(l[1]-i[1])*s),Math.round(i[2]+(l[2]-i[2])*s),Math.round(i[3]+(l[3]-i[3])*s)]}}return[255,0,0,255]}var O=30;function C(a,t,e,o,i=O){let d=a.getContext("2d");if(!d||t.length===0||e===0||o===0)return;a.width=e,a.height=o;let l=Math.max(...t.map(n=>n.count));if(l===0)return;let s=document.createElement("canvas");s.width=e,s.height=o;let r=s.getContext("2d");if(!r)return;r.fillStyle="black",r.fillRect(0,0,e,o),r.globalCompositeOperation="lighter";for(let n of t){if(n.x<-i||n.x>e+i||n.y<-i||n.y>o+i)continue;let u=n.count/l,c=r.createRadialGradient(n.x,n.y,0,n.x,n.y,i);c.addColorStop(0,`rgba(255,255,255,${u})`),c.addColorStop(.33,`rgba(255,255,255,${u*.607})`),c.addColorStop(.67,`rgba(255,255,255,${u*.135})`),c.addColorStop(1,"rgba(255,255,255,0)"),r.fillStyle=c,r.beginPath(),r.arc(n.x,n.y,i,0,Math.PI*2),r.fill()}let v=r.getImageData(0,0,e,o).data,y=d.createImageData(e,o),p=y.data;for(let n=0;n<v.length;n+=4){let u=v[n]/255;if(u>.01){let[c,w,P,T]=_(u);p[n]=c,p[n+1]=w,p[n+2]=P,p[n+3]=T}}d.putImageData(y,0,0)}var h=class{constructor(){this.grid=[];this.handleResize=()=>{this.resize(),this.doRender()};this.canvas=document.createElement("canvas"),this.canvas.style.cssText="position:absolute;top:0;left:0;pointer-events:none;z-index:99998;"}mount(){document.body.appendChild(this.canvas),this.resize(),window.addEventListener("resize",this.handleResize)}unmount(){this.canvas.remove(),window.removeEventListener("resize",this.handleResize)}render(t){this.grid=t,this.doRender()}setOpacity(t){this.canvas.style.opacity=String(t)}resize(){let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight;this.canvas.style.width=`${t}px`,this.canvas.style.height=`${e}px`}doRender(){if(this.grid.length===0)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight;C(this.canvas,this.grid,t,e)}};var m=class{constructor(t){this.root=null;this.statsEl=null;this.statusEl=null;this.config=t}mount(){this.root=document.createElement("div"),this.root.className="__li2-toolbar";let t=document.createElement("span");t.textContent="Li2 Heatmap",this.root.appendChild(t),this.root.appendChild(this.createSeparator()),this.statsEl=document.createElement("span"),this.statsEl.className="__li2-toolbar-stat",this.statsEl.textContent="...",this.root.appendChild(this.statsEl),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.root.appendChild(this.statusEl);let e=document.createElement("input");e.type="range",e.min="0",e.max="100",e.value=String(Math.round(this.config.initialOpacity*100)),e.className="__li2-toolbar-slider",e.addEventListener("input",()=>{this.config.onOpacityChange(Number(e.value)/100)}),this.root.appendChild(e);let o=document.createElement("button");o.className="__li2-toolbar-close",o.textContent="\xD7",o.title="Close heatmap",o.addEventListener("click",this.config.onClose),this.root.appendChild(o),document.body.appendChild(this.root)}unmount(){this.root?.remove(),this.root=null}setStats(t,e){this.statsEl&&(this.statsEl.textContent=`${t.toLocaleString()} clicks`)}setLoading(t){this.statusEl&&(t?(this.statusEl.className="__li2-toolbar-loading",this.statusEl.textContent="Loading..."):(this.statusEl.textContent="",this.statusEl.className=""))}setError(t){this.statusEl&&(this.statusEl.className="__li2-toolbar-error",this.statusEl.textContent=t)}createSeparator(){let t=document.createElement("span");return t.style.cssText="color:#555;user-select:none;",t.textContent="|",t}};function E(){if(document.getElementById("__li2-toolbar-styles"))return;let a=document.createElement("style");a.id="__li2-toolbar-styles",a.textContent=`
1
+ "use strict";var li2Analytics=(()=>{var C=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var B=(i,e)=>{for(var t in e)C(i,t,{get:e[t],enumerable:!0})},U=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of $(e))!A.call(i,a)&&a!==t&&C(i,a,{get:()=>e[a],enumerable:!(n=D(e,a))||n.enumerable});return i};var F=i=>U(C({},"__esModule",{value:!0}),i);var ee={};B(ee,{ToolbarManager:()=>y});async function k(i){let e=new URL(`${i.apiUrl}/api/v1/track/heatmap/clicks`);e.searchParams.set("page_path",i.pagePath),e.searchParams.set("from",i.from),e.searchParams.set("to",i.to),e.searchParams.set("target_width",String(i.targetWidth)),i.deviceType&&e.searchParams.set("device_type",i.deviceType);let t={"X-Li2-Key":i.publishableKey};i.sessionToken&&(t["X-Li2-Session"]=i.sessionToken);let n=await fetch(e.toString(),{headers:t});if(!n.ok)throw new Error(`Heatmap API error: ${n.status}`);return(await n.json()).data.heatmap}var w=[[0,[0,0,255,128]],[.25,[0,255,255,200]],[.5,[0,255,0,220]],[.75,[255,255,0,240]],[1,[255,0,0,255]]];function M(i){if(i<=0)return[0,0,0,0];let e=Math.min(1,Math.max(0,i));for(let t=0;t<w.length-1;t++){let[n,a]=w[t],[o,l]=w[t+1];if(e>=n&&e<=o){let s=(e-n)/(o-n);return[Math.round(a[0]+(l[0]-a[0])*s),Math.round(a[1]+(l[1]-a[1])*s),Math.round(a[2]+(l[2]-a[2])*s),Math.round(a[3]+(l[3]-a[3])*s)]}}return[255,0,0,255]}var G=30;function S(i,e,t,n,a=G){let o=i.getContext("2d");if(!o||e.length===0||t===0||n===0)return;i.width=t,i.height=n;let l=Math.max(...e.map(r=>r.count));if(l===0)return;let s=document.createElement("canvas");s.width=t,s.height=n;let c=s.getContext("2d");if(!c)return;c.fillStyle="black",c.fillRect(0,0,t,n),c.globalCompositeOperation="lighter";for(let r of e){if(r.x<-a||r.x>t+a||r.y<-a||r.y>n+a)continue;let u=r.count/l,d=c.createRadialGradient(r.x,r.y,0,r.x,r.y,a);d.addColorStop(0,`rgba(255,255,255,${u})`),d.addColorStop(.33,`rgba(255,255,255,${u*.607})`),d.addColorStop(.67,`rgba(255,255,255,${u*.135})`),d.addColorStop(1,"rgba(255,255,255,0)"),c.fillStyle=d,c.beginPath(),c.arc(r.x,r.y,a,0,Math.PI*2),c.fill()}let m=c.getImageData(0,0,t,n).data,p=o.createImageData(t,n),h=p.data;for(let r=0;r<m.length;r+=4){let u=m[r]/255;if(u>.01){let[d,R,O,z]=M(u);h[r]=d,h[r+1]=R,h[r+2]=O,h[r+3]=z}}o.putImageData(p,0,0)}var b=class{constructor(){this.grid=[];this.handleResize=()=>{this.resize(),this.doRender()};this.canvas=document.createElement("canvas"),this.canvas.style.cssText="position:absolute;top:0;left:0;pointer-events:none;z-index:99998;"}mount(){document.body.appendChild(this.canvas),this.resize(),window.addEventListener("resize",this.handleResize)}unmount(){this.canvas.remove(),window.removeEventListener("resize",this.handleResize)}render(e){this.grid=e,this.doRender()}setOpacity(e){this.canvas.style.opacity=String(e)}resize(){let e=document.documentElement.scrollWidth,t=document.documentElement.scrollHeight;this.canvas.style.width=`${e}px`,this.canvas.style.height=`${t}px`}doRender(){if(this.grid.length===0)return;let e=document.documentElement.scrollWidth,t=document.documentElement.scrollHeight;S(this.canvas,this.grid,e,t)}};var x=class{constructor(){this.highlight=null;this.tooltip=null;this.currentElement=null}mount(){this.highlight=document.createElement("div"),this.highlight.className="__li2-tagger-highlight",document.body.appendChild(this.highlight),this.tooltip=document.createElement("div"),this.tooltip.className="__li2-tagger-tooltip",document.body.appendChild(this.tooltip)}unmount(){this.highlight?.remove(),this.tooltip?.remove(),this.highlight=null,this.tooltip=null,this.currentElement=null}highlightElement(e){if(!this.highlight||!this.tooltip||e===this.currentElement)return;this.currentElement=e;let t=e.getBoundingClientRect(),n=window.getComputedStyle(e).position==="fixed",a=Math.max(t.width,20),o=Math.max(t.height,20);this.highlight.style.position=n?"fixed":"absolute",this.highlight.style.top=n?`${t.top}px`:`${t.top+window.scrollY}px`,this.highlight.style.left=n?`${t.left}px`:`${t.left+window.scrollX}px`,this.highlight.style.width=`${a}px`,this.highlight.style.height=`${o}px`,this.highlight.style.display="block";let l=e.tagName.toLowerCase(),s=(e.innerText||"").trim().slice(0,40),c=e.id?` #${e.id}`:"",g=s?` "${s}${s.length>=40?"...":""}"`:"";this.tooltip.textContent=`<${l}>${g}${c}`,this.tooltip.style.position=n?"fixed":"absolute";let m=n?t.top-28:t.top+window.scrollY-28;this.tooltip.style.top=`${Math.max(m,4)}px`,this.tooltip.style.left=n?`${t.left}px`:`${t.left+window.scrollX}px`,this.tooltip.style.display="block"}clearHighlight(){this.highlight&&(this.highlight.style.display="none"),this.tooltip&&(this.tooltip.style.display="none"),this.currentElement=null}fixSelection(e){this.highlightElement(e),this.highlight&&this.highlight.classList.add("__li2-tagger-highlight--selected")}clearSelection(){this.highlight&&this.highlight.classList.remove("__li2-tagger-highlight--selected")}updatePosition(){if(this.currentElement){let e=this.currentElement;this.currentElement=null,this.highlightElement(e)}}};var j=new Set(["a","button","input","select","textarea","form","label"]),K=new Set(["button","link","tab","menuitem"]);function T(i){let e=i;for(;e&&!(e instanceof HTMLElement);)e=e.parentElement;if(!e)return null;let n=W(e),a=X(n);return{tag:n.tagName.toLowerCase(),text:H(Y(n),256),href:V(n),className:H(n.className||"",512),id:n.id||null,selectorPath:q(n),isFixed:a}}function W(i){let e=i,t=0;for(;e&&t<5&&e.tagName!=="BODY";){let n=e.tagName.toLowerCase(),a=e.getAttribute("role");if(j.has(n)||a&&K.has(a))return e;e=e.parentElement,t++}return i}function X(i){let e=i;for(;e&&e!==document.body;){try{let n=window.getComputedStyle(e).getPropertyValue("position");if(n==="fixed"||n==="sticky")return!0}catch{break}e=e.parentElement}return!1}function q(i){let e=[],t=i,n=0;for(;t&&t!==document.body&&n<5;){let a=t.tagName.toLowerCase();t.id&&(a+=`#${t.id}`);let o=t.parentElement;if(o){let l=Array.from(o.children).filter(s=>s.tagName===t.tagName);if(l.length>1){let s=l.indexOf(t)+1;a+=`:nth-of-type(${s})`}}e.unshift(a),t=t.parentElement,n++}return e.join(" > ")}function Y(i){return i instanceof HTMLInputElement?i.value||i.placeholder||"":(i.innerText||i.textContent||"").trim()}function V(i){return i instanceof HTMLAnchorElement?i.href||null:i.getAttribute("href")||null}function H(i,e){return i.length<=e?i:i.slice(0,e)}var E=class{constructor(e,t){this.active=!1;this.overlay=e,this.callbacks=t,this.handleMouseMove=this.onMouseMove.bind(this),this.handleClick=this.onClick.bind(this),this.handleScroll=this.onScroll.bind(this)}activate(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMouseMove,!0),document.addEventListener("click",this.handleClick,!0),window.addEventListener("scroll",this.handleScroll,!0))}deactivate(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMouseMove,!0),document.removeEventListener("click",this.handleClick,!0),window.removeEventListener("scroll",this.handleScroll,!0),this.overlay.clearHighlight(),this.overlay.clearSelection())}onMouseMove(e){let t=e.target;if(!t)return;if(this.isToolbarElement(t)){this.overlay.clearHighlight();return}if(!T(t)){this.overlay.clearHighlight();return}let a=this.findMeaningfulDomElement(t);a&&this.overlay.highlightElement(a)}onClick(e){let t=e.target;if(!t||this.isToolbarElement(t))return;e.preventDefault(),e.stopPropagation();let n=T(t);if(!n)return;let a=this.findMeaningfulDomElement(t);a&&(this.overlay.fixSelection(a),this.callbacks.onElementSelected(a,n))}onScroll(){this.overlay.updatePosition()}isToolbarElement(e){let t=e;for(;t;){let n=t.className;if(typeof n=="string"&&(n.includes("__li2-toolbar")||n.includes("__li2-tagger")))return!0;t=t.parentElement}return!1}findMeaningfulDomElement(e){let t=new Set(["a","button","input","select","textarea","form","label"]),n=new Set(["button","link","tab","menuitem"]),a=e,o=0;for(;a&&o<5&&a.tagName!=="BODY";){let l=a.tagName.toLowerCase(),s=a.getAttribute("role");if(t.has(l)||s&&n.has(s))return a;a=a.parentElement,o++}return e}};var f=class extends Error{constructor(e,t){super(t),this.status=e}};function P(i){return{"X-Li2-Key":i.publishableKey,"X-Li2-Session":i.sessionToken}}async function N(i,e){let t=await fetch(`${i.apiUrl}/api/v1/track/event-rules`,{method:"POST",headers:{"Content-Type":"application/json",...P(i)},body:JSON.stringify(e)}),n=await t.json().catch(()=>({}));if(!t.ok){let a=n.error||n.message||`Error ${t.status}`;throw new f(t.status,a)}return n.data}async function I(i){let e=await fetch(`${i.apiUrl}/api/v1/track/event-rules`,{headers:P(i)});if(!e.ok)throw new f(e.status,"Failed to load existing rules");return(await e.json()).data||[]}var _=class{constructor(e){this.root=null;this.nameInput=null;this.nameError=null;this.submitBtn=null;this.statusEl=null;this.rulesListEl=null;this.criteriaCheckboxes=new Map;this.existingRules=[];this.currentInfo=null;this.state="idle";this.config=e}mount(){this.root=document.createElement("div"),this.root.className="__li2-tagger-panel",this.root.style.display="none",document.body.appendChild(this.root),this.fetchExistingRules()}unmount(){this.root?.remove(),this.root=null,this.criteriaCheckboxes.clear()}show(e){this.currentInfo=e,this.state="selected",this.buildPanelContent(e),this.root&&(this.root.style.display="block")}hide(){this.currentInfo=null,this.state="idle",this.root&&(this.root.style.display="none",this.root.innerHTML=""),this.criteriaCheckboxes.clear()}buildPanelContent(e){if(!this.root)return;this.root.innerHTML="",this.criteriaCheckboxes.clear();let t=document.createElement("div");t.className="__li2-tagger-panel-header";let n=document.createElement("span");n.textContent="Create Event Rule",t.appendChild(n);let a=document.createElement("button");a.className="__li2-tagger-panel-close",a.textContent="\xD7",a.addEventListener("click",()=>this.handleCancel()),t.appendChild(a),this.root.appendChild(t);let o=document.createElement("div");o.className="__li2-tagger-summary";let l=e.text?` "${e.text.slice(0,30)}${e.text.length>30?"...":""}"`:"";o.textContent=`Selected: <${e.tag}>${l} on ${window.location.pathname}`,this.root.appendChild(o);let s=document.createElement("div");s.className="__li2-tagger-field";let c=document.createElement("label");c.className="__li2-tagger-label",c.textContent="Event name",s.appendChild(c),this.nameInput=document.createElement("input"),this.nameInput.type="text",this.nameInput.placeholder="e.g. signup_click",this.nameInput.className="__li2-tagger-input",this.nameInput.addEventListener("input",()=>this.onNameInput()),s.appendChild(this.nameInput),this.nameError=document.createElement("div"),this.nameError.className="__li2-tagger-field-error",s.appendChild(this.nameError),this.root.appendChild(s);let g=document.createElement("div");g.className="__li2-tagger-label",g.textContent="Match criteria",this.root.appendChild(g);let m=[{key:"selector_path",label:"CSS Selector",value:e.selectorPath||null},{key:"element_text",label:"Text contains",value:e.text||null},{key:"element_id",label:"Element ID",value:e.id||null},{key:"element_href",label:"Link href",value:e.href||null},{key:"page_path",label:"Page path",value:window.location.pathname}];for(let u of m){let d=this.createCriterionRow(u);this.root.appendChild(d)}this.statusEl=document.createElement("div"),this.statusEl.className="__li2-tagger-panel-status",this.root.appendChild(this.statusEl);let p=document.createElement("div");p.className="__li2-tagger-btn-row";let h=document.createElement("button");h.className="__li2-tagger-btn __li2-tagger-btn-cancel",h.textContent="Cancel",h.addEventListener("click",()=>this.handleCancel()),p.appendChild(h),this.submitBtn=document.createElement("button"),this.submitBtn.className="__li2-tagger-btn __li2-tagger-btn-submit",this.submitBtn.textContent="Create Event Rule",this.submitBtn.addEventListener("click",()=>this.handleSubmit()),p.appendChild(this.submitBtn),this.root.appendChild(p);let r=document.createElement("div");r.className="__li2-tagger-rules-header",r.textContent="Existing rules",this.root.appendChild(r),this.rulesListEl=document.createElement("div"),this.rulesListEl.className="__li2-tagger-rules-list",this.renderRulesList(),this.root.appendChild(this.rulesListEl),setTimeout(()=>this.nameInput?.focus(),50)}createCriterionRow(e){let t=document.createElement("div");t.className="__li2-tagger-criterion";let n=document.createElement("input");n.type="checkbox",n.checked=!!e.value,n.disabled=!e.value,n.addEventListener("change",()=>this.updateSubmitState()),this.criteriaCheckboxes.set(e.key,n),t.appendChild(n);let a=document.createElement("span");a.className="__li2-tagger-criterion-label",a.textContent=e.label+":",t.appendChild(a);let o=document.createElement("span");return o.className="__li2-tagger-criterion-value",o.textContent=e.value?J(e.value,60):"(empty)",e.value||(o.style.color="#666"),t.appendChild(o),t}onNameInput(){if(!this.nameInput)return;let e=this.nameInput.value,t=e.toLowerCase().replace(/[^a-z0-9_]/g,"");t!==e&&(this.nameInput.value=t),this.validateName(),this.updateSubmitState()}validateName(){let e=this.nameInput?.value||"",t=null;return e?e.length>256?t="Max 256 characters":/^[a-z0-9_]+$/.test(e)?this.existingRules.some(n=>n.name===e)&&(t="Event name already exists"):t="Only lowercase letters, numbers, and underscores":t=null,this.nameError&&(this.nameError.textContent=t||""),t}updateSubmitState(){if(!this.submitBtn)return;let e=!!this.nameInput?.value&&!this.validateName(),t=this.getCheckedCriteria().length>0;this.submitBtn.disabled=!e||!t||this.state==="creating"}getCheckedCriteria(){let e=[];for(let[t,n]of this.criteriaCheckboxes)n.checked&&e.push(t);return e}async handleSubmit(){if(!this.nameInput||!this.currentInfo)return;let e=this.nameInput.value;if(!e||this.validateName())return;this.state="creating",this.setFormDisabled(!0),this.setStatus("Creating...","loading");let t=new Set(this.getCheckedCriteria()),n=this.currentInfo,a={name:e,selector_path:t.has("selector_path")&&n.selectorPath||void 0,element_text:t.has("element_text")&&n.text||void 0,element_id:t.has("element_id")&&n.id||void 0,element_href:t.has("element_href")&&n.href||void 0,page_path:t.has("page_path")?window.location.pathname:void 0,text_match_mode:t.has("element_text")?"contains":void 0},o={};for(let[l,s]of Object.entries(a))s!==void 0&&(o[l]=s);try{await N(this.config.apiConfig,o),this.state="success",this.setStatus(`Event rule '${e}' created!`,"success"),await this.fetchExistingRules(),setTimeout(()=>{this.hide(),this.config.onCreated(e)},2e3)}catch(l){this.state="error",this.setFormDisabled(!1),l instanceof f?this.setStatus(l.message,"error"):this.setStatus("Connection failed. Please try again.","error")}}handleCancel(){this.hide(),this.config.onCancel()}setFormDisabled(e){this.nameInput&&(this.nameInput.disabled=e),this.submitBtn&&(this.submitBtn.disabled=e,this.submitBtn.textContent=e?"Creating...":"Create Event Rule");for(let t of this.criteriaCheckboxes.values())(t.checked||!e)&&(t.disabled=e?!0:!t.checked)}setStatus(e,t){this.statusEl&&(this.statusEl.textContent=e,this.statusEl.className="__li2-tagger-panel-status",t==="loading"?this.statusEl.classList.add("__li2-tagger-status-loading"):t==="success"?this.statusEl.classList.add("__li2-tagger-status-success"):t==="error"&&this.statusEl.classList.add("__li2-tagger-status-error"))}async fetchExistingRules(){try{this.existingRules=await I(this.config.apiConfig),this.renderRulesList()}catch{}}renderRulesList(){if(this.rulesListEl){if(this.rulesListEl.innerHTML="",this.existingRules.length===0){let e=document.createElement("div");e.className="__li2-tagger-rules-empty",e.textContent="No rules yet",this.rulesListEl.appendChild(e);return}for(let e of this.existingRules){let t=document.createElement("div");t.className="__li2-tagger-rule-item",t.textContent=`\u2022 ${e.name}`,this.rulesListEl.appendChild(t)}}}};function J(i,e){return i.length>e?i.slice(0,e)+"...":i}var v=class{constructor(e){this.root=null;this.statsEl=null;this.statusEl=null;this.config=e}mount(){this.root=document.createElement("div"),this.root.className="__li2-toolbar",this.config.mode==="tagger"?this.mountTagger():this.mountHeatmap(),document.body.appendChild(this.root)}mountHeatmap(){if(!this.root)return;let e=document.createElement("span");e.textContent="Li2 Heatmap",this.root.appendChild(e),this.root.appendChild(this.createSeparator()),this.statsEl=document.createElement("span"),this.statsEl.className="__li2-toolbar-stat",this.statsEl.textContent="...",this.root.appendChild(this.statsEl),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.root.appendChild(this.statusEl);let t=document.createElement("input");t.type="range",t.min="0",t.max="100",t.value=String(Math.round(this.config.initialOpacity*100)),t.className="__li2-toolbar-slider",t.addEventListener("input",()=>{this.config.onOpacityChange(Number(t.value)/100)}),this.root.appendChild(t),this.appendCloseButton("Close heatmap")}mountTagger(){if(!this.root)return;let e=document.createElement("span");e.textContent="Li2 Event Tagger",this.root.appendChild(e),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.statusEl.className="__li2-toolbar-status",this.statusEl.textContent="Click an element to tag",this.root.appendChild(this.statusEl),this.appendCloseButton("Close tagger")}appendCloseButton(e){if(!this.root)return;let t=document.createElement("button");t.className="__li2-toolbar-close",t.textContent="\xD7",t.title=e,t.addEventListener("click",this.config.onClose),this.root.appendChild(t)}unmount(){this.root?.remove(),this.root=null}setStats(e,t){this.statsEl&&(this.statsEl.textContent=`${e.toLocaleString()} clicks`)}setLoading(e){this.statusEl&&(e?(this.statusEl.className="__li2-toolbar-loading",this.statusEl.textContent="Loading..."):(this.statusEl.textContent="",this.statusEl.className=""))}setStatus(e){this.statusEl&&(this.statusEl.className="__li2-toolbar-status",this.statusEl.textContent=e)}setError(e){this.statusEl&&(this.statusEl.className="__li2-toolbar-error",this.statusEl.textContent=e)}createSeparator(){let e=document.createElement("span");return e.style.cssText="color:#555;user-select:none;",e.textContent="|",e}};function L(){if(document.getElementById("__li2-toolbar-styles"))return;let i=document.createElement("style");i.id="__li2-toolbar-styles",i.textContent=`
2
2
  .__li2-toolbar {
3
3
  position: fixed; bottom: 20px; right: 20px; z-index: 99999;
4
4
  background: #1a1a2e; color: #fff; border-radius: 12px;
@@ -17,4 +17,97 @@
17
17
  .__li2-toolbar-stat { color: #a5b4fc; font-variant-numeric: tabular-nums; }
18
18
  .__li2-toolbar-loading { color: #fbbf24; }
19
19
  .__li2-toolbar-error { color: #f87171; }
20
- `,document.head.appendChild(a)}function z(){let a=new Date;return a.setDate(a.getDate()-7),a.toISOString().slice(0,10)}function M(){return new Date().toISOString().slice(0,10)}var f=class{constructor(t){this.overlay=null;this.ui=null;this.apiUrl=t.apiUrl,this.publishableKey=t.publishableKey}async activate(){let t=this.parseUrlParams();t&&(E(),this.overlay=new h,this.overlay.mount(),this.ui=new m({initialOpacity:.6,onOpacityChange:e=>this.overlay?.setOpacity(e),onClose:()=>this.deactivate()}),this.ui.mount(),await this.fetchAndRender(t))}deactivate(){this.overlay?.unmount(),this.ui?.unmount(),this.overlay=null,this.ui=null;let t=new URL(window.location.href);t.searchParams.delete("li2_heatmap"),t.searchParams.delete("li2_from"),t.searchParams.delete("li2_to"),t.searchParams.delete("li2_device"),history.replaceState(null,"",t.toString())}parseUrlParams(){let t=new URL(window.location.href);return t.searchParams.has("li2_heatmap")?{from:t.searchParams.get("li2_from")??z(),to:t.searchParams.get("li2_to")??M(),deviceType:t.searchParams.get("li2_device")??void 0}:null}async fetchAndRender(t){this.ui?.setLoading(!0);try{let e=await x({apiUrl:this.apiUrl,publishableKey:this.publishableKey,pagePath:window.location.pathname,from:t.from,to:t.to,deviceType:t.deviceType,targetWidth:window.innerWidth});this.overlay?.render(e.grid),this.ui?.setStats(e.total_clicks,e.grid.length)}catch{this.ui?.setError("Failed to load heatmap data")}finally{this.ui?.setLoading(!1)}}};if(typeof window<"u"&&window.__li2ToolbarConfig){let a=window.__li2ToolbarConfig;delete window.__li2ToolbarConfig,new f(a).activate()}return D(I);})();
20
+ .__li2-toolbar-status { color: #a5b4fc; }
21
+ .__li2-tagger-highlight {
22
+ display: none; pointer-events: none; z-index: 99998;
23
+ border: 2px dashed #6366f1; background: rgba(99,102,241,0.08);
24
+ border-radius: 4px; box-sizing: border-box;
25
+ transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s;
26
+ }
27
+ .__li2-tagger-highlight--selected {
28
+ border-style: solid; border-color: #4f46e5;
29
+ background: rgba(79,70,229,0.12);
30
+ }
31
+ .__li2-tagger-tooltip {
32
+ display: none; pointer-events: none; z-index: 99998;
33
+ background: #1a1a2e; color: #e0e7ff; font-family: monospace;
34
+ font-size: 11px; padding: 3px 8px; border-radius: 4px;
35
+ white-space: nowrap; max-width: 400px; overflow: hidden;
36
+ text-overflow: ellipsis; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
37
+ }
38
+ .__li2-tagger-panel {
39
+ position: fixed; bottom: 60px; right: 20px; z-index: 99999;
40
+ width: 380px; max-height: 520px; overflow-y: auto;
41
+ background: #1a1a2e; color: #e0e7ff; border-radius: 12px;
42
+ font-family: -apple-system, sans-serif; font-size: 13px;
43
+ box-shadow: 0 8px 32px rgba(0,0,0,0.4);
44
+ line-height: 1.4; box-sizing: border-box;
45
+ }
46
+ .__li2-tagger-panel * { box-sizing: border-box; margin: 0; padding: 0; }
47
+ .__li2-tagger-panel-header {
48
+ display: flex; justify-content: space-between; align-items: center;
49
+ padding: 12px 16px; border-bottom: 1px solid #2a2a4e;
50
+ font-weight: 600; font-size: 14px;
51
+ }
52
+ .__li2-tagger-panel-close {
53
+ background: none; border: none; color: #999; cursor: pointer;
54
+ font-size: 18px; padding: 2px 6px; border-radius: 4px;
55
+ }
56
+ .__li2-tagger-panel-close:hover { color: #fff; background: rgba(255,255,255,0.1); }
57
+ .__li2-tagger-summary {
58
+ padding: 8px 16px; color: #a5b4fc; font-size: 12px;
59
+ border-bottom: 1px solid #2a2a4e;
60
+ }
61
+ .__li2-tagger-field { padding: 10px 16px 4px; }
62
+ .__li2-tagger-label {
63
+ display: block; padding: 6px 16px 4px; color: #94a3b8;
64
+ font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
65
+ }
66
+ .__li2-tagger-input {
67
+ width: 100%; padding: 8px 10px; border-radius: 6px;
68
+ border: 1px solid #3a3a5e; background: #0f0f23; color: #e0e7ff;
69
+ font-size: 13px; font-family: monospace; outline: none;
70
+ }
71
+ .__li2-tagger-input:focus { border-color: #6366f1; }
72
+ .__li2-tagger-input:disabled { opacity: 0.5; }
73
+ .__li2-tagger-field-error { color: #f87171; font-size: 11px; padding: 2px 0 0; min-height: 16px; }
74
+ .__li2-tagger-criterion {
75
+ display: flex; align-items: center; gap: 8px;
76
+ padding: 4px 16px; font-size: 12px;
77
+ }
78
+ .__li2-tagger-criterion input[type=checkbox] { accent-color: #6366f1; flex-shrink: 0; }
79
+ .__li2-tagger-criterion-label { color: #94a3b8; white-space: nowrap; }
80
+ .__li2-tagger-criterion-value {
81
+ color: #e0e7ff; overflow: hidden; text-overflow: ellipsis;
82
+ white-space: nowrap; font-family: monospace; font-size: 11px;
83
+ }
84
+ .__li2-tagger-panel-status {
85
+ padding: 4px 16px; font-size: 12px; min-height: 22px;
86
+ }
87
+ .__li2-tagger-status-loading { color: #fbbf24; }
88
+ .__li2-tagger-status-success { color: #4ade80; }
89
+ .__li2-tagger-status-error { color: #f87171; }
90
+ .__li2-tagger-btn-row {
91
+ display: flex; justify-content: flex-end; gap: 8px;
92
+ padding: 8px 16px 12px;
93
+ }
94
+ .__li2-tagger-btn {
95
+ padding: 7px 14px; border-radius: 6px; font-size: 13px;
96
+ cursor: pointer; border: none; font-weight: 500;
97
+ }
98
+ .__li2-tagger-btn-cancel { background: #2a2a4e; color: #e0e7ff; }
99
+ .__li2-tagger-btn-cancel:hover { background: #3a3a5e; }
100
+ .__li2-tagger-btn-submit { background: #6366f1; color: #fff; }
101
+ .__li2-tagger-btn-submit:hover { background: #4f46e5; }
102
+ .__li2-tagger-btn-submit:disabled { opacity: 0.5; cursor: not-allowed; }
103
+ .__li2-tagger-rules-header {
104
+ padding: 8px 16px 4px; color: #64748b; font-size: 11px;
105
+ text-transform: uppercase; letter-spacing: 0.5px;
106
+ border-top: 1px solid #2a2a4e; margin-top: 4px;
107
+ }
108
+ .__li2-tagger-rules-list {
109
+ padding: 0 16px 12px; max-height: 100px; overflow-y: auto;
110
+ }
111
+ .__li2-tagger-rules-empty { color: #64748b; font-size: 12px; padding: 4px 0; }
112
+ .__li2-tagger-rule-item { color: #94a3b8; font-size: 12px; padding: 2px 0; }
113
+ `,document.head.appendChild(i)}function Q(){let i=new Date;return i.setDate(i.getDate()-7),i.toISOString().slice(0,10)}function Z(){return new Date().toISOString().slice(0,10)}var y=class{constructor(e){this.heatmapOverlay=null;this.taggerOverlay=null;this.taggerMode=null;this.taggerPanel=null;this.ui=null;this.selectedElement=null;this.onElementSelected=null;this.apiUrl=e.apiUrl,this.publishableKey=e.publishableKey,this.mode=e.mode||"heatmap",this.sessionToken=e.sessionToken}async activate(){if(!this.sessionToken){L(),this.ui=new v({mode:this.mode,initialOpacity:.6,onOpacityChange:()=>{},onClose:()=>this.deactivate()}),this.ui.mount(),this.ui.setError("Session expired. Please reopen from the dashboard.");return}L(),this.mode==="tagger"?this.activateTagger():await this.activateHeatmap()}deactivate(){this.heatmapOverlay?.unmount(),this.heatmapOverlay=null,this.taggerMode?.deactivate(),this.taggerMode=null,this.taggerPanel?.unmount(),this.taggerPanel=null,this.taggerOverlay?.unmount(),this.taggerOverlay=null,this.ui?.unmount(),this.ui=null,this.selectedElement=null;let e=new URL(window.location.href);e.searchParams.delete("li2_heatmap"),e.searchParams.delete("li2_tagger"),e.searchParams.delete("li2_session"),e.searchParams.delete("li2_from"),e.searchParams.delete("li2_to"),e.searchParams.delete("li2_device"),history.replaceState(null,"",e.toString())}async activateHeatmap(){let e=this.parseHeatmapParams();e&&(this.heatmapOverlay=new b,this.heatmapOverlay.mount(),this.ui=new v({mode:"heatmap",initialOpacity:.6,onOpacityChange:t=>this.heatmapOverlay?.setOpacity(t),onClose:()=>this.deactivate()}),this.ui.mount(),await this.fetchAndRender(e))}parseHeatmapParams(){let e=new URL(window.location.href);return e.searchParams.has("li2_heatmap")?{from:e.searchParams.get("li2_from")??Q(),to:e.searchParams.get("li2_to")??Z(),deviceType:e.searchParams.get("li2_device")??void 0}:null}async fetchAndRender(e){this.ui?.setLoading(!0);try{let t=await k({apiUrl:this.apiUrl,publishableKey:this.publishableKey,sessionToken:this.sessionToken,pagePath:window.location.pathname,from:e.from,to:e.to,deviceType:e.deviceType,targetWidth:window.innerWidth});this.heatmapOverlay?.render(t.grid),this.ui?.setStats(t.total_clicks,t.grid.length)}catch{this.ui?.setError("Failed to load heatmap data")}finally{this.ui?.setLoading(!1)}}activateTagger(){this.taggerOverlay=new x,this.taggerOverlay.mount(),this.taggerPanel=new _({apiConfig:{apiUrl:this.apiUrl,publishableKey:this.publishableKey,sessionToken:this.sessionToken},onCancel:()=>{this.taggerOverlay?.clearHighlight(),this.taggerOverlay?.clearSelection(),this.selectedElement=null,this.ui?.setStatus("Click an element to tag")},onCreated:()=>{this.taggerOverlay?.clearHighlight(),this.taggerOverlay?.clearSelection(),this.selectedElement=null,this.ui?.setStatus("Click an element to tag")}}),this.taggerPanel.mount(),this.taggerMode=new E(this.taggerOverlay,{onElementSelected:(e,t)=>{this.selectedElement={element:e,info:t},this.ui?.setStatus("Element selected"),this.taggerPanel?.show(t),this.onElementSelected?.({element:e,info:t})}}),this.taggerMode.activate(),this.ui=new v({mode:"tagger",initialOpacity:.6,onOpacityChange:()=>{},onClose:()=>this.deactivate()}),this.ui.mount()}};if(typeof window<"u"&&window.__li2ToolbarConfig){let i=window.__li2ToolbarConfig;delete window.__li2ToolbarConfig;let e=new y(i);window.__li2Toolbar=e,e.activate()}return F(ee);})();
@@ -1,4 +1,4 @@
1
- "use strict";var g=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var U=(a,t)=>{for(var e in t)g(a,e,{get:t[e],enumerable:!0})},R=(a,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of H(t))!L.call(a,i)&&i!==e&&g(a,i,{get:()=>t[i],enumerable:!(o=S(t,i))||o.enumerable});return a};var D=a=>R(g({},"__esModule",{value:!0}),a);var I={};U(I,{ToolbarManager:()=>f});module.exports=D(I);async function x(a){let t=new URL(`${a.apiUrl}/api/v1/track/heatmap/clicks`);t.searchParams.set("page_path",a.pagePath),t.searchParams.set("from",a.from),t.searchParams.set("to",a.to),t.searchParams.set("target_width",String(a.targetWidth)),a.deviceType&&t.searchParams.set("device_type",a.deviceType);let e=await fetch(t.toString(),{headers:{"X-Li2-Key":a.publishableKey}});if(!e.ok)throw new Error(`Heatmap API error: ${e.status}`);return(await e.json()).data.heatmap}var b=[[0,[0,0,255,128]],[.25,[0,255,255,200]],[.5,[0,255,0,220]],[.75,[255,255,0,240]],[1,[255,0,0,255]]];function _(a){if(a<=0)return[0,0,0,0];let t=Math.min(1,Math.max(0,a));for(let e=0;e<b.length-1;e++){let[o,i]=b[e],[d,l]=b[e+1];if(t>=o&&t<=d){let s=(t-o)/(d-o);return[Math.round(i[0]+(l[0]-i[0])*s),Math.round(i[1]+(l[1]-i[1])*s),Math.round(i[2]+(l[2]-i[2])*s),Math.round(i[3]+(l[3]-i[3])*s)]}}return[255,0,0,255]}var O=30;function C(a,t,e,o,i=O){let d=a.getContext("2d");if(!d||t.length===0||e===0||o===0)return;a.width=e,a.height=o;let l=Math.max(...t.map(n=>n.count));if(l===0)return;let s=document.createElement("canvas");s.width=e,s.height=o;let r=s.getContext("2d");if(!r)return;r.fillStyle="black",r.fillRect(0,0,e,o),r.globalCompositeOperation="lighter";for(let n of t){if(n.x<-i||n.x>e+i||n.y<-i||n.y>o+i)continue;let u=n.count/l,c=r.createRadialGradient(n.x,n.y,0,n.x,n.y,i);c.addColorStop(0,`rgba(255,255,255,${u})`),c.addColorStop(.33,`rgba(255,255,255,${u*.607})`),c.addColorStop(.67,`rgba(255,255,255,${u*.135})`),c.addColorStop(1,"rgba(255,255,255,0)"),r.fillStyle=c,r.beginPath(),r.arc(n.x,n.y,i,0,Math.PI*2),r.fill()}let v=r.getImageData(0,0,e,o).data,y=d.createImageData(e,o),p=y.data;for(let n=0;n<v.length;n+=4){let u=v[n]/255;if(u>.01){let[c,w,P,T]=_(u);p[n]=c,p[n+1]=w,p[n+2]=P,p[n+3]=T}}d.putImageData(y,0,0)}var h=class{constructor(){this.grid=[];this.handleResize=()=>{this.resize(),this.doRender()};this.canvas=document.createElement("canvas"),this.canvas.style.cssText="position:absolute;top:0;left:0;pointer-events:none;z-index:99998;"}mount(){document.body.appendChild(this.canvas),this.resize(),window.addEventListener("resize",this.handleResize)}unmount(){this.canvas.remove(),window.removeEventListener("resize",this.handleResize)}render(t){this.grid=t,this.doRender()}setOpacity(t){this.canvas.style.opacity=String(t)}resize(){let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight;this.canvas.style.width=`${t}px`,this.canvas.style.height=`${e}px`}doRender(){if(this.grid.length===0)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight;C(this.canvas,this.grid,t,e)}};var m=class{constructor(t){this.root=null;this.statsEl=null;this.statusEl=null;this.config=t}mount(){this.root=document.createElement("div"),this.root.className="__li2-toolbar";let t=document.createElement("span");t.textContent="Li2 Heatmap",this.root.appendChild(t),this.root.appendChild(this.createSeparator()),this.statsEl=document.createElement("span"),this.statsEl.className="__li2-toolbar-stat",this.statsEl.textContent="...",this.root.appendChild(this.statsEl),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.root.appendChild(this.statusEl);let e=document.createElement("input");e.type="range",e.min="0",e.max="100",e.value=String(Math.round(this.config.initialOpacity*100)),e.className="__li2-toolbar-slider",e.addEventListener("input",()=>{this.config.onOpacityChange(Number(e.value)/100)}),this.root.appendChild(e);let o=document.createElement("button");o.className="__li2-toolbar-close",o.textContent="\xD7",o.title="Close heatmap",o.addEventListener("click",this.config.onClose),this.root.appendChild(o),document.body.appendChild(this.root)}unmount(){this.root?.remove(),this.root=null}setStats(t,e){this.statsEl&&(this.statsEl.textContent=`${t.toLocaleString()} clicks`)}setLoading(t){this.statusEl&&(t?(this.statusEl.className="__li2-toolbar-loading",this.statusEl.textContent="Loading..."):(this.statusEl.textContent="",this.statusEl.className=""))}setError(t){this.statusEl&&(this.statusEl.className="__li2-toolbar-error",this.statusEl.textContent=t)}createSeparator(){let t=document.createElement("span");return t.style.cssText="color:#555;user-select:none;",t.textContent="|",t}};function E(){if(document.getElementById("__li2-toolbar-styles"))return;let a=document.createElement("style");a.id="__li2-toolbar-styles",a.textContent=`
1
+ "use strict";var C=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var B=(i,e)=>{for(var t in e)C(i,t,{get:e[t],enumerable:!0})},U=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of $(e))!A.call(i,a)&&a!==t&&C(i,a,{get:()=>e[a],enumerable:!(n=D(e,a))||n.enumerable});return i};var F=i=>U(C({},"__esModule",{value:!0}),i);var ee={};B(ee,{ToolbarManager:()=>y});module.exports=F(ee);async function k(i){let e=new URL(`${i.apiUrl}/api/v1/track/heatmap/clicks`);e.searchParams.set("page_path",i.pagePath),e.searchParams.set("from",i.from),e.searchParams.set("to",i.to),e.searchParams.set("target_width",String(i.targetWidth)),i.deviceType&&e.searchParams.set("device_type",i.deviceType);let t={"X-Li2-Key":i.publishableKey};i.sessionToken&&(t["X-Li2-Session"]=i.sessionToken);let n=await fetch(e.toString(),{headers:t});if(!n.ok)throw new Error(`Heatmap API error: ${n.status}`);return(await n.json()).data.heatmap}var w=[[0,[0,0,255,128]],[.25,[0,255,255,200]],[.5,[0,255,0,220]],[.75,[255,255,0,240]],[1,[255,0,0,255]]];function M(i){if(i<=0)return[0,0,0,0];let e=Math.min(1,Math.max(0,i));for(let t=0;t<w.length-1;t++){let[n,a]=w[t],[o,l]=w[t+1];if(e>=n&&e<=o){let s=(e-n)/(o-n);return[Math.round(a[0]+(l[0]-a[0])*s),Math.round(a[1]+(l[1]-a[1])*s),Math.round(a[2]+(l[2]-a[2])*s),Math.round(a[3]+(l[3]-a[3])*s)]}}return[255,0,0,255]}var G=30;function S(i,e,t,n,a=G){let o=i.getContext("2d");if(!o||e.length===0||t===0||n===0)return;i.width=t,i.height=n;let l=Math.max(...e.map(r=>r.count));if(l===0)return;let s=document.createElement("canvas");s.width=t,s.height=n;let c=s.getContext("2d");if(!c)return;c.fillStyle="black",c.fillRect(0,0,t,n),c.globalCompositeOperation="lighter";for(let r of e){if(r.x<-a||r.x>t+a||r.y<-a||r.y>n+a)continue;let u=r.count/l,d=c.createRadialGradient(r.x,r.y,0,r.x,r.y,a);d.addColorStop(0,`rgba(255,255,255,${u})`),d.addColorStop(.33,`rgba(255,255,255,${u*.607})`),d.addColorStop(.67,`rgba(255,255,255,${u*.135})`),d.addColorStop(1,"rgba(255,255,255,0)"),c.fillStyle=d,c.beginPath(),c.arc(r.x,r.y,a,0,Math.PI*2),c.fill()}let m=c.getImageData(0,0,t,n).data,p=o.createImageData(t,n),h=p.data;for(let r=0;r<m.length;r+=4){let u=m[r]/255;if(u>.01){let[d,R,O,z]=M(u);h[r]=d,h[r+1]=R,h[r+2]=O,h[r+3]=z}}o.putImageData(p,0,0)}var b=class{constructor(){this.grid=[];this.handleResize=()=>{this.resize(),this.doRender()};this.canvas=document.createElement("canvas"),this.canvas.style.cssText="position:absolute;top:0;left:0;pointer-events:none;z-index:99998;"}mount(){document.body.appendChild(this.canvas),this.resize(),window.addEventListener("resize",this.handleResize)}unmount(){this.canvas.remove(),window.removeEventListener("resize",this.handleResize)}render(e){this.grid=e,this.doRender()}setOpacity(e){this.canvas.style.opacity=String(e)}resize(){let e=document.documentElement.scrollWidth,t=document.documentElement.scrollHeight;this.canvas.style.width=`${e}px`,this.canvas.style.height=`${t}px`}doRender(){if(this.grid.length===0)return;let e=document.documentElement.scrollWidth,t=document.documentElement.scrollHeight;S(this.canvas,this.grid,e,t)}};var x=class{constructor(){this.highlight=null;this.tooltip=null;this.currentElement=null}mount(){this.highlight=document.createElement("div"),this.highlight.className="__li2-tagger-highlight",document.body.appendChild(this.highlight),this.tooltip=document.createElement("div"),this.tooltip.className="__li2-tagger-tooltip",document.body.appendChild(this.tooltip)}unmount(){this.highlight?.remove(),this.tooltip?.remove(),this.highlight=null,this.tooltip=null,this.currentElement=null}highlightElement(e){if(!this.highlight||!this.tooltip||e===this.currentElement)return;this.currentElement=e;let t=e.getBoundingClientRect(),n=window.getComputedStyle(e).position==="fixed",a=Math.max(t.width,20),o=Math.max(t.height,20);this.highlight.style.position=n?"fixed":"absolute",this.highlight.style.top=n?`${t.top}px`:`${t.top+window.scrollY}px`,this.highlight.style.left=n?`${t.left}px`:`${t.left+window.scrollX}px`,this.highlight.style.width=`${a}px`,this.highlight.style.height=`${o}px`,this.highlight.style.display="block";let l=e.tagName.toLowerCase(),s=(e.innerText||"").trim().slice(0,40),c=e.id?` #${e.id}`:"",g=s?` "${s}${s.length>=40?"...":""}"`:"";this.tooltip.textContent=`<${l}>${g}${c}`,this.tooltip.style.position=n?"fixed":"absolute";let m=n?t.top-28:t.top+window.scrollY-28;this.tooltip.style.top=`${Math.max(m,4)}px`,this.tooltip.style.left=n?`${t.left}px`:`${t.left+window.scrollX}px`,this.tooltip.style.display="block"}clearHighlight(){this.highlight&&(this.highlight.style.display="none"),this.tooltip&&(this.tooltip.style.display="none"),this.currentElement=null}fixSelection(e){this.highlightElement(e),this.highlight&&this.highlight.classList.add("__li2-tagger-highlight--selected")}clearSelection(){this.highlight&&this.highlight.classList.remove("__li2-tagger-highlight--selected")}updatePosition(){if(this.currentElement){let e=this.currentElement;this.currentElement=null,this.highlightElement(e)}}};var j=new Set(["a","button","input","select","textarea","form","label"]),K=new Set(["button","link","tab","menuitem"]);function T(i){let e=i;for(;e&&!(e instanceof HTMLElement);)e=e.parentElement;if(!e)return null;let n=W(e),a=X(n);return{tag:n.tagName.toLowerCase(),text:H(Y(n),256),href:V(n),className:H(n.className||"",512),id:n.id||null,selectorPath:q(n),isFixed:a}}function W(i){let e=i,t=0;for(;e&&t<5&&e.tagName!=="BODY";){let n=e.tagName.toLowerCase(),a=e.getAttribute("role");if(j.has(n)||a&&K.has(a))return e;e=e.parentElement,t++}return i}function X(i){let e=i;for(;e&&e!==document.body;){try{let n=window.getComputedStyle(e).getPropertyValue("position");if(n==="fixed"||n==="sticky")return!0}catch{break}e=e.parentElement}return!1}function q(i){let e=[],t=i,n=0;for(;t&&t!==document.body&&n<5;){let a=t.tagName.toLowerCase();t.id&&(a+=`#${t.id}`);let o=t.parentElement;if(o){let l=Array.from(o.children).filter(s=>s.tagName===t.tagName);if(l.length>1){let s=l.indexOf(t)+1;a+=`:nth-of-type(${s})`}}e.unshift(a),t=t.parentElement,n++}return e.join(" > ")}function Y(i){return i instanceof HTMLInputElement?i.value||i.placeholder||"":(i.innerText||i.textContent||"").trim()}function V(i){return i instanceof HTMLAnchorElement?i.href||null:i.getAttribute("href")||null}function H(i,e){return i.length<=e?i:i.slice(0,e)}var E=class{constructor(e,t){this.active=!1;this.overlay=e,this.callbacks=t,this.handleMouseMove=this.onMouseMove.bind(this),this.handleClick=this.onClick.bind(this),this.handleScroll=this.onScroll.bind(this)}activate(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMouseMove,!0),document.addEventListener("click",this.handleClick,!0),window.addEventListener("scroll",this.handleScroll,!0))}deactivate(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMouseMove,!0),document.removeEventListener("click",this.handleClick,!0),window.removeEventListener("scroll",this.handleScroll,!0),this.overlay.clearHighlight(),this.overlay.clearSelection())}onMouseMove(e){let t=e.target;if(!t)return;if(this.isToolbarElement(t)){this.overlay.clearHighlight();return}if(!T(t)){this.overlay.clearHighlight();return}let a=this.findMeaningfulDomElement(t);a&&this.overlay.highlightElement(a)}onClick(e){let t=e.target;if(!t||this.isToolbarElement(t))return;e.preventDefault(),e.stopPropagation();let n=T(t);if(!n)return;let a=this.findMeaningfulDomElement(t);a&&(this.overlay.fixSelection(a),this.callbacks.onElementSelected(a,n))}onScroll(){this.overlay.updatePosition()}isToolbarElement(e){let t=e;for(;t;){let n=t.className;if(typeof n=="string"&&(n.includes("__li2-toolbar")||n.includes("__li2-tagger")))return!0;t=t.parentElement}return!1}findMeaningfulDomElement(e){let t=new Set(["a","button","input","select","textarea","form","label"]),n=new Set(["button","link","tab","menuitem"]),a=e,o=0;for(;a&&o<5&&a.tagName!=="BODY";){let l=a.tagName.toLowerCase(),s=a.getAttribute("role");if(t.has(l)||s&&n.has(s))return a;a=a.parentElement,o++}return e}};var f=class extends Error{constructor(e,t){super(t),this.status=e}};function P(i){return{"X-Li2-Key":i.publishableKey,"X-Li2-Session":i.sessionToken}}async function N(i,e){let t=await fetch(`${i.apiUrl}/api/v1/track/event-rules`,{method:"POST",headers:{"Content-Type":"application/json",...P(i)},body:JSON.stringify(e)}),n=await t.json().catch(()=>({}));if(!t.ok){let a=n.error||n.message||`Error ${t.status}`;throw new f(t.status,a)}return n.data}async function I(i){let e=await fetch(`${i.apiUrl}/api/v1/track/event-rules`,{headers:P(i)});if(!e.ok)throw new f(e.status,"Failed to load existing rules");return(await e.json()).data||[]}var _=class{constructor(e){this.root=null;this.nameInput=null;this.nameError=null;this.submitBtn=null;this.statusEl=null;this.rulesListEl=null;this.criteriaCheckboxes=new Map;this.existingRules=[];this.currentInfo=null;this.state="idle";this.config=e}mount(){this.root=document.createElement("div"),this.root.className="__li2-tagger-panel",this.root.style.display="none",document.body.appendChild(this.root),this.fetchExistingRules()}unmount(){this.root?.remove(),this.root=null,this.criteriaCheckboxes.clear()}show(e){this.currentInfo=e,this.state="selected",this.buildPanelContent(e),this.root&&(this.root.style.display="block")}hide(){this.currentInfo=null,this.state="idle",this.root&&(this.root.style.display="none",this.root.innerHTML=""),this.criteriaCheckboxes.clear()}buildPanelContent(e){if(!this.root)return;this.root.innerHTML="",this.criteriaCheckboxes.clear();let t=document.createElement("div");t.className="__li2-tagger-panel-header";let n=document.createElement("span");n.textContent="Create Event Rule",t.appendChild(n);let a=document.createElement("button");a.className="__li2-tagger-panel-close",a.textContent="\xD7",a.addEventListener("click",()=>this.handleCancel()),t.appendChild(a),this.root.appendChild(t);let o=document.createElement("div");o.className="__li2-tagger-summary";let l=e.text?` "${e.text.slice(0,30)}${e.text.length>30?"...":""}"`:"";o.textContent=`Selected: <${e.tag}>${l} on ${window.location.pathname}`,this.root.appendChild(o);let s=document.createElement("div");s.className="__li2-tagger-field";let c=document.createElement("label");c.className="__li2-tagger-label",c.textContent="Event name",s.appendChild(c),this.nameInput=document.createElement("input"),this.nameInput.type="text",this.nameInput.placeholder="e.g. signup_click",this.nameInput.className="__li2-tagger-input",this.nameInput.addEventListener("input",()=>this.onNameInput()),s.appendChild(this.nameInput),this.nameError=document.createElement("div"),this.nameError.className="__li2-tagger-field-error",s.appendChild(this.nameError),this.root.appendChild(s);let g=document.createElement("div");g.className="__li2-tagger-label",g.textContent="Match criteria",this.root.appendChild(g);let m=[{key:"selector_path",label:"CSS Selector",value:e.selectorPath||null},{key:"element_text",label:"Text contains",value:e.text||null},{key:"element_id",label:"Element ID",value:e.id||null},{key:"element_href",label:"Link href",value:e.href||null},{key:"page_path",label:"Page path",value:window.location.pathname}];for(let u of m){let d=this.createCriterionRow(u);this.root.appendChild(d)}this.statusEl=document.createElement("div"),this.statusEl.className="__li2-tagger-panel-status",this.root.appendChild(this.statusEl);let p=document.createElement("div");p.className="__li2-tagger-btn-row";let h=document.createElement("button");h.className="__li2-tagger-btn __li2-tagger-btn-cancel",h.textContent="Cancel",h.addEventListener("click",()=>this.handleCancel()),p.appendChild(h),this.submitBtn=document.createElement("button"),this.submitBtn.className="__li2-tagger-btn __li2-tagger-btn-submit",this.submitBtn.textContent="Create Event Rule",this.submitBtn.addEventListener("click",()=>this.handleSubmit()),p.appendChild(this.submitBtn),this.root.appendChild(p);let r=document.createElement("div");r.className="__li2-tagger-rules-header",r.textContent="Existing rules",this.root.appendChild(r),this.rulesListEl=document.createElement("div"),this.rulesListEl.className="__li2-tagger-rules-list",this.renderRulesList(),this.root.appendChild(this.rulesListEl),setTimeout(()=>this.nameInput?.focus(),50)}createCriterionRow(e){let t=document.createElement("div");t.className="__li2-tagger-criterion";let n=document.createElement("input");n.type="checkbox",n.checked=!!e.value,n.disabled=!e.value,n.addEventListener("change",()=>this.updateSubmitState()),this.criteriaCheckboxes.set(e.key,n),t.appendChild(n);let a=document.createElement("span");a.className="__li2-tagger-criterion-label",a.textContent=e.label+":",t.appendChild(a);let o=document.createElement("span");return o.className="__li2-tagger-criterion-value",o.textContent=e.value?J(e.value,60):"(empty)",e.value||(o.style.color="#666"),t.appendChild(o),t}onNameInput(){if(!this.nameInput)return;let e=this.nameInput.value,t=e.toLowerCase().replace(/[^a-z0-9_]/g,"");t!==e&&(this.nameInput.value=t),this.validateName(),this.updateSubmitState()}validateName(){let e=this.nameInput?.value||"",t=null;return e?e.length>256?t="Max 256 characters":/^[a-z0-9_]+$/.test(e)?this.existingRules.some(n=>n.name===e)&&(t="Event name already exists"):t="Only lowercase letters, numbers, and underscores":t=null,this.nameError&&(this.nameError.textContent=t||""),t}updateSubmitState(){if(!this.submitBtn)return;let e=!!this.nameInput?.value&&!this.validateName(),t=this.getCheckedCriteria().length>0;this.submitBtn.disabled=!e||!t||this.state==="creating"}getCheckedCriteria(){let e=[];for(let[t,n]of this.criteriaCheckboxes)n.checked&&e.push(t);return e}async handleSubmit(){if(!this.nameInput||!this.currentInfo)return;let e=this.nameInput.value;if(!e||this.validateName())return;this.state="creating",this.setFormDisabled(!0),this.setStatus("Creating...","loading");let t=new Set(this.getCheckedCriteria()),n=this.currentInfo,a={name:e,selector_path:t.has("selector_path")&&n.selectorPath||void 0,element_text:t.has("element_text")&&n.text||void 0,element_id:t.has("element_id")&&n.id||void 0,element_href:t.has("element_href")&&n.href||void 0,page_path:t.has("page_path")?window.location.pathname:void 0,text_match_mode:t.has("element_text")?"contains":void 0},o={};for(let[l,s]of Object.entries(a))s!==void 0&&(o[l]=s);try{await N(this.config.apiConfig,o),this.state="success",this.setStatus(`Event rule '${e}' created!`,"success"),await this.fetchExistingRules(),setTimeout(()=>{this.hide(),this.config.onCreated(e)},2e3)}catch(l){this.state="error",this.setFormDisabled(!1),l instanceof f?this.setStatus(l.message,"error"):this.setStatus("Connection failed. Please try again.","error")}}handleCancel(){this.hide(),this.config.onCancel()}setFormDisabled(e){this.nameInput&&(this.nameInput.disabled=e),this.submitBtn&&(this.submitBtn.disabled=e,this.submitBtn.textContent=e?"Creating...":"Create Event Rule");for(let t of this.criteriaCheckboxes.values())(t.checked||!e)&&(t.disabled=e?!0:!t.checked)}setStatus(e,t){this.statusEl&&(this.statusEl.textContent=e,this.statusEl.className="__li2-tagger-panel-status",t==="loading"?this.statusEl.classList.add("__li2-tagger-status-loading"):t==="success"?this.statusEl.classList.add("__li2-tagger-status-success"):t==="error"&&this.statusEl.classList.add("__li2-tagger-status-error"))}async fetchExistingRules(){try{this.existingRules=await I(this.config.apiConfig),this.renderRulesList()}catch{}}renderRulesList(){if(this.rulesListEl){if(this.rulesListEl.innerHTML="",this.existingRules.length===0){let e=document.createElement("div");e.className="__li2-tagger-rules-empty",e.textContent="No rules yet",this.rulesListEl.appendChild(e);return}for(let e of this.existingRules){let t=document.createElement("div");t.className="__li2-tagger-rule-item",t.textContent=`\u2022 ${e.name}`,this.rulesListEl.appendChild(t)}}}};function J(i,e){return i.length>e?i.slice(0,e)+"...":i}var v=class{constructor(e){this.root=null;this.statsEl=null;this.statusEl=null;this.config=e}mount(){this.root=document.createElement("div"),this.root.className="__li2-toolbar",this.config.mode==="tagger"?this.mountTagger():this.mountHeatmap(),document.body.appendChild(this.root)}mountHeatmap(){if(!this.root)return;let e=document.createElement("span");e.textContent="Li2 Heatmap",this.root.appendChild(e),this.root.appendChild(this.createSeparator()),this.statsEl=document.createElement("span"),this.statsEl.className="__li2-toolbar-stat",this.statsEl.textContent="...",this.root.appendChild(this.statsEl),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.root.appendChild(this.statusEl);let t=document.createElement("input");t.type="range",t.min="0",t.max="100",t.value=String(Math.round(this.config.initialOpacity*100)),t.className="__li2-toolbar-slider",t.addEventListener("input",()=>{this.config.onOpacityChange(Number(t.value)/100)}),this.root.appendChild(t),this.appendCloseButton("Close heatmap")}mountTagger(){if(!this.root)return;let e=document.createElement("span");e.textContent="Li2 Event Tagger",this.root.appendChild(e),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.statusEl.className="__li2-toolbar-status",this.statusEl.textContent="Click an element to tag",this.root.appendChild(this.statusEl),this.appendCloseButton("Close tagger")}appendCloseButton(e){if(!this.root)return;let t=document.createElement("button");t.className="__li2-toolbar-close",t.textContent="\xD7",t.title=e,t.addEventListener("click",this.config.onClose),this.root.appendChild(t)}unmount(){this.root?.remove(),this.root=null}setStats(e,t){this.statsEl&&(this.statsEl.textContent=`${e.toLocaleString()} clicks`)}setLoading(e){this.statusEl&&(e?(this.statusEl.className="__li2-toolbar-loading",this.statusEl.textContent="Loading..."):(this.statusEl.textContent="",this.statusEl.className=""))}setStatus(e){this.statusEl&&(this.statusEl.className="__li2-toolbar-status",this.statusEl.textContent=e)}setError(e){this.statusEl&&(this.statusEl.className="__li2-toolbar-error",this.statusEl.textContent=e)}createSeparator(){let e=document.createElement("span");return e.style.cssText="color:#555;user-select:none;",e.textContent="|",e}};function L(){if(document.getElementById("__li2-toolbar-styles"))return;let i=document.createElement("style");i.id="__li2-toolbar-styles",i.textContent=`
2
2
  .__li2-toolbar {
3
3
  position: fixed; bottom: 20px; right: 20px; z-index: 99999;
4
4
  background: #1a1a2e; color: #fff; border-radius: 12px;
@@ -17,4 +17,97 @@
17
17
  .__li2-toolbar-stat { color: #a5b4fc; font-variant-numeric: tabular-nums; }
18
18
  .__li2-toolbar-loading { color: #fbbf24; }
19
19
  .__li2-toolbar-error { color: #f87171; }
20
- `,document.head.appendChild(a)}function z(){let a=new Date;return a.setDate(a.getDate()-7),a.toISOString().slice(0,10)}function M(){return new Date().toISOString().slice(0,10)}var f=class{constructor(t){this.overlay=null;this.ui=null;this.apiUrl=t.apiUrl,this.publishableKey=t.publishableKey}async activate(){let t=this.parseUrlParams();t&&(E(),this.overlay=new h,this.overlay.mount(),this.ui=new m({initialOpacity:.6,onOpacityChange:e=>this.overlay?.setOpacity(e),onClose:()=>this.deactivate()}),this.ui.mount(),await this.fetchAndRender(t))}deactivate(){this.overlay?.unmount(),this.ui?.unmount(),this.overlay=null,this.ui=null;let t=new URL(window.location.href);t.searchParams.delete("li2_heatmap"),t.searchParams.delete("li2_from"),t.searchParams.delete("li2_to"),t.searchParams.delete("li2_device"),history.replaceState(null,"",t.toString())}parseUrlParams(){let t=new URL(window.location.href);return t.searchParams.has("li2_heatmap")?{from:t.searchParams.get("li2_from")??z(),to:t.searchParams.get("li2_to")??M(),deviceType:t.searchParams.get("li2_device")??void 0}:null}async fetchAndRender(t){this.ui?.setLoading(!0);try{let e=await x({apiUrl:this.apiUrl,publishableKey:this.publishableKey,pagePath:window.location.pathname,from:t.from,to:t.to,deviceType:t.deviceType,targetWidth:window.innerWidth});this.overlay?.render(e.grid),this.ui?.setStats(e.total_clicks,e.grid.length)}catch{this.ui?.setError("Failed to load heatmap data")}finally{this.ui?.setLoading(!1)}}};if(typeof window<"u"&&window.__li2ToolbarConfig){let a=window.__li2ToolbarConfig;delete window.__li2ToolbarConfig,new f(a).activate()}0&&(module.exports={ToolbarManager});
20
+ .__li2-toolbar-status { color: #a5b4fc; }
21
+ .__li2-tagger-highlight {
22
+ display: none; pointer-events: none; z-index: 99998;
23
+ border: 2px dashed #6366f1; background: rgba(99,102,241,0.08);
24
+ border-radius: 4px; box-sizing: border-box;
25
+ transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s;
26
+ }
27
+ .__li2-tagger-highlight--selected {
28
+ border-style: solid; border-color: #4f46e5;
29
+ background: rgba(79,70,229,0.12);
30
+ }
31
+ .__li2-tagger-tooltip {
32
+ display: none; pointer-events: none; z-index: 99998;
33
+ background: #1a1a2e; color: #e0e7ff; font-family: monospace;
34
+ font-size: 11px; padding: 3px 8px; border-radius: 4px;
35
+ white-space: nowrap; max-width: 400px; overflow: hidden;
36
+ text-overflow: ellipsis; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
37
+ }
38
+ .__li2-tagger-panel {
39
+ position: fixed; bottom: 60px; right: 20px; z-index: 99999;
40
+ width: 380px; max-height: 520px; overflow-y: auto;
41
+ background: #1a1a2e; color: #e0e7ff; border-radius: 12px;
42
+ font-family: -apple-system, sans-serif; font-size: 13px;
43
+ box-shadow: 0 8px 32px rgba(0,0,0,0.4);
44
+ line-height: 1.4; box-sizing: border-box;
45
+ }
46
+ .__li2-tagger-panel * { box-sizing: border-box; margin: 0; padding: 0; }
47
+ .__li2-tagger-panel-header {
48
+ display: flex; justify-content: space-between; align-items: center;
49
+ padding: 12px 16px; border-bottom: 1px solid #2a2a4e;
50
+ font-weight: 600; font-size: 14px;
51
+ }
52
+ .__li2-tagger-panel-close {
53
+ background: none; border: none; color: #999; cursor: pointer;
54
+ font-size: 18px; padding: 2px 6px; border-radius: 4px;
55
+ }
56
+ .__li2-tagger-panel-close:hover { color: #fff; background: rgba(255,255,255,0.1); }
57
+ .__li2-tagger-summary {
58
+ padding: 8px 16px; color: #a5b4fc; font-size: 12px;
59
+ border-bottom: 1px solid #2a2a4e;
60
+ }
61
+ .__li2-tagger-field { padding: 10px 16px 4px; }
62
+ .__li2-tagger-label {
63
+ display: block; padding: 6px 16px 4px; color: #94a3b8;
64
+ font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
65
+ }
66
+ .__li2-tagger-input {
67
+ width: 100%; padding: 8px 10px; border-radius: 6px;
68
+ border: 1px solid #3a3a5e; background: #0f0f23; color: #e0e7ff;
69
+ font-size: 13px; font-family: monospace; outline: none;
70
+ }
71
+ .__li2-tagger-input:focus { border-color: #6366f1; }
72
+ .__li2-tagger-input:disabled { opacity: 0.5; }
73
+ .__li2-tagger-field-error { color: #f87171; font-size: 11px; padding: 2px 0 0; min-height: 16px; }
74
+ .__li2-tagger-criterion {
75
+ display: flex; align-items: center; gap: 8px;
76
+ padding: 4px 16px; font-size: 12px;
77
+ }
78
+ .__li2-tagger-criterion input[type=checkbox] { accent-color: #6366f1; flex-shrink: 0; }
79
+ .__li2-tagger-criterion-label { color: #94a3b8; white-space: nowrap; }
80
+ .__li2-tagger-criterion-value {
81
+ color: #e0e7ff; overflow: hidden; text-overflow: ellipsis;
82
+ white-space: nowrap; font-family: monospace; font-size: 11px;
83
+ }
84
+ .__li2-tagger-panel-status {
85
+ padding: 4px 16px; font-size: 12px; min-height: 22px;
86
+ }
87
+ .__li2-tagger-status-loading { color: #fbbf24; }
88
+ .__li2-tagger-status-success { color: #4ade80; }
89
+ .__li2-tagger-status-error { color: #f87171; }
90
+ .__li2-tagger-btn-row {
91
+ display: flex; justify-content: flex-end; gap: 8px;
92
+ padding: 8px 16px 12px;
93
+ }
94
+ .__li2-tagger-btn {
95
+ padding: 7px 14px; border-radius: 6px; font-size: 13px;
96
+ cursor: pointer; border: none; font-weight: 500;
97
+ }
98
+ .__li2-tagger-btn-cancel { background: #2a2a4e; color: #e0e7ff; }
99
+ .__li2-tagger-btn-cancel:hover { background: #3a3a5e; }
100
+ .__li2-tagger-btn-submit { background: #6366f1; color: #fff; }
101
+ .__li2-tagger-btn-submit:hover { background: #4f46e5; }
102
+ .__li2-tagger-btn-submit:disabled { opacity: 0.5; cursor: not-allowed; }
103
+ .__li2-tagger-rules-header {
104
+ padding: 8px 16px 4px; color: #64748b; font-size: 11px;
105
+ text-transform: uppercase; letter-spacing: 0.5px;
106
+ border-top: 1px solid #2a2a4e; margin-top: 4px;
107
+ }
108
+ .__li2-tagger-rules-list {
109
+ padding: 0 16px 12px; max-height: 100px; overflow-y: auto;
110
+ }
111
+ .__li2-tagger-rules-empty { color: #64748b; font-size: 12px; padding: 4px 0; }
112
+ .__li2-tagger-rule-item { color: #94a3b8; font-size: 12px; padding: 2px 0; }
113
+ `,document.head.appendChild(i)}function Q(){let i=new Date;return i.setDate(i.getDate()-7),i.toISOString().slice(0,10)}function Z(){return new Date().toISOString().slice(0,10)}var y=class{constructor(e){this.heatmapOverlay=null;this.taggerOverlay=null;this.taggerMode=null;this.taggerPanel=null;this.ui=null;this.selectedElement=null;this.onElementSelected=null;this.apiUrl=e.apiUrl,this.publishableKey=e.publishableKey,this.mode=e.mode||"heatmap",this.sessionToken=e.sessionToken}async activate(){if(!this.sessionToken){L(),this.ui=new v({mode:this.mode,initialOpacity:.6,onOpacityChange:()=>{},onClose:()=>this.deactivate()}),this.ui.mount(),this.ui.setError("Session expired. Please reopen from the dashboard.");return}L(),this.mode==="tagger"?this.activateTagger():await this.activateHeatmap()}deactivate(){this.heatmapOverlay?.unmount(),this.heatmapOverlay=null,this.taggerMode?.deactivate(),this.taggerMode=null,this.taggerPanel?.unmount(),this.taggerPanel=null,this.taggerOverlay?.unmount(),this.taggerOverlay=null,this.ui?.unmount(),this.ui=null,this.selectedElement=null;let e=new URL(window.location.href);e.searchParams.delete("li2_heatmap"),e.searchParams.delete("li2_tagger"),e.searchParams.delete("li2_session"),e.searchParams.delete("li2_from"),e.searchParams.delete("li2_to"),e.searchParams.delete("li2_device"),history.replaceState(null,"",e.toString())}async activateHeatmap(){let e=this.parseHeatmapParams();e&&(this.heatmapOverlay=new b,this.heatmapOverlay.mount(),this.ui=new v({mode:"heatmap",initialOpacity:.6,onOpacityChange:t=>this.heatmapOverlay?.setOpacity(t),onClose:()=>this.deactivate()}),this.ui.mount(),await this.fetchAndRender(e))}parseHeatmapParams(){let e=new URL(window.location.href);return e.searchParams.has("li2_heatmap")?{from:e.searchParams.get("li2_from")??Q(),to:e.searchParams.get("li2_to")??Z(),deviceType:e.searchParams.get("li2_device")??void 0}:null}async fetchAndRender(e){this.ui?.setLoading(!0);try{let t=await k({apiUrl:this.apiUrl,publishableKey:this.publishableKey,sessionToken:this.sessionToken,pagePath:window.location.pathname,from:e.from,to:e.to,deviceType:e.deviceType,targetWidth:window.innerWidth});this.heatmapOverlay?.render(t.grid),this.ui?.setStats(t.total_clicks,t.grid.length)}catch{this.ui?.setError("Failed to load heatmap data")}finally{this.ui?.setLoading(!1)}}activateTagger(){this.taggerOverlay=new x,this.taggerOverlay.mount(),this.taggerPanel=new _({apiConfig:{apiUrl:this.apiUrl,publishableKey:this.publishableKey,sessionToken:this.sessionToken},onCancel:()=>{this.taggerOverlay?.clearHighlight(),this.taggerOverlay?.clearSelection(),this.selectedElement=null,this.ui?.setStatus("Click an element to tag")},onCreated:()=>{this.taggerOverlay?.clearHighlight(),this.taggerOverlay?.clearSelection(),this.selectedElement=null,this.ui?.setStatus("Click an element to tag")}}),this.taggerPanel.mount(),this.taggerMode=new E(this.taggerOverlay,{onElementSelected:(e,t)=>{this.selectedElement={element:e,info:t},this.ui?.setStatus("Element selected"),this.taggerPanel?.show(t),this.onElementSelected?.({element:e,info:t})}}),this.taggerMode.activate(),this.ui=new v({mode:"tagger",initialOpacity:.6,onOpacityChange:()=>{},onClose:()=>this.deactivate()}),this.ui.mount()}};if(typeof window<"u"&&window.__li2ToolbarConfig){let i=window.__li2ToolbarConfig;delete window.__li2ToolbarConfig;let e=new y(i);window.__li2Toolbar=e,e.activate()}0&&(module.exports={ToolbarManager});
@@ -1,4 +1,4 @@
1
- async function y(a){let t=new URL(`${a.apiUrl}/api/v1/track/heatmap/clicks`);t.searchParams.set("page_path",a.pagePath),t.searchParams.set("from",a.from),t.searchParams.set("to",a.to),t.searchParams.set("target_width",String(a.targetWidth)),a.deviceType&&t.searchParams.set("device_type",a.deviceType);let e=await fetch(t.toString(),{headers:{"X-Li2-Key":a.publishableKey}});if(!e.ok)throw new Error(`Heatmap API error: ${e.status}`);return(await e.json()).data.heatmap}var f=[[0,[0,0,255,128]],[.25,[0,255,255,200]],[.5,[0,255,0,220]],[.75,[255,255,0,240]],[1,[255,0,0,255]]];function x(a){if(a<=0)return[0,0,0,0];let t=Math.min(1,Math.max(0,a));for(let e=0;e<f.length-1;e++){let[i,n]=f[e],[d,l]=f[e+1];if(t>=i&&t<=d){let s=(t-i)/(d-i);return[Math.round(n[0]+(l[0]-n[0])*s),Math.round(n[1]+(l[1]-n[1])*s),Math.round(n[2]+(l[2]-n[2])*s),Math.round(n[3]+(l[3]-n[3])*s)]}}return[255,0,0,255]}var T=30;function _(a,t,e,i,n=T){let d=a.getContext("2d");if(!d||t.length===0||e===0||i===0)return;a.width=e,a.height=i;let l=Math.max(...t.map(o=>o.count));if(l===0)return;let s=document.createElement("canvas");s.width=e,s.height=i;let r=s.getContext("2d");if(!r)return;r.fillStyle="black",r.fillRect(0,0,e,i),r.globalCompositeOperation="lighter";for(let o of t){if(o.x<-n||o.x>e+n||o.y<-n||o.y>i+n)continue;let u=o.count/l,c=r.createRadialGradient(o.x,o.y,0,o.x,o.y,n);c.addColorStop(0,`rgba(255,255,255,${u})`),c.addColorStop(.33,`rgba(255,255,255,${u*.607})`),c.addColorStop(.67,`rgba(255,255,255,${u*.135})`),c.addColorStop(1,"rgba(255,255,255,0)"),r.fillStyle=c,r.beginPath(),r.arc(o.x,o.y,n,0,Math.PI*2),r.fill()}let b=r.getImageData(0,0,e,i).data,v=d.createImageData(e,i),p=v.data;for(let o=0;o<b.length;o+=4){let u=b[o]/255;if(u>.01){let[c,E,w,P]=x(u);p[o]=c,p[o+1]=E,p[o+2]=w,p[o+3]=P}}d.putImageData(v,0,0)}var h=class{constructor(){this.grid=[];this.handleResize=()=>{this.resize(),this.doRender()};this.canvas=document.createElement("canvas"),this.canvas.style.cssText="position:absolute;top:0;left:0;pointer-events:none;z-index:99998;"}mount(){document.body.appendChild(this.canvas),this.resize(),window.addEventListener("resize",this.handleResize)}unmount(){this.canvas.remove(),window.removeEventListener("resize",this.handleResize)}render(t){this.grid=t,this.doRender()}setOpacity(t){this.canvas.style.opacity=String(t)}resize(){let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight;this.canvas.style.width=`${t}px`,this.canvas.style.height=`${e}px`}doRender(){if(this.grid.length===0)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight;_(this.canvas,this.grid,t,e)}};var m=class{constructor(t){this.root=null;this.statsEl=null;this.statusEl=null;this.config=t}mount(){this.root=document.createElement("div"),this.root.className="__li2-toolbar";let t=document.createElement("span");t.textContent="Li2 Heatmap",this.root.appendChild(t),this.root.appendChild(this.createSeparator()),this.statsEl=document.createElement("span"),this.statsEl.className="__li2-toolbar-stat",this.statsEl.textContent="...",this.root.appendChild(this.statsEl),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.root.appendChild(this.statusEl);let e=document.createElement("input");e.type="range",e.min="0",e.max="100",e.value=String(Math.round(this.config.initialOpacity*100)),e.className="__li2-toolbar-slider",e.addEventListener("input",()=>{this.config.onOpacityChange(Number(e.value)/100)}),this.root.appendChild(e);let i=document.createElement("button");i.className="__li2-toolbar-close",i.textContent="\xD7",i.title="Close heatmap",i.addEventListener("click",this.config.onClose),this.root.appendChild(i),document.body.appendChild(this.root)}unmount(){this.root?.remove(),this.root=null}setStats(t,e){this.statsEl&&(this.statsEl.textContent=`${t.toLocaleString()} clicks`)}setLoading(t){this.statusEl&&(t?(this.statusEl.className="__li2-toolbar-loading",this.statusEl.textContent="Loading..."):(this.statusEl.textContent="",this.statusEl.className=""))}setError(t){this.statusEl&&(this.statusEl.className="__li2-toolbar-error",this.statusEl.textContent=t)}createSeparator(){let t=document.createElement("span");return t.style.cssText="color:#555;user-select:none;",t.textContent="|",t}};function C(){if(document.getElementById("__li2-toolbar-styles"))return;let a=document.createElement("style");a.id="__li2-toolbar-styles",a.textContent=`
1
+ import{a as y}from"../chunk-FF6VDEL5.mjs";async function k(n){let e=new URL(`${n.apiUrl}/api/v1/track/heatmap/clicks`);e.searchParams.set("page_path",n.pagePath),e.searchParams.set("from",n.from),e.searchParams.set("to",n.to),e.searchParams.set("target_width",String(n.targetWidth)),n.deviceType&&e.searchParams.set("device_type",n.deviceType);let t={"X-Li2-Key":n.publishableKey};n.sessionToken&&(t["X-Li2-Session"]=n.sessionToken);let i=await fetch(e.toString(),{headers:t});if(!i.ok)throw new Error(`Heatmap API error: ${i.status}`);return(await i.json()).data.heatmap}var C=[[0,[0,0,255,128]],[.25,[0,255,255,200]],[.5,[0,255,0,220]],[.75,[255,255,0,240]],[1,[255,0,0,255]]];function L(n){if(n<=0)return[0,0,0,0];let e=Math.min(1,Math.max(0,n));for(let t=0;t<C.length-1;t++){let[i,a]=C[t],[r,l]=C[t+1];if(e>=i&&e<=r){let o=(e-i)/(r-i);return[Math.round(a[0]+(l[0]-a[0])*o),Math.round(a[1]+(l[1]-a[1])*o),Math.round(a[2]+(l[2]-a[2])*o),Math.round(a[3]+(l[3]-a[3])*o)]}}return[255,0,0,255]}var O=30;function S(n,e,t,i,a=O){let r=n.getContext("2d");if(!r||e.length===0||t===0||i===0)return;n.width=t,n.height=i;let l=Math.max(...e.map(s=>s.count));if(l===0)return;let o=document.createElement("canvas");o.width=t,o.height=i;let c=o.getContext("2d");if(!c)return;c.fillStyle="black",c.fillRect(0,0,t,i),c.globalCompositeOperation="lighter";for(let s of e){if(s.x<-a||s.x>t+a||s.y<-a||s.y>i+a)continue;let u=s.count/l,d=c.createRadialGradient(s.x,s.y,0,s.x,s.y,a);d.addColorStop(0,`rgba(255,255,255,${u})`),d.addColorStop(.33,`rgba(255,255,255,${u*.607})`),d.addColorStop(.67,`rgba(255,255,255,${u*.135})`),d.addColorStop(1,"rgba(255,255,255,0)"),c.fillStyle=d,c.beginPath(),c.arc(s.x,s.y,a,0,Math.PI*2),c.fill()}let m=c.getImageData(0,0,t,i).data,p=r.createImageData(t,i),h=p.data;for(let s=0;s<m.length;s+=4){let u=m[s]/255;if(u>.01){let[d,R,I,N]=L(u);h[s]=d,h[s+1]=R,h[s+2]=I,h[s+3]=N}}r.putImageData(p,0,0)}var b=class{constructor(){this.grid=[];this.handleResize=()=>{this.resize(),this.doRender()};this.canvas=document.createElement("canvas"),this.canvas.style.cssText="position:absolute;top:0;left:0;pointer-events:none;z-index:99998;"}mount(){document.body.appendChild(this.canvas),this.resize(),window.addEventListener("resize",this.handleResize)}unmount(){this.canvas.remove(),window.removeEventListener("resize",this.handleResize)}render(e){this.grid=e,this.doRender()}setOpacity(e){this.canvas.style.opacity=String(e)}resize(){let e=document.documentElement.scrollWidth,t=document.documentElement.scrollHeight;this.canvas.style.width=`${e}px`,this.canvas.style.height=`${t}px`}doRender(){if(this.grid.length===0)return;let e=document.documentElement.scrollWidth,t=document.documentElement.scrollHeight;S(this.canvas,this.grid,e,t)}};var x=class{constructor(){this.highlight=null;this.tooltip=null;this.currentElement=null}mount(){this.highlight=document.createElement("div"),this.highlight.className="__li2-tagger-highlight",document.body.appendChild(this.highlight),this.tooltip=document.createElement("div"),this.tooltip.className="__li2-tagger-tooltip",document.body.appendChild(this.tooltip)}unmount(){this.highlight?.remove(),this.tooltip?.remove(),this.highlight=null,this.tooltip=null,this.currentElement=null}highlightElement(e){if(!this.highlight||!this.tooltip||e===this.currentElement)return;this.currentElement=e;let t=e.getBoundingClientRect(),i=window.getComputedStyle(e).position==="fixed",a=Math.max(t.width,20),r=Math.max(t.height,20);this.highlight.style.position=i?"fixed":"absolute",this.highlight.style.top=i?`${t.top}px`:`${t.top+window.scrollY}px`,this.highlight.style.left=i?`${t.left}px`:`${t.left+window.scrollX}px`,this.highlight.style.width=`${a}px`,this.highlight.style.height=`${r}px`,this.highlight.style.display="block";let l=e.tagName.toLowerCase(),o=(e.innerText||"").trim().slice(0,40),c=e.id?` #${e.id}`:"",g=o?` "${o}${o.length>=40?"...":""}"`:"";this.tooltip.textContent=`<${l}>${g}${c}`,this.tooltip.style.position=i?"fixed":"absolute";let m=i?t.top-28:t.top+window.scrollY-28;this.tooltip.style.top=`${Math.max(m,4)}px`,this.tooltip.style.left=i?`${t.left}px`:`${t.left+window.scrollX}px`,this.tooltip.style.display="block"}clearHighlight(){this.highlight&&(this.highlight.style.display="none"),this.tooltip&&(this.tooltip.style.display="none"),this.currentElement=null}fixSelection(e){this.highlightElement(e),this.highlight&&this.highlight.classList.add("__li2-tagger-highlight--selected")}clearSelection(){this.highlight&&this.highlight.classList.remove("__li2-tagger-highlight--selected")}updatePosition(){if(this.currentElement){let e=this.currentElement;this.currentElement=null,this.highlightElement(e)}}};var _=class{constructor(e,t){this.active=!1;this.overlay=e,this.callbacks=t,this.handleMouseMove=this.onMouseMove.bind(this),this.handleClick=this.onClick.bind(this),this.handleScroll=this.onScroll.bind(this)}activate(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMouseMove,!0),document.addEventListener("click",this.handleClick,!0),window.addEventListener("scroll",this.handleScroll,!0))}deactivate(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMouseMove,!0),document.removeEventListener("click",this.handleClick,!0),window.removeEventListener("scroll",this.handleScroll,!0),this.overlay.clearHighlight(),this.overlay.clearSelection())}onMouseMove(e){let t=e.target;if(!t)return;if(this.isToolbarElement(t)){this.overlay.clearHighlight();return}if(!y(t)){this.overlay.clearHighlight();return}let a=this.findMeaningfulDomElement(t);a&&this.overlay.highlightElement(a)}onClick(e){let t=e.target;if(!t||this.isToolbarElement(t))return;e.preventDefault(),e.stopPropagation();let i=y(t);if(!i)return;let a=this.findMeaningfulDomElement(t);a&&(this.overlay.fixSelection(a),this.callbacks.onElementSelected(a,i))}onScroll(){this.overlay.updatePosition()}isToolbarElement(e){let t=e;for(;t;){let i=t.className;if(typeof i=="string"&&(i.includes("__li2-toolbar")||i.includes("__li2-tagger")))return!0;t=t.parentElement}return!1}findMeaningfulDomElement(e){let t=new Set(["a","button","input","select","textarea","form","label"]),i=new Set(["button","link","tab","menuitem"]),a=e,r=0;for(;a&&r<5&&a.tagName!=="BODY";){let l=a.tagName.toLowerCase(),o=a.getAttribute("role");if(t.has(l)||o&&i.has(o))return a;a=a.parentElement,r++}return e}};var f=class extends Error{constructor(e,t){super(t),this.status=e}};function M(n){return{"X-Li2-Key":n.publishableKey,"X-Li2-Session":n.sessionToken}}async function P(n,e){let t=await fetch(`${n.apiUrl}/api/v1/track/event-rules`,{method:"POST",headers:{"Content-Type":"application/json",...M(n)},body:JSON.stringify(e)}),i=await t.json().catch(()=>({}));if(!t.ok){let a=i.error||i.message||`Error ${t.status}`;throw new f(t.status,a)}return i.data}async function H(n){let e=await fetch(`${n.apiUrl}/api/v1/track/event-rules`,{headers:M(n)});if(!e.ok)throw new f(e.status,"Failed to load existing rules");return(await e.json()).data||[]}var E=class{constructor(e){this.root=null;this.nameInput=null;this.nameError=null;this.submitBtn=null;this.statusEl=null;this.rulesListEl=null;this.criteriaCheckboxes=new Map;this.existingRules=[];this.currentInfo=null;this.state="idle";this.config=e}mount(){this.root=document.createElement("div"),this.root.className="__li2-tagger-panel",this.root.style.display="none",document.body.appendChild(this.root),this.fetchExistingRules()}unmount(){this.root?.remove(),this.root=null,this.criteriaCheckboxes.clear()}show(e){this.currentInfo=e,this.state="selected",this.buildPanelContent(e),this.root&&(this.root.style.display="block")}hide(){this.currentInfo=null,this.state="idle",this.root&&(this.root.style.display="none",this.root.innerHTML=""),this.criteriaCheckboxes.clear()}buildPanelContent(e){if(!this.root)return;this.root.innerHTML="",this.criteriaCheckboxes.clear();let t=document.createElement("div");t.className="__li2-tagger-panel-header";let i=document.createElement("span");i.textContent="Create Event Rule",t.appendChild(i);let a=document.createElement("button");a.className="__li2-tagger-panel-close",a.textContent="\xD7",a.addEventListener("click",()=>this.handleCancel()),t.appendChild(a),this.root.appendChild(t);let r=document.createElement("div");r.className="__li2-tagger-summary";let l=e.text?` "${e.text.slice(0,30)}${e.text.length>30?"...":""}"`:"";r.textContent=`Selected: <${e.tag}>${l} on ${window.location.pathname}`,this.root.appendChild(r);let o=document.createElement("div");o.className="__li2-tagger-field";let c=document.createElement("label");c.className="__li2-tagger-label",c.textContent="Event name",o.appendChild(c),this.nameInput=document.createElement("input"),this.nameInput.type="text",this.nameInput.placeholder="e.g. signup_click",this.nameInput.className="__li2-tagger-input",this.nameInput.addEventListener("input",()=>this.onNameInput()),o.appendChild(this.nameInput),this.nameError=document.createElement("div"),this.nameError.className="__li2-tagger-field-error",o.appendChild(this.nameError),this.root.appendChild(o);let g=document.createElement("div");g.className="__li2-tagger-label",g.textContent="Match criteria",this.root.appendChild(g);let m=[{key:"selector_path",label:"CSS Selector",value:e.selectorPath||null},{key:"element_text",label:"Text contains",value:e.text||null},{key:"element_id",label:"Element ID",value:e.id||null},{key:"element_href",label:"Link href",value:e.href||null},{key:"page_path",label:"Page path",value:window.location.pathname}];for(let u of m){let d=this.createCriterionRow(u);this.root.appendChild(d)}this.statusEl=document.createElement("div"),this.statusEl.className="__li2-tagger-panel-status",this.root.appendChild(this.statusEl);let p=document.createElement("div");p.className="__li2-tagger-btn-row";let h=document.createElement("button");h.className="__li2-tagger-btn __li2-tagger-btn-cancel",h.textContent="Cancel",h.addEventListener("click",()=>this.handleCancel()),p.appendChild(h),this.submitBtn=document.createElement("button"),this.submitBtn.className="__li2-tagger-btn __li2-tagger-btn-submit",this.submitBtn.textContent="Create Event Rule",this.submitBtn.addEventListener("click",()=>this.handleSubmit()),p.appendChild(this.submitBtn),this.root.appendChild(p);let s=document.createElement("div");s.className="__li2-tagger-rules-header",s.textContent="Existing rules",this.root.appendChild(s),this.rulesListEl=document.createElement("div"),this.rulesListEl.className="__li2-tagger-rules-list",this.renderRulesList(),this.root.appendChild(this.rulesListEl),setTimeout(()=>this.nameInput?.focus(),50)}createCriterionRow(e){let t=document.createElement("div");t.className="__li2-tagger-criterion";let i=document.createElement("input");i.type="checkbox",i.checked=!!e.value,i.disabled=!e.value,i.addEventListener("change",()=>this.updateSubmitState()),this.criteriaCheckboxes.set(e.key,i),t.appendChild(i);let a=document.createElement("span");a.className="__li2-tagger-criterion-label",a.textContent=e.label+":",t.appendChild(a);let r=document.createElement("span");return r.className="__li2-tagger-criterion-value",r.textContent=e.value?z(e.value,60):"(empty)",e.value||(r.style.color="#666"),t.appendChild(r),t}onNameInput(){if(!this.nameInput)return;let e=this.nameInput.value,t=e.toLowerCase().replace(/[^a-z0-9_]/g,"");t!==e&&(this.nameInput.value=t),this.validateName(),this.updateSubmitState()}validateName(){let e=this.nameInput?.value||"",t=null;return e?e.length>256?t="Max 256 characters":/^[a-z0-9_]+$/.test(e)?this.existingRules.some(i=>i.name===e)&&(t="Event name already exists"):t="Only lowercase letters, numbers, and underscores":t=null,this.nameError&&(this.nameError.textContent=t||""),t}updateSubmitState(){if(!this.submitBtn)return;let e=!!this.nameInput?.value&&!this.validateName(),t=this.getCheckedCriteria().length>0;this.submitBtn.disabled=!e||!t||this.state==="creating"}getCheckedCriteria(){let e=[];for(let[t,i]of this.criteriaCheckboxes)i.checked&&e.push(t);return e}async handleSubmit(){if(!this.nameInput||!this.currentInfo)return;let e=this.nameInput.value;if(!e||this.validateName())return;this.state="creating",this.setFormDisabled(!0),this.setStatus("Creating...","loading");let t=new Set(this.getCheckedCriteria()),i=this.currentInfo,a={name:e,selector_path:t.has("selector_path")&&i.selectorPath||void 0,element_text:t.has("element_text")&&i.text||void 0,element_id:t.has("element_id")&&i.id||void 0,element_href:t.has("element_href")&&i.href||void 0,page_path:t.has("page_path")?window.location.pathname:void 0,text_match_mode:t.has("element_text")?"contains":void 0},r={};for(let[l,o]of Object.entries(a))o!==void 0&&(r[l]=o);try{await P(this.config.apiConfig,r),this.state="success",this.setStatus(`Event rule '${e}' created!`,"success"),await this.fetchExistingRules(),setTimeout(()=>{this.hide(),this.config.onCreated(e)},2e3)}catch(l){this.state="error",this.setFormDisabled(!1),l instanceof f?this.setStatus(l.message,"error"):this.setStatus("Connection failed. Please try again.","error")}}handleCancel(){this.hide(),this.config.onCancel()}setFormDisabled(e){this.nameInput&&(this.nameInput.disabled=e),this.submitBtn&&(this.submitBtn.disabled=e,this.submitBtn.textContent=e?"Creating...":"Create Event Rule");for(let t of this.criteriaCheckboxes.values())(t.checked||!e)&&(t.disabled=e?!0:!t.checked)}setStatus(e,t){this.statusEl&&(this.statusEl.textContent=e,this.statusEl.className="__li2-tagger-panel-status",t==="loading"?this.statusEl.classList.add("__li2-tagger-status-loading"):t==="success"?this.statusEl.classList.add("__li2-tagger-status-success"):t==="error"&&this.statusEl.classList.add("__li2-tagger-status-error"))}async fetchExistingRules(){try{this.existingRules=await H(this.config.apiConfig),this.renderRulesList()}catch{}}renderRulesList(){if(this.rulesListEl){if(this.rulesListEl.innerHTML="",this.existingRules.length===0){let e=document.createElement("div");e.className="__li2-tagger-rules-empty",e.textContent="No rules yet",this.rulesListEl.appendChild(e);return}for(let e of this.existingRules){let t=document.createElement("div");t.className="__li2-tagger-rule-item",t.textContent=`\u2022 ${e.name}`,this.rulesListEl.appendChild(t)}}}};function z(n,e){return n.length>e?n.slice(0,e)+"...":n}var v=class{constructor(e){this.root=null;this.statsEl=null;this.statusEl=null;this.config=e}mount(){this.root=document.createElement("div"),this.root.className="__li2-toolbar",this.config.mode==="tagger"?this.mountTagger():this.mountHeatmap(),document.body.appendChild(this.root)}mountHeatmap(){if(!this.root)return;let e=document.createElement("span");e.textContent="Li2 Heatmap",this.root.appendChild(e),this.root.appendChild(this.createSeparator()),this.statsEl=document.createElement("span"),this.statsEl.className="__li2-toolbar-stat",this.statsEl.textContent="...",this.root.appendChild(this.statsEl),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.root.appendChild(this.statusEl);let t=document.createElement("input");t.type="range",t.min="0",t.max="100",t.value=String(Math.round(this.config.initialOpacity*100)),t.className="__li2-toolbar-slider",t.addEventListener("input",()=>{this.config.onOpacityChange(Number(t.value)/100)}),this.root.appendChild(t),this.appendCloseButton("Close heatmap")}mountTagger(){if(!this.root)return;let e=document.createElement("span");e.textContent="Li2 Event Tagger",this.root.appendChild(e),this.root.appendChild(this.createSeparator()),this.statusEl=document.createElement("span"),this.statusEl.className="__li2-toolbar-status",this.statusEl.textContent="Click an element to tag",this.root.appendChild(this.statusEl),this.appendCloseButton("Close tagger")}appendCloseButton(e){if(!this.root)return;let t=document.createElement("button");t.className="__li2-toolbar-close",t.textContent="\xD7",t.title=e,t.addEventListener("click",this.config.onClose),this.root.appendChild(t)}unmount(){this.root?.remove(),this.root=null}setStats(e,t){this.statsEl&&(this.statsEl.textContent=`${e.toLocaleString()} clicks`)}setLoading(e){this.statusEl&&(e?(this.statusEl.className="__li2-toolbar-loading",this.statusEl.textContent="Loading..."):(this.statusEl.textContent="",this.statusEl.className=""))}setStatus(e){this.statusEl&&(this.statusEl.className="__li2-toolbar-status",this.statusEl.textContent=e)}setError(e){this.statusEl&&(this.statusEl.className="__li2-toolbar-error",this.statusEl.textContent=e)}createSeparator(){let e=document.createElement("span");return e.style.cssText="color:#555;user-select:none;",e.textContent="|",e}};function w(){if(document.getElementById("__li2-toolbar-styles"))return;let n=document.createElement("style");n.id="__li2-toolbar-styles",n.textContent=`
2
2
  .__li2-toolbar {
3
3
  position: fixed; bottom: 20px; right: 20px; z-index: 99999;
4
4
  background: #1a1a2e; color: #fff; border-radius: 12px;
@@ -17,4 +17,97 @@ async function y(a){let t=new URL(`${a.apiUrl}/api/v1/track/heatmap/clicks`);t.s
17
17
  .__li2-toolbar-stat { color: #a5b4fc; font-variant-numeric: tabular-nums; }
18
18
  .__li2-toolbar-loading { color: #fbbf24; }
19
19
  .__li2-toolbar-error { color: #f87171; }
20
- `,document.head.appendChild(a)}function S(){let a=new Date;return a.setDate(a.getDate()-7),a.toISOString().slice(0,10)}function H(){return new Date().toISOString().slice(0,10)}var g=class{constructor(t){this.overlay=null;this.ui=null;this.apiUrl=t.apiUrl,this.publishableKey=t.publishableKey}async activate(){let t=this.parseUrlParams();t&&(C(),this.overlay=new h,this.overlay.mount(),this.ui=new m({initialOpacity:.6,onOpacityChange:e=>this.overlay?.setOpacity(e),onClose:()=>this.deactivate()}),this.ui.mount(),await this.fetchAndRender(t))}deactivate(){this.overlay?.unmount(),this.ui?.unmount(),this.overlay=null,this.ui=null;let t=new URL(window.location.href);t.searchParams.delete("li2_heatmap"),t.searchParams.delete("li2_from"),t.searchParams.delete("li2_to"),t.searchParams.delete("li2_device"),history.replaceState(null,"",t.toString())}parseUrlParams(){let t=new URL(window.location.href);return t.searchParams.has("li2_heatmap")?{from:t.searchParams.get("li2_from")??S(),to:t.searchParams.get("li2_to")??H(),deviceType:t.searchParams.get("li2_device")??void 0}:null}async fetchAndRender(t){this.ui?.setLoading(!0);try{let e=await y({apiUrl:this.apiUrl,publishableKey:this.publishableKey,pagePath:window.location.pathname,from:t.from,to:t.to,deviceType:t.deviceType,targetWidth:window.innerWidth});this.overlay?.render(e.grid),this.ui?.setStats(e.total_clicks,e.grid.length)}catch{this.ui?.setError("Failed to load heatmap data")}finally{this.ui?.setLoading(!1)}}};if(typeof window<"u"&&window.__li2ToolbarConfig){let a=window.__li2ToolbarConfig;delete window.__li2ToolbarConfig,new g(a).activate()}export{g as ToolbarManager};
20
+ .__li2-toolbar-status { color: #a5b4fc; }
21
+ .__li2-tagger-highlight {
22
+ display: none; pointer-events: none; z-index: 99998;
23
+ border: 2px dashed #6366f1; background: rgba(99,102,241,0.08);
24
+ border-radius: 4px; box-sizing: border-box;
25
+ transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s;
26
+ }
27
+ .__li2-tagger-highlight--selected {
28
+ border-style: solid; border-color: #4f46e5;
29
+ background: rgba(79,70,229,0.12);
30
+ }
31
+ .__li2-tagger-tooltip {
32
+ display: none; pointer-events: none; z-index: 99998;
33
+ background: #1a1a2e; color: #e0e7ff; font-family: monospace;
34
+ font-size: 11px; padding: 3px 8px; border-radius: 4px;
35
+ white-space: nowrap; max-width: 400px; overflow: hidden;
36
+ text-overflow: ellipsis; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
37
+ }
38
+ .__li2-tagger-panel {
39
+ position: fixed; bottom: 60px; right: 20px; z-index: 99999;
40
+ width: 380px; max-height: 520px; overflow-y: auto;
41
+ background: #1a1a2e; color: #e0e7ff; border-radius: 12px;
42
+ font-family: -apple-system, sans-serif; font-size: 13px;
43
+ box-shadow: 0 8px 32px rgba(0,0,0,0.4);
44
+ line-height: 1.4; box-sizing: border-box;
45
+ }
46
+ .__li2-tagger-panel * { box-sizing: border-box; margin: 0; padding: 0; }
47
+ .__li2-tagger-panel-header {
48
+ display: flex; justify-content: space-between; align-items: center;
49
+ padding: 12px 16px; border-bottom: 1px solid #2a2a4e;
50
+ font-weight: 600; font-size: 14px;
51
+ }
52
+ .__li2-tagger-panel-close {
53
+ background: none; border: none; color: #999; cursor: pointer;
54
+ font-size: 18px; padding: 2px 6px; border-radius: 4px;
55
+ }
56
+ .__li2-tagger-panel-close:hover { color: #fff; background: rgba(255,255,255,0.1); }
57
+ .__li2-tagger-summary {
58
+ padding: 8px 16px; color: #a5b4fc; font-size: 12px;
59
+ border-bottom: 1px solid #2a2a4e;
60
+ }
61
+ .__li2-tagger-field { padding: 10px 16px 4px; }
62
+ .__li2-tagger-label {
63
+ display: block; padding: 6px 16px 4px; color: #94a3b8;
64
+ font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
65
+ }
66
+ .__li2-tagger-input {
67
+ width: 100%; padding: 8px 10px; border-radius: 6px;
68
+ border: 1px solid #3a3a5e; background: #0f0f23; color: #e0e7ff;
69
+ font-size: 13px; font-family: monospace; outline: none;
70
+ }
71
+ .__li2-tagger-input:focus { border-color: #6366f1; }
72
+ .__li2-tagger-input:disabled { opacity: 0.5; }
73
+ .__li2-tagger-field-error { color: #f87171; font-size: 11px; padding: 2px 0 0; min-height: 16px; }
74
+ .__li2-tagger-criterion {
75
+ display: flex; align-items: center; gap: 8px;
76
+ padding: 4px 16px; font-size: 12px;
77
+ }
78
+ .__li2-tagger-criterion input[type=checkbox] { accent-color: #6366f1; flex-shrink: 0; }
79
+ .__li2-tagger-criterion-label { color: #94a3b8; white-space: nowrap; }
80
+ .__li2-tagger-criterion-value {
81
+ color: #e0e7ff; overflow: hidden; text-overflow: ellipsis;
82
+ white-space: nowrap; font-family: monospace; font-size: 11px;
83
+ }
84
+ .__li2-tagger-panel-status {
85
+ padding: 4px 16px; font-size: 12px; min-height: 22px;
86
+ }
87
+ .__li2-tagger-status-loading { color: #fbbf24; }
88
+ .__li2-tagger-status-success { color: #4ade80; }
89
+ .__li2-tagger-status-error { color: #f87171; }
90
+ .__li2-tagger-btn-row {
91
+ display: flex; justify-content: flex-end; gap: 8px;
92
+ padding: 8px 16px 12px;
93
+ }
94
+ .__li2-tagger-btn {
95
+ padding: 7px 14px; border-radius: 6px; font-size: 13px;
96
+ cursor: pointer; border: none; font-weight: 500;
97
+ }
98
+ .__li2-tagger-btn-cancel { background: #2a2a4e; color: #e0e7ff; }
99
+ .__li2-tagger-btn-cancel:hover { background: #3a3a5e; }
100
+ .__li2-tagger-btn-submit { background: #6366f1; color: #fff; }
101
+ .__li2-tagger-btn-submit:hover { background: #4f46e5; }
102
+ .__li2-tagger-btn-submit:disabled { opacity: 0.5; cursor: not-allowed; }
103
+ .__li2-tagger-rules-header {
104
+ padding: 8px 16px 4px; color: #64748b; font-size: 11px;
105
+ text-transform: uppercase; letter-spacing: 0.5px;
106
+ border-top: 1px solid #2a2a4e; margin-top: 4px;
107
+ }
108
+ .__li2-tagger-rules-list {
109
+ padding: 0 16px 12px; max-height: 100px; overflow-y: auto;
110
+ }
111
+ .__li2-tagger-rules-empty { color: #64748b; font-size: 12px; padding: 4px 0; }
112
+ .__li2-tagger-rule-item { color: #94a3b8; font-size: 12px; padding: 2px 0; }
113
+ `,document.head.appendChild(n)}function D(){let n=new Date;return n.setDate(n.getDate()-7),n.toISOString().slice(0,10)}function $(){return new Date().toISOString().slice(0,10)}var T=class{constructor(e){this.heatmapOverlay=null;this.taggerOverlay=null;this.taggerMode=null;this.taggerPanel=null;this.ui=null;this.selectedElement=null;this.onElementSelected=null;this.apiUrl=e.apiUrl,this.publishableKey=e.publishableKey,this.mode=e.mode||"heatmap",this.sessionToken=e.sessionToken}async activate(){if(!this.sessionToken){w(),this.ui=new v({mode:this.mode,initialOpacity:.6,onOpacityChange:()=>{},onClose:()=>this.deactivate()}),this.ui.mount(),this.ui.setError("Session expired. Please reopen from the dashboard.");return}w(),this.mode==="tagger"?this.activateTagger():await this.activateHeatmap()}deactivate(){this.heatmapOverlay?.unmount(),this.heatmapOverlay=null,this.taggerMode?.deactivate(),this.taggerMode=null,this.taggerPanel?.unmount(),this.taggerPanel=null,this.taggerOverlay?.unmount(),this.taggerOverlay=null,this.ui?.unmount(),this.ui=null,this.selectedElement=null;let e=new URL(window.location.href);e.searchParams.delete("li2_heatmap"),e.searchParams.delete("li2_tagger"),e.searchParams.delete("li2_session"),e.searchParams.delete("li2_from"),e.searchParams.delete("li2_to"),e.searchParams.delete("li2_device"),history.replaceState(null,"",e.toString())}async activateHeatmap(){let e=this.parseHeatmapParams();e&&(this.heatmapOverlay=new b,this.heatmapOverlay.mount(),this.ui=new v({mode:"heatmap",initialOpacity:.6,onOpacityChange:t=>this.heatmapOverlay?.setOpacity(t),onClose:()=>this.deactivate()}),this.ui.mount(),await this.fetchAndRender(e))}parseHeatmapParams(){let e=new URL(window.location.href);return e.searchParams.has("li2_heatmap")?{from:e.searchParams.get("li2_from")??D(),to:e.searchParams.get("li2_to")??$(),deviceType:e.searchParams.get("li2_device")??void 0}:null}async fetchAndRender(e){this.ui?.setLoading(!0);try{let t=await k({apiUrl:this.apiUrl,publishableKey:this.publishableKey,sessionToken:this.sessionToken,pagePath:window.location.pathname,from:e.from,to:e.to,deviceType:e.deviceType,targetWidth:window.innerWidth});this.heatmapOverlay?.render(t.grid),this.ui?.setStats(t.total_clicks,t.grid.length)}catch{this.ui?.setError("Failed to load heatmap data")}finally{this.ui?.setLoading(!1)}}activateTagger(){this.taggerOverlay=new x,this.taggerOverlay.mount(),this.taggerPanel=new E({apiConfig:{apiUrl:this.apiUrl,publishableKey:this.publishableKey,sessionToken:this.sessionToken},onCancel:()=>{this.taggerOverlay?.clearHighlight(),this.taggerOverlay?.clearSelection(),this.selectedElement=null,this.ui?.setStatus("Click an element to tag")},onCreated:()=>{this.taggerOverlay?.clearHighlight(),this.taggerOverlay?.clearSelection(),this.selectedElement=null,this.ui?.setStatus("Click an element to tag")}}),this.taggerPanel.mount(),this.taggerMode=new _(this.taggerOverlay,{onElementSelected:(e,t)=>{this.selectedElement={element:e,info:t},this.ui?.setStatus("Element selected"),this.taggerPanel?.show(t),this.onElementSelected?.({element:e,info:t})}}),this.taggerMode.activate(),this.ui=new v({mode:"tagger",initialOpacity:.6,onOpacityChange:()=>{},onClose:()=>this.deactivate()}),this.ui.mount()}};if(typeof window<"u"&&window.__li2ToolbarConfig){let n=window.__li2ToolbarConfig;delete window.__li2ToolbarConfig;let e=new T(n);window.__li2Toolbar=e,e.activate()}export{T as ToolbarManager};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@li2/analytics",
3
- "version": "0.3.1-beta.0",
3
+ "version": "0.3.2",
4
4
  "description": "Li2 Analytics SDK for conversion tracking",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -30,17 +30,6 @@
30
30
  "files": [
31
31
  "dist"
32
32
  ],
33
- "scripts": {
34
- "build": "tsup src/index.ts src/outbound.ts src/auto-events.ts src/pageview/index.ts src/click-tracker/index.ts src/toolbar/index.ts --format cjs,esm,iife --dts --minify --global-name li2Analytics",
35
- "build:obfuscate": "tsup src/index.ts src/outbound.ts src/auto-events.ts src/pageview/index.ts src/click-tracker/index.ts src/toolbar/index.ts --format cjs,esm,iife --dts --minify --global-name li2Analytics && node scripts/obfuscate.js",
36
- "dev": "tsup src/index.ts src/outbound.ts src/auto-events.ts src/pageview/index.ts src/click-tracker/index.ts src/toolbar/index.ts --format cjs,esm,iife --dts --watch --global-name li2Analytics",
37
- "demo": "pnpm run build && node demo/server.js",
38
- "demo:serve": "node demo/server.js",
39
- "test": "vitest run",
40
- "test:watch": "vitest",
41
- "test:coverage": "vitest run --coverage",
42
- "prepublishOnly": "pnpm run build:obfuscate"
43
- },
44
33
  "keywords": [
45
34
  "li2",
46
35
  "analytics",
@@ -56,5 +45,15 @@
56
45
  "tsup": "^8.0.0",
57
46
  "typescript": "^5.0.0",
58
47
  "vitest": "^4.0.18"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup src/index.ts src/outbound.ts src/auto-events.ts src/pageview/index.ts src/click-tracker/index.ts src/toolbar/index.ts --format cjs,esm,iife --dts --minify --global-name li2Analytics",
51
+ "build:obfuscate": "tsup src/index.ts src/outbound.ts src/auto-events.ts src/pageview/index.ts src/click-tracker/index.ts src/toolbar/index.ts --format cjs,esm,iife --dts --minify --global-name li2Analytics && node scripts/obfuscate.js",
52
+ "dev": "tsup src/index.ts src/outbound.ts src/auto-events.ts src/pageview/index.ts src/click-tracker/index.ts src/toolbar/index.ts --format cjs,esm,iife --dts --watch --global-name li2Analytics",
53
+ "demo": "pnpm run build && node demo/server.js",
54
+ "demo:serve": "node demo/server.js",
55
+ "test": "vitest run",
56
+ "test:watch": "vitest",
57
+ "test:coverage": "vitest run --coverage"
59
58
  }
60
- }
59
+ }