@varianta/sdk 0.1.1 → 0.1.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.
package/dist/index.cjs.js CHANGED
@@ -4,5 +4,5 @@
4
4
 
5
5
  `;if(i.status===400){const a=await i.json().catch(()=>({}));n+=a.error||"Invalid design data."}else i.status===429?n+="Rate limit exceeded.":i.status>=500&&(n+="Server error.");throw new Error(n)}return i.json()}catch(i){throw i instanceof Error&&i.message.includes("Failed to fetch")?new Error("Network error finalizing design"):i}}async uploadAsset(e,t){try{const i=new FormData;i.append("shopId",t),i.append("file",e);const n=await fetch(`${this.baseUrl}/assets/upload`,{method:"POST",body:i});if(!n.ok){let a=`Failed to upload asset (${n.status} ${n.statusText})
6
6
 
7
- `;if(n.status===400){const s=await n.json().catch(()=>({}));a+=s.error||"Invalid file."}else n.status===413?a+="File too large (max 15MB).":n.status>=500&&(a+="Server error.");throw new Error(a)}return n.json()}catch(i){throw i instanceof Error&&i.message.includes("Failed to fetch")?new Error("Network error uploading asset"):i}}async getStorageUsage(e){try{const t=await fetch(`${this.baseUrl}/assets/usage?shopId=${encodeURIComponent(e)}`);if(!t.ok)throw new Error(`Failed to fetch storage usage (${t.status})`);return t.json()}catch(t){throw t instanceof Error&&t.message.includes("Failed to fetch")?new Error("Network error fetching storage usage"):t}}}function c(f,e,...t){const i=document.createElement(f);return e&&Object.entries(e).forEach(([n,a])=>{n==="class"?i.className=a:n in i?i[n]=a:i.setAttribute(n,String(a))}),t.forEach(n=>{typeof n=="string"?i.appendChild(document.createTextNode(n)):i.appendChild(n)}),i}function W(f,e){let t=null,i=null;const n=(...a)=>{i=a,t&&clearTimeout(t),t=setTimeout(()=>{i&&f(...i),t=null,i=null},e)};return n.flush=()=>{t&&(clearTimeout(t),t=null),i&&(f(...i),i=null)},n.cancel=()=>{t&&(clearTimeout(t),t=null),i=null},n}class G extends M{constructor(){super(),this.percentLabel=c("span",{class:"zoom-percent"},"100%");const e=c("button",{class:"zoom-btn",title:"Zoom out"},"−");e.addEventListener("click",()=>this.emit("zoom-out",void 0));const t=c("button",{class:"zoom-btn",title:"Fit to view"},"Fit");t.addEventListener("click",()=>this.emit("zoom-fit",void 0));const i=c("button",{class:"zoom-btn",title:"Zoom in"},"+");i.addEventListener("click",()=>this.emit("zoom-in",void 0)),this.element=c("div",{class:"zoom-toolbar"}),this.element.appendChild(e),this.element.appendChild(t),this.element.appendChild(i),this.element.appendChild(this.percentLabel)}setZoom(e){this.percentLabel.textContent=`${Math.round(e*100)}%`}getElement(){return this.element}}const J=[{label:"Inter",value:"Inter"},{label:"Arial",value:"Arial"},{label:"Georgia",value:"Georgia"},{label:"Times New Roman",value:"Times New Roman"},{label:"Courier New",value:"Courier New"}],V=[{label:"L",value:"left"},{label:"C",value:"center"},{label:"R",value:"right"}],U=["image/png","image/jpeg","image/webp","image/svg+xml"],K=15*1024*1024;class Q extends M{constructor(e){super(),this.mode="text",this.isSelected=!1,this.textInputEl=null,this.fontSelectEl=null,this.sizeInputEl=null,this.colorInputEl=null,this.alignGroupEl=null,this.area=e;const t=L(e),i=D(e);this.mode=i&&!t?"image":"text",this.element=c("div",{class:"area-card"}),this.element.addEventListener("click",o=>{o.target.tagName==="INPUT"||o.target.tagName==="SELECT"||o.target.tagName==="BUTTON"||this.emit("select",{areaId:e.id})});const n=c("div",{class:"area-card-header"}),a=c("div",{class:"area-card-name-row"}),s=c("span",{class:"area-card-name"},e.name);if(a.appendChild(s),e.required){const o=c("span",{class:"area-card-badge"},"Required");a.appendChild(o)}n.appendChild(a);const r=c("button",{class:"area-card-reset-btn",title:"Reset content"},"Reset");if(r.addEventListener("click",o=>{o.stopPropagation(),this.emit("clear",{areaId:e.id})}),n.appendChild(r),this.element.appendChild(n),t&&i){const o=c("div",{class:"area-card-mode-switcher"}),d=c("button",{class:"mode-btn mode-btn-active"},"Text");d.dataset.mode="text";const l=c("button",{class:"mode-btn"},"Image");l.dataset.mode="image",d.addEventListener("click",h=>{h.stopPropagation(),this.setMode("text"),d.classList.add("mode-btn-active"),l.classList.remove("mode-btn-active"),this.currentContent?.type==="image"&&this.emit("clear",{areaId:e.id})}),l.addEventListener("click",h=>{h.stopPropagation(),this.setMode("image"),l.classList.add("mode-btn-active"),d.classList.remove("mode-btn-active"),this.currentContent?.type==="text"&&this.emit("clear",{areaId:e.id})}),o.appendChild(d),o.appendChild(l),this.element.appendChild(o)}this.contentContainer=c("div",{class:"area-card-content"}),this.element.appendChild(this.contentContainer),this.transformContainer=c("div",{class:"area-card-transforms"}),this.element.appendChild(this.transformContainer),this.renderContent()}setMode(e){this.mode=e,this.renderContent()}setContent(e){const t=this.currentContent?.type;this.currentContent=e,e?.type==="image"&&(this.mode="image"),this.element.querySelectorAll(".mode-btn").forEach(i=>{const n=i;n.classList.toggle("mode-btn-active",n.dataset.mode===this.mode)}),e?.type!==t||e?.type==="image"||e===void 0?this.renderContent():e?.type==="text"&&this.updateTextValues(e),this.renderTransforms()}setSelected(e){this.isSelected=e,this.element.classList.toggle("area-card-selected",e),this.renderTransforms()}updateTextValues(e){this.textInputEl&&this.textInputEl.value!==e.text&&(this.textInputEl.value=e.text),this.fontSelectEl&&this.fontSelectEl.value!==e.font&&(this.fontSelectEl.value=e.font),this.sizeInputEl&&this.sizeInputEl.value!==String(e.size)&&(this.sizeInputEl.value=String(e.size)),this.colorInputEl&&this.colorInputEl.value!==e.color&&(this.colorInputEl.value=e.color),this.alignGroupEl&&this.alignGroupEl.querySelectorAll(".align-btn").forEach(t=>{const i=t,n=i.title==="Left"?"left":i.title==="Center"?"center":"right";i.classList.toggle("align-btn-active",n===e.align)})}renderContent(){this.contentContainer.innerHTML="",this.textInputEl=null,this.fontSelectEl=null,this.sizeInputEl=null,this.colorInputEl=null,this.alignGroupEl=null;const e=L(this.area),t=D(this.area),i=!t||e&&t&&this.mode==="text",n=!e||e&&t&&this.mode==="image";e&&i&&this.renderTextControls(),t&&n&&this.renderImageControls()}renderTextControls(){const e=this.currentContent,t=e?.type==="text"?e:k(this.area),i=c("input",{class:"area-input-text",type:"text",placeholder:this.area.placeholder||"Enter text..."});i.value=t.text,this.area.textOptions?.maxLength&&(i.maxLength=this.area.textOptions.maxLength),i.addEventListener("input",()=>{this.emit("text:change",{areaId:this.area.id,updates:{text:i.value}})}),this.contentContainer.appendChild(i),this.textInputEl=i;const n=c("div",{class:"area-input-row"}),a=c("select",{class:"area-input-font"});for(const l of J){const h=c("option");h.value=l.value,h.textContent=l.label,l.value===t.font&&(h.selected=!0),a.appendChild(h)}a.addEventListener("change",()=>{this.emit("text:change",{areaId:this.area.id,updates:{font:a.value}})}),n.appendChild(a),this.fontSelectEl=a;const s=c("input",{class:"area-input-size",type:"number"});s.value=String(t.size),s.min=String(this.area.textOptions?.minSize||8),s.max=String(this.area.textOptions?.maxSize||200),s.addEventListener("change",()=>{this.emit("text:change",{areaId:this.area.id,updates:{size:parseInt(s.value,10)||24}})}),n.appendChild(s),this.sizeInputEl=s,this.contentContainer.appendChild(n);const r=c("div",{class:"area-input-row"}),o=c("div",{class:"area-input-align"});for(const l of V){const h=c("button",{class:`align-btn${t.align===l.value?" align-btn-active":""}`,title:l.label==="L"?"Left":l.label==="C"?"Center":"Right"},l.label);h.addEventListener("click",u=>{u.stopPropagation(),this.emit("text:change",{areaId:this.area.id,updates:{align:l.value}}),o.querySelectorAll(".align-btn").forEach(g=>g.classList.remove("align-btn-active")),h.classList.add("align-btn-active")}),o.appendChild(h)}r.appendChild(o),this.alignGroupEl=o;const d=c("input",{class:"area-input-color",type:"color"});d.value=t.color,d.addEventListener("input",()=>{this.emit("text:change",{areaId:this.area.id,updates:{color:d.value}})}),r.appendChild(d),this.colorInputEl=d,this.contentContainer.appendChild(r)}renderImageControls(){const e=this.currentContent;if(e?.type==="image"){const t=c("div",{class:"area-image-preview"}),i=c("img",{class:"area-image-thumb"});i.src=e.dataUrl,i.alt=e.filename||"Uploaded image",t.appendChild(i);const n=c("div",{class:"area-image-info"});n.appendChild(c("span",{class:"area-image-name"},e.filename||"Image"));const a=c("button",{class:"area-image-remove-btn"},"Remove");a.addEventListener("click",s=>{s.stopPropagation(),this.emit("clear",{areaId:this.area.id})}),n.appendChild(a),t.appendChild(n),this.contentContainer.appendChild(t)}else{const t=c("button",{class:"area-upload-btn"},"Upload Image"),i=c("input",{type:"file"});i.accept=U.join(","),i.style.display="none";const n=c("div",{class:"area-validation-error"});n.style.display="none",i.addEventListener("change",()=>{const a=i.files?.[0];if(!a)return;if(!U.includes(a.type)){const r="Only PNG, JPEG, WebP, and SVG images are accepted";n.textContent=r,n.style.display="block",this.emit("validation:error",{areaId:this.area.id,message:r}),i.value="";return}if(a.size>K){const r="File must be smaller than 15MB";n.textContent=r,n.style.display="block",this.emit("validation:error",{areaId:this.area.id,message:r}),i.value="";return}n.style.display="none";const s=new FileReader;s.onload=()=>{const r=s.result;this.emit("image:change",{areaId:this.area.id,dataUrl:r,filename:a.name})},s.readAsDataURL(a),i.value=""}),t.addEventListener("click",a=>{a.stopPropagation(),i.click()}),this.contentContainer.appendChild(t),this.contentContainer.appendChild(i),this.contentContainer.appendChild(n)}}renderTransforms(){this.transformContainer.innerHTML="";const e=this.currentContent;if(!this.isSelected||!e)return;const t=e.type==="text"?this.area.textOptions?.allowPositioning:this.area.imageOptions?.allowPositioning,i=e.type==="image"&&this.area.imageOptions?.allowScaling,n=e.type==="image"&&this.area.imageOptions?.allowRotation;if(!t&&!i&&!n)return;const a=c("div",{class:"area-card-divider"});this.transformContainer.appendChild(a);const s=c("div",{class:"transform-header"});s.appendChild(c("span",{class:"transform-title"},"Transform"));const r=c("button",{class:"transform-reset-btn"},"Reset");r.addEventListener("click",d=>{d.stopPropagation(),t&&this.emit("offset:change",{areaId:this.area.id,offset:{x:0,y:0}}),i&&this.emit("scale:change",{areaId:this.area.id,scale:1}),n&&this.emit("rotation:change",{areaId:this.area.id,rotation:0})}),s.appendChild(r),this.transformContainer.appendChild(s);const o=e.offset??{x:0,y:0};if(t){const d=c("div",{class:"area-input-row"}),l=c("label",{class:"transform-label"},"X"),h=c("input",{class:"transform-input",type:"number"});h.value=String(Math.round(o.x)),h.addEventListener("change",()=>{this.emit("offset:change",{areaId:this.area.id,offset:{...o,x:parseInt(h.value,10)||0}})});const u=c("label",{class:"transform-label"},"Y"),g=c("input",{class:"transform-input",type:"number"});g.value=String(Math.round(o.y)),g.addEventListener("change",()=>{this.emit("offset:change",{areaId:this.area.id,offset:{...o,y:parseInt(g.value,10)||0}})}),d.appendChild(l),d.appendChild(h),d.appendChild(u),d.appendChild(g),this.transformContainer.appendChild(d)}if(i&&e.type==="image"){const d=e.scale??1,l=c("div",{class:"area-input-row transform-slider-row"}),h=c("label",{class:"transform-label"},`Scale: ${Math.round(d*100)}%`),u=c("input",{class:"transform-slider",type:"range"});u.min="10",u.max="500",u.step="5",u.value=String(Math.round(d*100)),u.addEventListener("input",()=>{const g=parseInt(u.value,10)/100;h.textContent=`Scale: ${Math.round(g*100)}%`,this.emit("scale:change",{areaId:this.area.id,scale:g})}),l.appendChild(h),l.appendChild(u),this.transformContainer.appendChild(l)}if(n&&e.type==="image"){const d=e.rotation??0,l=c("div",{class:"area-input-row transform-slider-row"}),h=c("label",{class:"transform-label"},`Rotation: ${Math.round(d)}°`),u=c("input",{class:"transform-slider",type:"range"});u.min="0",u.max="360",u.step="1",u.value=String(Math.round(d)),u.addEventListener("input",()=>{const g=parseInt(u.value,10);h.textContent=`Rotation: ${g}°`,this.emit("rotation:change",{areaId:this.area.id,rotation:g})}),l.appendChild(h),l.appendChild(u),this.transformContainer.appendChild(l)}}getElement(){return this.element}}class _ extends M{constructor(e){super(),this.cards=new Map,this.isMobile=!1,this.boundEscapeHandler=n=>{n.key==="Escape"&&this.emit("dismiss",void 0)},this.backdrop=c("div",{class:"area-panel-backdrop"}),this.backdrop.addEventListener("click",()=>{this.emit("dismiss",void 0)}),this.element=c("div",{class:"area-panel"});const t=c("div",{class:"area-panel-header"});t.appendChild(c("span",{class:"area-panel-title"},"Customize"));const i=c("button",{class:"area-panel-close-btn",title:"Close"},"×");if(i.addEventListener("click",()=>{this.emit("dismiss",void 0)}),t.appendChild(i),this.element.appendChild(t),this.panelContent=c("div",{class:"area-panel-content"}),e.length===0){const n=c("p",{class:"area-panel-empty"},"No customization areas defined.");this.panelContent.appendChild(n)}else for(const n of e){const a=new Q(n);this.cards.set(n.id,a),a.on("text:change",s=>this.emit("text:change",s)),a.on("image:change",s=>this.emit("image:change",s)),a.on("clear",s=>this.emit("clear",s)),a.on("select",s=>this.emit("select",s)),a.on("offset:change",s=>this.emit("offset:change",s)),a.on("scale:change",s=>this.emit("scale:change",s)),a.on("rotation:change",s=>this.emit("rotation:change",s)),a.on("validation:error",s=>this.emit("validation:error",s)),this.panelContent.appendChild(a.getElement())}this.element.appendChild(this.panelContent)}setContents(e){for(const[t,i]of this.cards)i.setContent(e.get(t))}setSelectedArea(e){for(const[t,i]of this.cards){const n=t===e;i.setSelected(n),i.getElement().style.display=n?"":"none"}e?(this.element.classList.add("area-panel-visible"),this.isMobile&&this.backdrop.classList.add("area-panel-backdrop-visible"),document.addEventListener("keydown",this.boundEscapeHandler)):(this.element.classList.remove("area-panel-visible"),this.isMobile&&this.backdrop.classList.remove("area-panel-backdrop-visible"),document.removeEventListener("keydown",this.boundEscapeHandler))}setMobile(e){this.isMobile=e,this.element.classList.toggle("area-panel-mobile",e),e||(this.element.classList.remove("area-panel-visible"),this.backdrop.classList.remove("area-panel-backdrop-visible"))}getElement(){return this.element}getBackdrop(){return this.backdrop}}class ee{constructor(e=window){this.target=e,this.commands=[],this.isEnabled=!0,this.handleKeyDown=t=>{if(!this.isEnabled)return;const i=t.target;if(!(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.isContentEditable)){for(const n of this.commands)if(this.matchesCommand(t,n)){t.preventDefault(),n.handler(t);break}}},this.target.addEventListener("keydown",this.handleKeyDown)}register(e){return this.commands.push(e),()=>{const t=this.commands.indexOf(e);t!==-1&&this.commands.splice(t,1)}}enable(){this.isEnabled=!0}disable(){this.isEnabled=!1}isActive(){return this.isEnabled}matchesCommand(e,t){return!(e.key.toLowerCase()!==t.key.toLowerCase()||t.ctrl!==void 0&&t.ctrl!==e.ctrlKey||t.shift!==void 0&&t.shift!==e.shiftKey||t.alt!==void 0&&t.alt!==e.altKey||t.meta!==void 0&&t.meta!==e.metaKey)}destroy(){this.target.removeEventListener("keydown",this.handleKeyDown),this.commands=[]}}function te(){return/Mac|iPod|iPhone|iPad/.test(navigator.platform)}function ie(){return te()?"meta":"ctrl"}function ne(f,e,t,i){const n=f/t,a=e/i;return Math.min(n,a)}function ae(f,e,t=8,i=10,n=300){const a=ne(f,e,t,i),s=a>=n;return{actualDPI:Math.round(a),targetDPI:n,width:f,height:e,passed:s,warning:s?void 0:`Image resolution is ${Math.round(a)} DPI at 100% scale. For best print quality, use images with at least ${n} DPI. This may result in pixelated or blurry prints.`}}const R=':host{--editor-bg: #f3f4f6;--editor-surface: #ffffff;--editor-border: #e5e7eb;--editor-text: #111827;--editor-text-muted: #6b7280;--editor-primary: #3b82f6;--editor-primary-hover: #2563eb;--editor-danger: #ef4444;--editor-radius: 8px;--editor-radius-sm: 4px;--editor-font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--editor-panel-width: 280px;display:block;width:100%;height:100%;font-family:var(--editor-font);font-size:13px;color:var(--editor-text);line-height:1.4}:host([theme="dark"]){--editor-bg: #1f2937;--editor-surface: #374151;--editor-border: #4b5563;--editor-text: #f9fafb;--editor-text-muted: #9ca3af}.editor-container{display:flex;flex-direction:column;width:100%;height:100%;position:relative;overflow:hidden;background:var(--editor-bg)}.layout-desktop .editor-main{display:flex;flex:1;min-height:0}.layout-desktop .canvas-area{flex:1;min-width:0;position:relative;display:flex;flex-direction:column}.layout-desktop .area-panel{width:var(--editor-panel-width);border-left:1px solid var(--editor-border);background:var(--editor-surface);display:none;flex-direction:column;overflow:hidden}.layout-desktop .area-panel.area-panel-visible{display:flex}.layout-mobile .editor-main{display:flex;flex-direction:column;flex:1;min-height:0}.layout-mobile .canvas-area{flex:1;position:relative;display:flex;flex-direction:column;min-height:0}.layout-mobile .area-panel{position:absolute;bottom:0;left:0;right:0;max-height:50%;background:var(--editor-surface);border-top:1px solid var(--editor-border);border-radius:var(--editor-radius) var(--editor-radius) 0 0;box-shadow:0 -4px 20px #00000026;transform:translateY(100%);transition:transform .25s ease-out;z-index:20;display:flex;flex-direction:column;overflow:hidden}.layout-mobile .area-panel.area-panel-visible{transform:translateY(0)}.area-panel-backdrop{display:none}.layout-mobile .area-panel-backdrop{display:block;position:absolute;inset:0;background:#0000004d;z-index:15;opacity:0;pointer-events:none;transition:opacity .25s ease-out}.layout-mobile .area-panel-backdrop.area-panel-backdrop-visible{opacity:1;pointer-events:auto}.zoom-toolbar{display:flex;align-items:center;gap:4px;padding:8px 12px;background:var(--editor-surface);border-bottom:1px solid var(--editor-border)}.zoom-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:var(--editor-surface);color:var(--editor-text);cursor:pointer;font-size:14px;font-family:var(--editor-font);transition:background .15s;-webkit-tap-highlight-color:transparent;touch-action:manipulation}.zoom-btn:hover{background:var(--editor-bg)}.zoom-btn:active{background:var(--editor-border)}.zoom-percent{margin-left:8px;font-size:12px;color:var(--editor-text-muted);min-width:40px}.canvas-wrapper{flex:1;position:relative;overflow:hidden;min-height:200px}.editor-canvas{position:absolute;top:0;left:0}.area-panel-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--editor-border);flex-shrink:0}.area-panel-title{font-weight:600;font-size:14px}.area-panel-close-btn{width:28px;height:28px;border:none;background:none;color:var(--editor-text-muted);cursor:pointer;font-size:18px;line-height:1;border-radius:var(--editor-radius-sm);display:flex;align-items:center;justify-content:center}.area-panel-close-btn:hover{background:var(--editor-bg);color:var(--editor-text)}.area-panel-content{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:12px}.area-panel-empty{color:var(--editor-text-muted);font-size:12px;text-align:center;padding:20px 0}.area-card{padding:12px;border:1px solid var(--editor-border);border-radius:var(--editor-radius);background:var(--editor-surface);cursor:pointer;transition:border-color .15s}.area-card:hover{border-color:var(--editor-primary)}.area-card-selected{border-color:var(--editor-primary);box-shadow:0 0 0 1px var(--editor-primary)}.area-card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.area-card-name-row{display:flex;align-items:center;gap:6px}.area-card-name{font-weight:600;font-size:13px}.area-card-badge{display:inline-block;padding:1px 6px;font-size:10px;font-weight:500;background:#fef3c7;color:#92400e;border-radius:10px}.area-card-reset-btn{padding:2px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:none;color:var(--editor-text-muted);cursor:pointer;font-size:11px;font-family:var(--editor-font)}.area-card-reset-btn:hover{background:var(--editor-bg);color:var(--editor-danger);border-color:var(--editor-danger)}.area-card-mode-switcher{display:flex;gap:4px;margin-bottom:8px}.mode-btn{flex:1;padding:4px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:var(--editor-surface);color:var(--editor-text);cursor:pointer;font-size:12px;font-family:var(--editor-font);transition:all .15s}.mode-btn-active{background:var(--editor-primary);color:#fff;border-color:var(--editor-primary)}.area-input-text{width:100%;padding:6px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:13px;color:var(--editor-text);background:var(--editor-surface);box-sizing:border-box;margin-bottom:6px}.area-input-text:focus{outline:none;border-color:var(--editor-primary);box-shadow:0 0 0 1px var(--editor-primary)}.area-input-row{display:flex;gap:6px;align-items:center;margin-bottom:6px}.area-input-font{flex:1;padding:4px 6px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:12px;color:var(--editor-text);background:var(--editor-surface);min-width:0}.area-input-size{width:56px;padding:4px 6px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:12px;color:var(--editor-text);background:var(--editor-surface)}.area-input-align{display:flex;gap:2px}.align-btn{width:28px;height:28px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:var(--editor-surface);color:var(--editor-text);cursor:pointer;font-size:12px;font-weight:600;font-family:var(--editor-font)}.align-btn-active{background:var(--editor-primary);color:#fff;border-color:var(--editor-primary)}.area-input-color{width:32px;height:28px;padding:0;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);cursor:pointer;background:none}.area-upload-btn{width:100%;padding:10px;border:2px dashed var(--editor-border);border-radius:var(--editor-radius);background:var(--editor-bg);color:var(--editor-text-muted);cursor:pointer;font-family:var(--editor-font);font-size:12px;text-align:center;transition:all .15s;min-height:44px}.area-upload-btn:hover{border-color:var(--editor-primary);color:var(--editor-primary)}.area-image-preview{display:flex;gap:8px;align-items:center}.area-image-thumb{width:48px;height:48px;object-fit:cover;border-radius:var(--editor-radius-sm);border:1px solid var(--editor-border)}.area-image-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.area-image-name{font-size:12px;color:var(--editor-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.area-image-remove-btn{padding:2px 8px;border:1px solid var(--editor-danger);border-radius:var(--editor-radius-sm);background:none;color:var(--editor-danger);cursor:pointer;font-size:11px;font-family:var(--editor-font);width:fit-content}.area-image-remove-btn:hover{background:#fef2f2}.area-card-divider{height:1px;background:var(--editor-border);margin:8px 0}.transform-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.transform-title{font-weight:600;font-size:12px}.transform-reset-btn{padding:2px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:none;color:var(--editor-text-muted);cursor:pointer;font-size:11px;font-family:var(--editor-font)}.transform-reset-btn:hover{background:var(--editor-bg)}.transform-label{font-size:11px;color:var(--editor-text-muted);white-space:nowrap}.transform-input{width:60px;padding:3px 6px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:12px;color:var(--editor-text);background:var(--editor-surface)}.transform-slider-row{flex-direction:column;align-items:stretch}.transform-slider{width:100%;accent-color:var(--editor-primary)}.loading-container{display:flex;justify-content:center;align-items:center;width:100%;height:100%;min-height:200px}.loading-spinner{width:32px;height:32px;border:3px solid var(--editor-border);border-top-color:var(--editor-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error-container{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%;min-height:200px;padding:20px;text-align:center}.error-title{font-weight:600;font-size:16px;color:var(--editor-danger);margin-bottom:8px}.error-message{font-size:13px;color:var(--editor-text-muted);max-width:400px;white-space:pre-wrap}:host(:focus){outline:2px solid var(--editor-primary);outline-offset:-2px}input:focus,select:focus,button:focus-visible{outline:2px solid var(--editor-primary);outline-offset:-1px}.context-menu{position:absolute;z-index:100;min-width:160px;background:var(--editor-surface);border:1px solid var(--editor-border);border-radius:var(--editor-radius);box-shadow:0 4px 12px #00000026;padding:4px 0;font-size:13px}.context-menu-header{padding:6px 12px;font-weight:600;font-size:12px;color:var(--editor-text-muted);user-select:none}.context-menu-divider{height:1px;background:var(--editor-border);margin:4px 0}.context-menu-item{padding:6px 12px;cursor:pointer;color:var(--editor-text);user-select:none;transition:background .1s}.context-menu-item:hover{background:var(--editor-bg)}.context-menu-item:active{background:var(--editor-border)}.context-menu-item-disabled{color:var(--editor-text-muted);cursor:default;pointer-events:none}.editor-toast{position:absolute;top:16px;left:50%;transform:translate(-50%);padding:10px 20px;border-radius:var(--editor-radius);font-size:13px;font-family:var(--editor-font);line-height:1.4;z-index:200;max-width:400px;text-align:center;animation:toast-in .25s ease-out,toast-out .25s ease-in forwards;animation-delay:0s,var(--toast-duration, 3.75s);pointer-events:none;box-shadow:0 4px 12px #00000026}.editor-toast-warning{background:#fef3c7;color:#92400e;border:1px solid #f59e0b}.editor-toast-error{background:#fef2f2;color:#991b1b;border:1px solid var(--editor-danger)}.editor-toast-info{background:#eff6ff;color:#1e40af;border:1px solid var(--editor-primary)}@keyframes toast-in{0%{opacity:0;transform:translate(-50%) translateY(-10px)}to{opacity:1;transform:translate(-50%) translateY(0)}}@keyframes toast-out{0%{opacity:1;transform:translate(-50%) translateY(0)}to{opacity:0;transform:translate(-50%) translateY(-10px)}}.editor-modal-overlay{position:absolute;inset:0;background:#0006;z-index:300;display:flex;align-items:center;justify-content:center;animation:modal-overlay-in .2s ease-out}@keyframes modal-overlay-in{0%{opacity:0}to{opacity:1}}.editor-modal{background:var(--editor-surface);border-radius:var(--editor-radius);box-shadow:0 8px 32px #0003;max-width:380px;width:calc(100% - 32px);padding:20px;animation:modal-in .2s ease-out}@keyframes modal-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.editor-modal-title{font-weight:600;font-size:15px;margin-bottom:8px;color:var(--editor-text)}.editor-modal-body{font-size:13px;color:var(--editor-text-muted);margin-bottom:16px;line-height:1.5}.editor-modal-actions{display:flex;justify-content:flex-end;gap:8px}.editor-modal-btn{padding:8px 16px;border-radius:var(--editor-radius-sm);font-size:13px;font-family:var(--editor-font);cursor:pointer;border:1px solid var(--editor-border);background:var(--editor-surface);color:var(--editor-text);transition:background .15s}.editor-modal-btn:hover{background:var(--editor-bg)}.editor-modal-btn-primary{background:var(--editor-primary);color:#fff;border-color:var(--editor-primary)}.editor-modal-btn-primary:hover{background:var(--editor-primary-hover)}.area-validation-error{font-size:11px;color:var(--editor-danger);margin-top:4px}@media(pointer:coarse){.zoom-btn{min-width:44px;min-height:44px}.area-input-text,.area-input-font,.area-input-size{min-height:44px;font-size:16px}.align-btn{min-width:44px;min-height:44px}.area-upload-btn{min-height:48px}}',re="2.0.0",se=768;class oe extends HTMLElement{constructor(){super(),this.resizeObserver=null,this.isReady=!1,this.currentTemplate=null,this.loadingTemplateId=null,this.isMobileLayout=!1,this.subscriptions=[],this.storageUsage=null,this.storageUsageLastRefresh=0,this.emitChange=W(()=>{this.dispatchEvent(new CustomEvent("change",{detail:{design:this.getDesign()},bubbles:!0,composed:!0}))},300),this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["template-id","theme","mode","store-id","api-url"]}async connectedCallback(){try{this.hasAttribute("tabindex")||this.setAttribute("tabindex","0"),this.renderLoading(),await this.initialize()}catch(e){this.showError("Failed to initialize editor",e)}}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,i){t!==i&&e==="template-id"&&this.isReady&&i&&this.loadTemplate(i)}getDesign(){if(!this.currentTemplate)throw new Error("No design loaded");return{templateId:this.currentTemplate.metadata.id,engineVersion:re,contents:this.contentManager.toJSON(),userData:{}}}setDesign(e){if(e.templateId!==this.currentTemplate?.metadata.id)throw new Error("Design template ID does not match current template");this.contentManager.fromJSON(e.contents),this.syncEngineContents(),this.stateManager.setState({contents:this.contentManager.toJSON(),isDirty:!0})}undo(){this.stateManager.undo()&&this.syncFromState()}redo(){this.stateManager.redo()&&this.syncFromState()}clear(){this.contentManager.reset(),this.syncEngineContents(),this.stateManager.setState({contents:this.contentManager.toJSON(),selectedAreaId:null,isDirty:!1}),this.engine.setSelectedArea(null),this.inputPanel.setSelectedArea(null),this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()})}selectArea(e){this.handleAreaSelect(e)}getSelectedAreaId(){return this.stateManager.getState().selectedAreaId}setAreaContent(e,t){t.type==="text"?this.contentManager.setTextContent(e,t):this.contentManager.setImageContent(e,t.dataUrl,t.filename),this.syncEngineContents(),this.saveContentState()}getAreaContent(e){return this.contentManager.getContent(e)}async finalize(){const e=this.engine.checkSafeAreaViolations();if(e.length>0){const a=this.currentTemplate?.areas||[],s=e.map(r=>a.find(o=>o.id===r)?.name||r).join(", ");if(!await this.showConfirmation("Content outside safe area",`Content in ${s} extends beyond the safe area. It may be trimmed during printing. Continue?`,"Cancel","Proceed Anyway"))throw new Error("Finalization cancelled by user")}const t=this.getDesign(),i=this.getAttribute("store-id")||"demo-shop",n=await this.apiClient.finalizeDesign(i,t);return this.dispatchEvent(new CustomEvent("customizer:finalize",{detail:{designId:n.designId,proofUrl:n.proofUrl,templateId:t.templateId,designJson:t,status:n.status},bubbles:!0,composed:!0})),n}renderLoading(){const e=document.createElement("style");e.textContent=R,this.shadow.appendChild(e);const t=c("div",{class:"loading-container"},c("div",{class:"loading-spinner"}));this.shadow.appendChild(t)}async initialize(){const e=this.getAttribute("api-url")||"http://localhost:4000/public";this.apiClient=new X(e);const t=this.getAttribute("template-id");if(!t)throw new Error("template-id attribute is required");await this.loadTemplate(t),this.isReady=!0,this.dispatchEvent(new CustomEvent("ready",{bubbles:!0,composed:!0}))}async loadTemplate(e){if(this.loadingTemplateId!==e){this.loadingTemplateId=e;try{const t=await this.apiClient.getTemplate(e);if(this.loadingTemplateId!==e)return;this.currentTemplate=t;const i=t.areas||[];this.contentManager=new B(i);const n={template:t,contents:this.contentManager.toJSON(),selectedAreaId:null,zoom:1,pan:{x:0,y:0},isDirty:!1,warnings:[]};this.stateManager=new q(n),this.buildUI(t,i),this.engine=new Z(this.canvas),this.engine.setArtboard({width:t.artboard.width,height:t.artboard.height,backgroundColor:t.artboard.backgroundColor??"#ffffff"}),this.engine.setAreas(i),this.engine.setContents(this.contentManager.getContents()),t.backgroundImage&&this.engine.setBackgroundImage(t.backgroundImage);const a=t.artboard.safeArea??t.safeArea;a&&this.engine.setSafeArea(a),this.engine.start(),this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom()),this.interaction=new j(this.canvas,this.engine,()=>this.contentManager.getContents(),()=>this.stateManager.getState().selectedAreaId),this.wireInteractionEvents(),this.subscriptions.push(this.contentManager.subscribe(()=>{this.syncEngineContents(),this.inputPanel.setContents(this.contentManager.getContents())})),this.keyboard=new ee(this),this.setupKeyboardShortcuts(),this.inputPanel.setContents(this.contentManager.getContents());const s=this.getAttribute("store-id");s&&this.apiClient.getStorageUsage(s).then(r=>{this.storageUsage=r,r.usagePercent>=100?this.showToast("Storage quota exceeded. Upgrade your plan for more storage.","error"):r.usagePercent>=80&&this.showToast(`Storage ${r.usagePercent}% full. Consider upgrading your plan.`,"warning")}).catch(()=>{}),this.loadingTemplateId=null}catch(t){throw this.loadingTemplateId=null,new Error(`Failed to load template: ${t.message}`)}}}buildUI(e,t){this.shadow.innerHTML="";const i=document.createElement("style");i.textContent=R,this.shadow.appendChild(i),this.container=c("div",{class:"editor-container"}),this.zoomToolbar=new G,this.subscriptions.push(this.zoomToolbar.on("zoom-in",()=>this.handleZoomIn())),this.subscriptions.push(this.zoomToolbar.on("zoom-out",()=>this.handleZoomOut())),this.subscriptions.push(this.zoomToolbar.on("zoom-fit",()=>this.handleZoomFit()));const n=c("div",{class:"canvas-area"});n.appendChild(this.zoomToolbar.getElement()),this.canvasWrapper=c("div",{class:"canvas-wrapper"}),this.canvas=document.createElement("canvas"),this.canvas.className="editor-canvas",this.canvasWrapper.appendChild(this.canvas),n.appendChild(this.canvasWrapper),this.inputPanel=new _(t),this.wireInputPanelEvents();const a=c("div",{class:"editor-main"});a.appendChild(n),a.appendChild(this.inputPanel.getBackdrop()),a.appendChild(this.inputPanel.getElement()),this.container.appendChild(a),this.shadow.appendChild(this.container),this.resizeObserver=new ResizeObserver(s=>{for(const r of s)r.target===this.canvasWrapper&&this.handleCanvasResize(r.contentRect),r.target===this.container&&this.handleLayoutResize(r.contentRect)}),this.resizeObserver.observe(this.canvasWrapper),this.resizeObserver.observe(this.container)}wireInteractionEvents(){this.subscriptions.push(this.interaction.on("area:select",({areaId:e})=>{this.handleAreaSelect(e)})),this.subscriptions.push(this.interaction.on("content:drag",({areaId:e,offset:t})=>{this.contentManager.setContentOffset(e,t),this.saveContentState()})),this.subscriptions.push(this.interaction.on("content:scale",({areaId:e,scale:t})=>{this.contentManager.setImageScale(e,t),this.saveContentState()})),this.subscriptions.push(this.interaction.on("content:rotate",({areaId:e,rotation:t})=>{this.contentManager.setImageRotation(e,t),this.saveContentState()})),this.subscriptions.push(this.interaction.on("zoom",({zoom:e})=>{this.engine.setZoom(e);const t=this.engine.getCenteredPan(e);t&&this.engine.setPan(t),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())})),this.subscriptions.push(this.interaction.on("pan",({pan:e})=>{this.engine.setPan(e),this.stateManager.update({pan:e})})),this.subscriptions.push(this.interaction.on("cursor",({cursor:e})=>{this.canvas.style.cursor=e})),this.subscriptions.push(this.interaction.on("context-menu",({areaId:e,clientX:t,clientY:i})=>{this.handleContextMenu(e,t,i)}))}wireInputPanelEvents(){this.subscriptions.push(this.inputPanel.on("text:change",({areaId:e,updates:t})=>{this.contentManager.setTextContent(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("image:change",async({areaId:e,dataUrl:t,filename:i})=>{const n=this.contentManager.getContents();let a=0;for(const[r,o]of n)o.type==="image"&&r!==e&&a++;if(a>=10){this.showToast("Maximum of 10 images per design reached","error");return}if(await this.refreshStorageUsage(),this.storageUsage&&this.storageUsage.usagePercent>=100){this.showToast("Storage quota exceeded. Upgrade your plan for more storage.","error");return}const s=this.currentTemplate?.areas.find(r=>r.id===e);if(s&&this.currentTemplate){const r=this.currentTemplate.print.targetDpi;try{const o=new Image,d=await new Promise((g,m)=>{o.onload=()=>g({width:o.naturalWidth,height:o.naturalHeight}),o.onerror=()=>m(new Error("Failed to load image")),o.src=t}),l=s.location.width/r,h=s.location.height/r,u=ae(d.width,d.height,l,h,r);if(u.actualDPI<150){if(!await this.showConfirmation("Low resolution detected",`This image is ${u.actualDPI} DPI at print size. Print may appear blurry. Recommended: ${r} DPI.`,"Cancel","Use Anyway"))return}else u.actualDPI<r&&(this.showToast(`Image resolution is ${u.actualDPI} DPI (${r} recommended)`,"warning"),this.stateManager.update({warnings:[...this.stateManager.getState().warnings,{type:"dpi",message:`${u.actualDPI} DPI`,areaId:e}]}))}catch{}}if(this.contentManager.setImageContent(e,t,i),this.saveContentState(),this.storageUsage){const r=Math.round(t.length*.75);this.storageUsage.storageUsed+=r,this.storageUsage.usagePercent=this.storageUsage.storageQuota>0?Math.round(this.storageUsage.storageUsed/this.storageUsage.storageQuota*100):0}})),this.subscriptions.push(this.inputPanel.on("validation:error",({message:e})=>{this.showToast(e,"error")})),this.subscriptions.push(this.inputPanel.on("clear",({areaId:e})=>{this.contentManager.clearContent(e),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("select",({areaId:e})=>{this.handleAreaSelect(e)})),this.subscriptions.push(this.inputPanel.on("offset:change",({areaId:e,offset:t})=>{this.contentManager.setContentOffset(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("scale:change",({areaId:e,scale:t})=>{this.contentManager.setImageScale(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("rotation:change",({areaId:e,rotation:t})=>{this.contentManager.setImageRotation(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("dismiss",()=>{this.handleAreaSelect(null)}))}handleAreaSelect(e,t=!1){this.stateManager.update({selectedAreaId:e}),this.engine.setSelectedArea(e),this.inputPanel.setSelectedArea(t?e:null),e&&document.activeElement!==this&&this.focus(),this.dispatchEvent(new CustomEvent("area:select",{detail:{areaId:e},bubbles:!0,composed:!0}))}handleContextMenu(e,t,i){this.handleAreaSelect(e,!!e)}handleZoomIn(){const e=this.engine.getZoom(),t=Math.min(e*1.25,5),i=this.engine.getCenteredPan(t);this.engine.setZoom(t),i&&this.engine.setPan(i),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())}handleZoomOut(){const e=this.engine.getZoom(),t=Math.max(e*.8,.1),i=this.engine.getCenteredPan(t);this.engine.setZoom(t),i&&this.engine.setPan(i),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())}handleZoomFit(){this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())}handleCanvasResize(e){const{width:t,height:i}=e;if(t===0||i===0)return;const n=window.devicePixelRatio||1;this.canvas.width=t*n,this.canvas.height=i*n,this.canvas.style.width=`${t}px`,this.canvas.style.height=`${i}px`,this.engine&&(this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom()))}handleLayoutResize(e){const t=e.width<se;t!==this.isMobileLayout&&(this.isMobileLayout=t,this.container.classList.toggle("layout-desktop",!t),this.container.classList.toggle("layout-mobile",t),this.inputPanel.setMobile(t))}async refreshStorageUsage(){if(Date.now()-this.storageUsageLastRefresh<3e4)return;const e=this.getAttribute("store-id");if(e)try{this.storageUsage=await this.apiClient.getStorageUsage(e),this.storageUsageLastRefresh=Date.now()}catch{}}saveContentState(){this.stateManager.setState({contents:this.contentManager.toJSON(),isDirty:!0}),this.engine.checkSafeAreaViolations(),this.emitChange()}syncEngineContents(){this.engine?.setContents(this.contentManager.getContents())}syncFromState(){const e=this.stateManager.getState();this.contentManager.setContentsQuiet(e.contents),this.syncEngineContents(),this.inputPanel.setContents(this.contentManager.getContents()),this.engine.setSelectedArea(e.selectedAreaId),this.inputPanel.setSelectedArea(e.selectedAreaId)}setupKeyboardShortcuts(){const e=ie();this.keyboard.register({key:"z",[e]:!0,handler:()=>this.undo()}),this.keyboard.register({key:"z",[e]:!0,shift:!0,handler:()=>this.redo()}),this.keyboard.register({key:"Escape",handler:()=>this.handleAreaSelect(null)})}showToast(e,t="info"){const i=c("div",{class:`editor-toast editor-toast-${t}`},e);this.shadow.appendChild(i),setTimeout(()=>i.remove(),4e3)}showConfirmation(e,t,i="Cancel",n="Continue"){return new Promise(a=>{const s=c("div",{class:"editor-modal-overlay"}),r=c("div",{class:"editor-modal"});r.appendChild(c("div",{class:"editor-modal-title"},e)),r.appendChild(c("div",{class:"editor-modal-body"},t));const o=c("div",{class:"editor-modal-actions"}),d=c("button",{class:"editor-modal-btn"},i);d.addEventListener("click",()=>{s.remove(),a(!1)});const l=c("button",{class:"editor-modal-btn editor-modal-btn-primary"},n);l.addEventListener("click",()=>{s.remove(),a(!0)}),o.appendChild(d),o.appendChild(l),r.appendChild(o),s.appendChild(r),s.addEventListener("click",h=>{h.target===s&&(s.remove(),a(!1))}),this.shadow.appendChild(s)})}showError(e,t){this.shadow.innerHTML="";const i=document.createElement("style");i.textContent=R,this.shadow.appendChild(i);const n=c("div",{class:"error-container"});n.appendChild(c("div",{class:"error-title"},e)),n.appendChild(c("div",{class:"error-message"},t?.message??"")),this.shadow.appendChild(n),this.dispatchEvent(new CustomEvent("error",{detail:{message:e,error:t},bubbles:!0,composed:!0}))}cleanup(){for(const e of this.subscriptions)e();this.subscriptions=[],this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.engine?.destroy(),this.interaction?.destroy(),this.keyboard?.destroy(),this.isReady=!1,this.currentTemplate=null}}customElements.get("customizer-editor")||customElements.define("customizer-editor",oe);function F(f,e){const t=typeof f=="string"?document.querySelector(f):f;if(!t)throw new Error(`Container not found: ${typeof f=="string"?f:"provided element is null"}`);const i=document.createElement("customizer-editor");i.setAttribute("template-id",e.templateId),e.theme&&i.setAttribute("theme",e.theme),e.mode&&i.setAttribute("mode",e.mode),e.className&&i.classList.add(e.className),i.style.width="100%",i.style.height="100%";const n=[],a=(r,o)=>{i.addEventListener(r,o),n.push({event:r,handler:o})};t.innerHTML="",t.appendChild(i);const s={getDesign(){if(typeof i.getDesign!="function")throw new Error("Editor not ready: getDesign method not available");return i.getDesign()},setDesign(r){if(typeof i.setDesign!="function")throw new Error("Editor not ready: setDesign method not available");i.setDesign(r)},undo(){if(typeof i.undo!="function")throw new Error("Editor not ready: undo method not available");i.undo()},redo(){if(typeof i.redo!="function")throw new Error("Editor not ready: redo method not available");i.redo()},canUndo(){return typeof i.canUndo!="function"?!1:i.canUndo()},canRedo(){return typeof i.canRedo!="function"?!1:i.canRedo()},async finalize(){const r=this.getDesign(),o=e.apiUrl||"https://api.varianta.io";try{const d=await fetch(`${o}/public/finalize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({templateId:e.templateId,design:r})});if(!d.ok){const h=await d.json().catch(()=>({message:"Finalization failed"}));throw new Error(h.message||"Finalization failed")}const l=await d.json();return e.onFinalize&&e.onFinalize(l),l}catch(d){const l={code:"FINALIZE_ERROR",message:d instanceof Error?d.message:"Unknown error",details:d};throw e.onError&&e.onError(l),d}},addTextLayer(r){if(typeof i.addTextLayer!="function")throw new Error("Editor not ready: addTextLayer method not available");i.addTextLayer(r)},async addImageLayer(r){if(typeof i.addImageLayer!="function")throw new Error("Editor not ready: addImageLayer method not available");return i.addImageLayer(r)},removeLayer(r){if(typeof i.removeLayer!="function")throw new Error("Editor not ready: removeLayer method not available");i.removeLayer(r)},selectLayer(r){if(typeof i.selectLayer!="function")throw new Error("Editor not ready: selectLayer method not available");i.selectLayer(r)},getSelectedLayerId(){return typeof i.getSelectedLayerId!="function"?null:i.getSelectedLayerId()},setTheme(r){i.setAttribute("theme",r)},setMode(r){i.setAttribute("mode",r)},destroy(){n.forEach(({event:r,handler:o})=>{i.removeEventListener(r,o)}),i.parentNode&&i.parentNode.removeChild(i)},getElement(){return i}};return e.onReady&&a("ready",(()=>{e.onReady?.(s)})),e.onChange&&a("change",(r=>{const o=r.detail.design;e.onChange?.(o)})),e.onLayerSelect&&a("layer:select",(r=>{e.onLayerSelect?.(r.detail.layerId)})),e.onLayerAdd&&a("layer:add",(r=>{e.onLayerAdd?.(r.detail.layerId)})),e.onLayerRemove&&a("layer:remove",(r=>{e.onLayerRemove?.(r.detail.layerId)})),e.onLayerUpdate&&a("layer:update",(r=>{e.onLayerUpdate?.(r.detail.layerId)})),e.onError&&a("error",(r=>{const o=r.detail.error;e.onError?.(o)})),e.initialDesign&&i.addEventListener("ready",()=>{e.initialDesign&&i.setDesign(e.initialDesign)},{once:!0}),e.debug&&(console.log("[Customizer SDK] Initialized with options:",e),console.log("[Customizer SDK] Instance:",s)),s}const O=x.forwardRef((f,e)=>{const{templateId:t,apiUrl:i,theme:n="light",mode:a="edit",debug:s=!1,className:r,style:o,initialDesign:d,onReady:l,onChange:h,onLayerSelect:u,onLayerAdd:g,onLayerRemove:m,onLayerUpdate:b,onError:y,onFinalize:v}=f,C=x.useRef(null),p=x.useRef(null),I=x.useRef({onReady:l,onChange:h,onLayerSelect:u,onLayerAdd:g,onLayerRemove:m,onLayerUpdate:b,onError:y,onFinalize:v});return x.useEffect(()=>{I.current={onReady:l,onChange:h,onLayerSelect:u,onLayerAdd:g,onLayerRemove:m,onLayerUpdate:b,onError:y,onFinalize:v}},[l,h,u,g,m,b,y,v]),x.useEffect(()=>{if(!C.current)return;const E={templateId:t,apiUrl:i,theme:n,mode:a,debug:s,initialDesign:d,onReady:()=>I.current.onReady?.(),onChange:w=>I.current.onChange?.(w),onLayerSelect:w=>I.current.onLayerSelect?.(w),onLayerAdd:w=>I.current.onLayerAdd?.(w),onLayerRemove:w=>I.current.onLayerRemove?.(w),onLayerUpdate:w=>I.current.onLayerUpdate?.(w),onError:w=>I.current.onError?.(w),onFinalize:w=>I.current.onFinalize?.(w)};try{const w=F(C.current,E);p.current=w}catch(w){console.error("[Customizer React] Failed to initialize:",w),I.current.onError?.({code:"INIT_ERROR",message:w instanceof Error?w.message:"Unknown error",details:w})}return()=>{p.current&&(p.current.destroy(),p.current=null)}},[t,i,s,d]),x.useEffect(()=>{p.current&&p.current.setTheme(n)},[n]),x.useEffect(()=>{p.current&&p.current.setMode(a)},[a]),x.useImperativeHandle(e,()=>({getDesign:()=>{if(!p.current)throw new Error("Editor not initialized");return p.current.getDesign()},setDesign:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.setDesign(E)},undo:()=>{if(!p.current)throw new Error("Editor not initialized");p.current.undo()},redo:()=>{if(!p.current)throw new Error("Editor not initialized");p.current.redo()},canUndo:()=>p.current?p.current.canUndo():!1,canRedo:()=>p.current?p.current.canRedo():!1,finalize:async()=>{if(!p.current)throw new Error("Editor not initialized");return p.current.finalize()},addTextLayer:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.addTextLayer(E)},addImageLayer:async E=>{if(!p.current)throw new Error("Editor not initialized");return p.current.addImageLayer(E)},removeLayer:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.removeLayer(E)},selectLayer:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.selectLayer(E)},getSelectedLayerId:()=>p.current?p.current.getSelectedLayerId():null,setTheme:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.setTheme(E)},setMode:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.setMode(E)},destroy:()=>{p.current&&(p.current.destroy(),p.current=null)},getElement:()=>{if(!p.current)throw new Error("Editor not initialized");return p.current.getElement()}}),[]),N.jsx("div",{ref:C,className:r,style:{width:"100%",height:"100%",...o}})});O.displayName="Customizer";function de(f={}){const{autoSave:e=!1,autoSaveKey:t="customizer-design",autoSaveDebounce:i=1e3}=f,n=x.useRef(null),[a,s]=x.useState(null),[r,o]=x.useState(!1),[d,l]=x.useState(!1),[h,u]=x.useState(null),[g,m]=x.useState(!1),[b,y]=x.useState(null),v=x.useRef(void 0);x.useEffect(()=>{if(!(!e||!a))return v.current&&clearTimeout(v.current),v.current=setTimeout(()=>{try{localStorage.setItem(t,JSON.stringify(a))}catch(z){console.error("[useCustomizer] Auto-save failed:",z)}},i),()=>{v.current&&clearTimeout(v.current)}},[a,e,t,i]);const C=x.useCallback(()=>{if(!n.current)return null;try{return n.current.getDesign()}catch(z){return console.error("[useCustomizer] getDesign failed:",z),null}},[]),p=x.useCallback(z=>{if(n.current)try{n.current.setDesign(z),s(z)}catch(S){console.error("[useCustomizer] setDesign failed:",S)}},[]),I=x.useCallback(()=>{if(n.current)try{n.current.undo(),o(n.current.canUndo()),l(n.current.canRedo())}catch(z){console.error("[useCustomizer] undo failed:",z)}},[]),E=x.useCallback(()=>{if(n.current)try{n.current.redo(),o(n.current.canUndo()),l(n.current.canRedo())}catch(z){console.error("[useCustomizer] redo failed:",z)}},[]),w=x.useCallback(async()=>{if(!n.current||g)return null;m(!0);try{const z=await n.current.finalize();return y(z),z}catch(z){return console.error("[useCustomizer] finalize failed:",z),null}finally{m(!1)}},[g]),T=x.useCallback(z=>{if(n.current)try{n.current.addTextLayer(z)}catch(S){console.error("[useCustomizer] addTextLayer failed:",S)}},[]),P=x.useCallback(async z=>{if(n.current)try{await n.current.addImageLayer(z)}catch(S){console.error("[useCustomizer] addImageLayer failed:",S)}},[]),A=x.useCallback(z=>{if(n.current)try{n.current.removeLayer(z)}catch(S){console.error("[useCustomizer] removeLayer failed:",S)}},[]),H=x.useCallback(z=>{if(n.current)try{n.current.selectLayer(z),u(z)}catch(S){console.error("[useCustomizer] selectLayer failed:",S)}},[]);return{customizerRef:n,design:a,canUndo:r,canRedo:d,selectedLayerId:h,isFinalizing:g,finalizeResult:b,getDesign:C,setDesign:p,undo:I,redo:E,finalize:w,addTextLayer:T,addImageLayer:P,removeLayer:A,selectLayer:H}}exports.Customizer=O;exports.initCustomizer=F;exports.useCustomizer=de;
7
+ `;if(n.status===400){const s=await n.json().catch(()=>({}));a+=s.error||"Invalid file."}else n.status===413?a+="File too large (max 15MB).":n.status>=500&&(a+="Server error.");throw new Error(a)}return n.json()}catch(i){throw i instanceof Error&&i.message.includes("Failed to fetch")?new Error("Network error uploading asset"):i}}async getStorageUsage(e){try{const t=await fetch(`${this.baseUrl}/assets/usage?shopId=${encodeURIComponent(e)}`);if(!t.ok)throw new Error(`Failed to fetch storage usage (${t.status})`);return t.json()}catch(t){throw t instanceof Error&&t.message.includes("Failed to fetch")?new Error("Network error fetching storage usage"):t}}}function c(f,e,...t){const i=document.createElement(f);return e&&Object.entries(e).forEach(([n,a])=>{n==="class"?i.className=a:n in i?i[n]=a:i.setAttribute(n,String(a))}),t.forEach(n=>{typeof n=="string"?i.appendChild(document.createTextNode(n)):i.appendChild(n)}),i}function W(f,e){let t=null,i=null;const n=(...a)=>{i=a,t&&clearTimeout(t),t=setTimeout(()=>{i&&f(...i),t=null,i=null},e)};return n.flush=()=>{t&&(clearTimeout(t),t=null),i&&(f(...i),i=null)},n.cancel=()=>{t&&(clearTimeout(t),t=null),i=null},n}class G extends M{constructor(){super(),this.percentLabel=c("span",{class:"zoom-percent"},"100%");const e=c("button",{class:"zoom-btn",title:"Zoom out"},"−");e.addEventListener("click",()=>this.emit("zoom-out",void 0));const t=c("button",{class:"zoom-btn",title:"Fit to view"},"Fit");t.addEventListener("click",()=>this.emit("zoom-fit",void 0));const i=c("button",{class:"zoom-btn",title:"Zoom in"},"+");i.addEventListener("click",()=>this.emit("zoom-in",void 0)),this.element=c("div",{class:"zoom-toolbar"}),this.element.appendChild(e),this.element.appendChild(t),this.element.appendChild(i),this.element.appendChild(this.percentLabel)}setZoom(e){this.percentLabel.textContent=`${Math.round(e*100)}%`}getElement(){return this.element}}const J=[{label:"Inter",value:"Inter"},{label:"Arial",value:"Arial"},{label:"Georgia",value:"Georgia"},{label:"Times New Roman",value:"Times New Roman"},{label:"Courier New",value:"Courier New"}],V=[{label:"L",value:"left"},{label:"C",value:"center"},{label:"R",value:"right"}],U=["image/png","image/jpeg","image/webp","image/svg+xml"],K=15*1024*1024;class Q extends M{constructor(e){super(),this.mode="text",this.isSelected=!1,this.textInputEl=null,this.fontSelectEl=null,this.sizeInputEl=null,this.colorInputEl=null,this.alignGroupEl=null,this.area=e;const t=L(e),i=D(e);this.mode=i&&!t?"image":"text",this.element=c("div",{class:"area-card"}),this.element.addEventListener("click",o=>{o.target.tagName==="INPUT"||o.target.tagName==="SELECT"||o.target.tagName==="BUTTON"||this.emit("select",{areaId:e.id})});const n=c("div",{class:"area-card-header"}),a=c("div",{class:"area-card-name-row"}),s=c("span",{class:"area-card-name"},e.name);if(a.appendChild(s),e.required){const o=c("span",{class:"area-card-badge"},"Required");a.appendChild(o)}n.appendChild(a);const r=c("button",{class:"area-card-reset-btn",title:"Reset content"},"Reset");if(r.addEventListener("click",o=>{o.stopPropagation(),this.emit("clear",{areaId:e.id})}),n.appendChild(r),this.element.appendChild(n),t&&i){const o=c("div",{class:"area-card-mode-switcher"}),d=c("button",{class:"mode-btn mode-btn-active"},"Text");d.dataset.mode="text";const l=c("button",{class:"mode-btn"},"Image");l.dataset.mode="image",d.addEventListener("click",h=>{h.stopPropagation(),this.setMode("text"),d.classList.add("mode-btn-active"),l.classList.remove("mode-btn-active"),this.currentContent?.type==="image"&&this.emit("clear",{areaId:e.id})}),l.addEventListener("click",h=>{h.stopPropagation(),this.setMode("image"),l.classList.add("mode-btn-active"),d.classList.remove("mode-btn-active"),this.currentContent?.type==="text"&&this.emit("clear",{areaId:e.id})}),o.appendChild(d),o.appendChild(l),this.element.appendChild(o)}this.contentContainer=c("div",{class:"area-card-content"}),this.element.appendChild(this.contentContainer),this.transformContainer=c("div",{class:"area-card-transforms"}),this.element.appendChild(this.transformContainer),this.renderContent()}setMode(e){this.mode=e,this.renderContent()}setContent(e){const t=this.currentContent?.type;this.currentContent=e,e?.type==="image"&&(this.mode="image"),this.element.querySelectorAll(".mode-btn").forEach(i=>{const n=i;n.classList.toggle("mode-btn-active",n.dataset.mode===this.mode)}),e?.type!==t||e?.type==="image"||e===void 0?this.renderContent():e?.type==="text"&&this.updateTextValues(e),this.renderTransforms()}setSelected(e){this.isSelected=e,this.element.classList.toggle("area-card-selected",e),this.renderTransforms()}updateTextValues(e){this.textInputEl&&this.textInputEl.value!==e.text&&(this.textInputEl.value=e.text),this.fontSelectEl&&this.fontSelectEl.value!==e.font&&(this.fontSelectEl.value=e.font),this.sizeInputEl&&this.sizeInputEl.value!==String(e.size)&&(this.sizeInputEl.value=String(e.size)),this.colorInputEl&&this.colorInputEl.value!==e.color&&(this.colorInputEl.value=e.color),this.alignGroupEl&&this.alignGroupEl.querySelectorAll(".align-btn").forEach(t=>{const i=t,n=i.title==="Left"?"left":i.title==="Center"?"center":"right";i.classList.toggle("align-btn-active",n===e.align)})}renderContent(){this.contentContainer.innerHTML="",this.textInputEl=null,this.fontSelectEl=null,this.sizeInputEl=null,this.colorInputEl=null,this.alignGroupEl=null;const e=L(this.area),t=D(this.area),i=!t||e&&t&&this.mode==="text",n=!e||e&&t&&this.mode==="image";e&&i&&this.renderTextControls(),t&&n&&this.renderImageControls()}renderTextControls(){const e=this.currentContent,t=e?.type==="text"?e:k(this.area),i=c("input",{class:"area-input-text",type:"text",placeholder:this.area.placeholder||"Enter text..."});i.value=t.text,this.area.textOptions?.maxLength&&(i.maxLength=this.area.textOptions.maxLength),i.addEventListener("input",()=>{this.emit("text:change",{areaId:this.area.id,updates:{text:i.value}})}),this.contentContainer.appendChild(i),this.textInputEl=i;const n=c("div",{class:"area-input-row"}),a=c("select",{class:"area-input-font"});for(const l of J){const h=c("option");h.value=l.value,h.textContent=l.label,l.value===t.font&&(h.selected=!0),a.appendChild(h)}a.addEventListener("change",()=>{this.emit("text:change",{areaId:this.area.id,updates:{font:a.value}})}),n.appendChild(a),this.fontSelectEl=a;const s=c("input",{class:"area-input-size",type:"number"});s.value=String(t.size),s.min=String(this.area.textOptions?.minSize||8),s.max=String(this.area.textOptions?.maxSize||200),s.addEventListener("change",()=>{this.emit("text:change",{areaId:this.area.id,updates:{size:parseInt(s.value,10)||24}})}),n.appendChild(s),this.sizeInputEl=s,this.contentContainer.appendChild(n);const r=c("div",{class:"area-input-row"}),o=c("div",{class:"area-input-align"});for(const l of V){const h=c("button",{class:`align-btn${t.align===l.value?" align-btn-active":""}`,title:l.label==="L"?"Left":l.label==="C"?"Center":"Right"},l.label);h.addEventListener("click",u=>{u.stopPropagation(),this.emit("text:change",{areaId:this.area.id,updates:{align:l.value}}),o.querySelectorAll(".align-btn").forEach(g=>g.classList.remove("align-btn-active")),h.classList.add("align-btn-active")}),o.appendChild(h)}r.appendChild(o),this.alignGroupEl=o;const d=c("input",{class:"area-input-color",type:"color"});d.value=t.color,d.addEventListener("input",()=>{this.emit("text:change",{areaId:this.area.id,updates:{color:d.value}})}),r.appendChild(d),this.colorInputEl=d,this.contentContainer.appendChild(r)}renderImageControls(){const e=this.currentContent;if(e?.type==="image"){const t=c("div",{class:"area-image-preview"}),i=c("img",{class:"area-image-thumb"});i.src=e.dataUrl,i.alt=e.filename||"Uploaded image",t.appendChild(i);const n=c("div",{class:"area-image-info"});n.appendChild(c("span",{class:"area-image-name"},e.filename||"Image"));const a=c("button",{class:"area-image-remove-btn"},"Remove");a.addEventListener("click",s=>{s.stopPropagation(),this.emit("clear",{areaId:this.area.id})}),n.appendChild(a),t.appendChild(n),this.contentContainer.appendChild(t)}else{const t=c("button",{class:"area-upload-btn"},"Upload Image"),i=c("input",{type:"file"});i.accept=U.join(","),i.style.display="none";const n=c("div",{class:"area-validation-error"});n.style.display="none",i.addEventListener("change",()=>{const a=i.files?.[0];if(!a)return;if(!U.includes(a.type)){const r="Only PNG, JPEG, WebP, and SVG images are accepted";n.textContent=r,n.style.display="block",this.emit("validation:error",{areaId:this.area.id,message:r}),i.value="";return}if(a.size>K){const r="File must be smaller than 15MB";n.textContent=r,n.style.display="block",this.emit("validation:error",{areaId:this.area.id,message:r}),i.value="";return}n.style.display="none";const s=new FileReader;s.onload=()=>{const r=s.result;this.emit("image:change",{areaId:this.area.id,dataUrl:r,filename:a.name})},s.readAsDataURL(a),i.value=""}),t.addEventListener("click",a=>{a.stopPropagation(),i.click()}),this.contentContainer.appendChild(t),this.contentContainer.appendChild(i),this.contentContainer.appendChild(n)}}renderTransforms(){this.transformContainer.innerHTML="";const e=this.currentContent;if(!this.isSelected||!e)return;const t=e.type==="text"?this.area.textOptions?.allowPositioning:this.area.imageOptions?.allowPositioning,i=e.type==="image"&&this.area.imageOptions?.allowScaling,n=e.type==="image"&&this.area.imageOptions?.allowRotation;if(!t&&!i&&!n)return;const a=c("div",{class:"area-card-divider"});this.transformContainer.appendChild(a);const s=c("div",{class:"transform-header"});s.appendChild(c("span",{class:"transform-title"},"Transform"));const r=c("button",{class:"transform-reset-btn"},"Reset");r.addEventListener("click",d=>{d.stopPropagation(),t&&this.emit("offset:change",{areaId:this.area.id,offset:{x:0,y:0}}),i&&this.emit("scale:change",{areaId:this.area.id,scale:1}),n&&this.emit("rotation:change",{areaId:this.area.id,rotation:0})}),s.appendChild(r),this.transformContainer.appendChild(s);const o=e.offset??{x:0,y:0};if(t){const d=c("div",{class:"area-input-row"}),l=c("label",{class:"transform-label"},"X"),h=c("input",{class:"transform-input",type:"number"});h.value=String(Math.round(o.x)),h.addEventListener("change",()=>{this.emit("offset:change",{areaId:this.area.id,offset:{...o,x:parseInt(h.value,10)||0}})});const u=c("label",{class:"transform-label"},"Y"),g=c("input",{class:"transform-input",type:"number"});g.value=String(Math.round(o.y)),g.addEventListener("change",()=>{this.emit("offset:change",{areaId:this.area.id,offset:{...o,y:parseInt(g.value,10)||0}})}),d.appendChild(l),d.appendChild(h),d.appendChild(u),d.appendChild(g),this.transformContainer.appendChild(d)}if(i&&e.type==="image"){const d=e.scale??1,l=c("div",{class:"area-input-row transform-slider-row"}),h=c("label",{class:"transform-label"},`Scale: ${Math.round(d*100)}%`),u=c("input",{class:"transform-slider",type:"range"});u.min="10",u.max="500",u.step="5",u.value=String(Math.round(d*100)),u.addEventListener("input",()=>{const g=parseInt(u.value,10)/100;h.textContent=`Scale: ${Math.round(g*100)}%`,this.emit("scale:change",{areaId:this.area.id,scale:g})}),l.appendChild(h),l.appendChild(u),this.transformContainer.appendChild(l)}if(n&&e.type==="image"){const d=e.rotation??0,l=c("div",{class:"area-input-row transform-slider-row"}),h=c("label",{class:"transform-label"},`Rotation: ${Math.round(d)}°`),u=c("input",{class:"transform-slider",type:"range"});u.min="0",u.max="360",u.step="1",u.value=String(Math.round(d)),u.addEventListener("input",()=>{const g=parseInt(u.value,10);h.textContent=`Rotation: ${g}°`,this.emit("rotation:change",{areaId:this.area.id,rotation:g})}),l.appendChild(h),l.appendChild(u),this.transformContainer.appendChild(l)}}getElement(){return this.element}}class _ extends M{constructor(e){super(),this.cards=new Map,this.isMobile=!1,this.boundEscapeHandler=n=>{n.key==="Escape"&&this.emit("dismiss",void 0)},this.backdrop=c("div",{class:"area-panel-backdrop"}),this.backdrop.addEventListener("click",()=>{this.emit("dismiss",void 0)}),this.element=c("div",{class:"area-panel"});const t=c("div",{class:"area-panel-header"});t.appendChild(c("span",{class:"area-panel-title"},"Customize"));const i=c("button",{class:"area-panel-close-btn",title:"Close"},"×");if(i.addEventListener("click",()=>{this.emit("dismiss",void 0)}),t.appendChild(i),this.element.appendChild(t),this.panelContent=c("div",{class:"area-panel-content"}),e.length===0){const n=c("p",{class:"area-panel-empty"},"No customization areas defined.");this.panelContent.appendChild(n)}else for(const n of e){const a=new Q(n);this.cards.set(n.id,a),a.on("text:change",s=>this.emit("text:change",s)),a.on("image:change",s=>this.emit("image:change",s)),a.on("clear",s=>this.emit("clear",s)),a.on("select",s=>this.emit("select",s)),a.on("offset:change",s=>this.emit("offset:change",s)),a.on("scale:change",s=>this.emit("scale:change",s)),a.on("rotation:change",s=>this.emit("rotation:change",s)),a.on("validation:error",s=>this.emit("validation:error",s)),this.panelContent.appendChild(a.getElement())}this.element.appendChild(this.panelContent)}setContents(e){for(const[t,i]of this.cards)i.setContent(e.get(t))}setSelectedArea(e){for(const[t,i]of this.cards){const n=t===e;i.setSelected(n),i.getElement().style.display=n?"":"none"}e?(this.element.classList.add("area-panel-visible"),this.isMobile&&this.backdrop.classList.add("area-panel-backdrop-visible"),document.addEventListener("keydown",this.boundEscapeHandler)):(this.element.classList.remove("area-panel-visible"),this.isMobile&&this.backdrop.classList.remove("area-panel-backdrop-visible"),document.removeEventListener("keydown",this.boundEscapeHandler))}setMobile(e){this.isMobile=e,this.element.classList.toggle("area-panel-mobile",e),e||(this.element.classList.remove("area-panel-visible"),this.backdrop.classList.remove("area-panel-backdrop-visible"))}getElement(){return this.element}getBackdrop(){return this.backdrop}}class ee{constructor(e=window){this.target=e,this.commands=[],this.isEnabled=!0,this.handleKeyDown=t=>{if(!this.isEnabled)return;const i=t.target;if(!(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.isContentEditable)){for(const n of this.commands)if(this.matchesCommand(t,n)){t.preventDefault(),n.handler(t);break}}},this.target.addEventListener("keydown",this.handleKeyDown)}register(e){return this.commands.push(e),()=>{const t=this.commands.indexOf(e);t!==-1&&this.commands.splice(t,1)}}enable(){this.isEnabled=!0}disable(){this.isEnabled=!1}isActive(){return this.isEnabled}matchesCommand(e,t){return!(e.key.toLowerCase()!==t.key.toLowerCase()||t.ctrl!==void 0&&t.ctrl!==e.ctrlKey||t.shift!==void 0&&t.shift!==e.shiftKey||t.alt!==void 0&&t.alt!==e.altKey||t.meta!==void 0&&t.meta!==e.metaKey)}destroy(){this.target.removeEventListener("keydown",this.handleKeyDown),this.commands=[]}}function te(){return/Mac|iPod|iPhone|iPad/.test(navigator.platform)}function ie(){return te()?"meta":"ctrl"}function ne(f,e,t,i){const n=f/t,a=e/i;return Math.min(n,a)}function ae(f,e,t=8,i=10,n=300){const a=ne(f,e,t,i),s=a>=n;return{actualDPI:Math.round(a),targetDPI:n,width:f,height:e,passed:s,warning:s?void 0:`Image resolution is ${Math.round(a)} DPI at 100% scale. For best print quality, use images with at least ${n} DPI. This may result in pixelated or blurry prints.`}}const R=':host{--editor-bg: #f3f4f6;--editor-surface: #ffffff;--editor-border: #e5e7eb;--editor-text: #111827;--editor-text-muted: #6b7280;--editor-primary: #3b82f6;--editor-primary-hover: #2563eb;--editor-danger: #ef4444;--editor-radius: 8px;--editor-radius-sm: 4px;--editor-font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--editor-panel-width: 280px;display:block;width:100%;height:100%;font-family:var(--editor-font);font-size:13px;color:var(--editor-text);line-height:1.4}:host([theme="dark"]){--editor-bg: #1f2937;--editor-surface: #374151;--editor-border: #4b5563;--editor-text: #f9fafb;--editor-text-muted: #9ca3af}.editor-container{display:flex;flex-direction:column;width:100%;height:100%;position:relative;overflow:hidden;background:var(--editor-bg)}.layout-desktop .editor-main{display:flex;flex:1;min-height:0}.layout-desktop .canvas-area{flex:1;min-width:0;position:relative;display:flex;flex-direction:column}.layout-desktop .area-panel{width:var(--editor-panel-width);border-left:1px solid var(--editor-border);background:var(--editor-surface);display:none;flex-direction:column;overflow:hidden}.layout-desktop .area-panel.area-panel-visible{display:flex}.layout-mobile .editor-main{display:flex;flex-direction:column;flex:1;min-height:0}.layout-mobile .canvas-area{flex:1;position:relative;display:flex;flex-direction:column;min-height:0}.layout-mobile .area-panel{position:absolute;bottom:0;left:0;right:0;max-height:50%;background:var(--editor-surface);border-top:1px solid var(--editor-border);border-radius:var(--editor-radius) var(--editor-radius) 0 0;box-shadow:0 -4px 20px #00000026;transform:translateY(100%);transition:transform .25s ease-out;z-index:20;display:flex;flex-direction:column;overflow:hidden}.layout-mobile .area-panel.area-panel-visible{transform:translateY(0)}.area-panel-backdrop{display:none}.layout-mobile .area-panel-backdrop{display:block;position:absolute;inset:0;background:#0000004d;z-index:15;opacity:0;pointer-events:none;transition:opacity .25s ease-out}.layout-mobile .area-panel-backdrop.area-panel-backdrop-visible{opacity:1;pointer-events:auto}.zoom-toolbar{display:flex;align-items:center;gap:4px;padding:8px 12px;background:var(--editor-surface);border-bottom:1px solid var(--editor-border)}.zoom-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:var(--editor-surface);color:var(--editor-text);cursor:pointer;font-size:14px;font-family:var(--editor-font);transition:background .15s;-webkit-tap-highlight-color:transparent;touch-action:manipulation}.zoom-btn:hover{background:var(--editor-bg)}.zoom-btn:active{background:var(--editor-border)}.zoom-percent{margin-left:8px;font-size:12px;color:var(--editor-text-muted);min-width:40px}.canvas-wrapper{flex:1;position:relative;overflow:hidden;min-height:200px}.editor-canvas{position:absolute;top:0;left:0}.area-panel-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--editor-border);flex-shrink:0}.area-panel-title{font-weight:600;font-size:14px}.area-panel-close-btn{width:28px;height:28px;border:none;background:none;color:var(--editor-text-muted);cursor:pointer;font-size:18px;line-height:1;border-radius:var(--editor-radius-sm);display:flex;align-items:center;justify-content:center}.area-panel-close-btn:hover{background:var(--editor-bg);color:var(--editor-text)}.area-panel-content{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:12px}.area-panel-empty{color:var(--editor-text-muted);font-size:12px;text-align:center;padding:20px 0}.area-card{padding:12px;border:1px solid var(--editor-border);border-radius:var(--editor-radius);background:var(--editor-surface);cursor:pointer;transition:border-color .15s}.area-card:hover{border-color:var(--editor-primary)}.area-card-selected{border-color:var(--editor-primary);box-shadow:0 0 0 1px var(--editor-primary)}.area-card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.area-card-name-row{display:flex;align-items:center;gap:6px}.area-card-name{font-weight:600;font-size:13px}.area-card-badge{display:inline-block;padding:1px 6px;font-size:10px;font-weight:500;background:#fef3c7;color:#92400e;border-radius:10px}.area-card-reset-btn{padding:2px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:none;color:var(--editor-text-muted);cursor:pointer;font-size:11px;font-family:var(--editor-font)}.area-card-reset-btn:hover{background:var(--editor-bg);color:var(--editor-danger);border-color:var(--editor-danger)}.area-card-mode-switcher{display:flex;gap:4px;margin-bottom:8px}.mode-btn{flex:1;padding:4px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:var(--editor-surface);color:var(--editor-text);cursor:pointer;font-size:12px;font-family:var(--editor-font);transition:all .15s}.mode-btn-active{background:var(--editor-primary);color:#fff;border-color:var(--editor-primary)}.area-input-text{width:100%;padding:6px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:13px;color:var(--editor-text);background:var(--editor-surface);box-sizing:border-box;margin-bottom:6px}.area-input-text:focus{outline:none;border-color:var(--editor-primary);box-shadow:0 0 0 1px var(--editor-primary)}.area-input-row{display:flex;gap:6px;align-items:center;margin-bottom:6px}.area-input-font{flex:1;padding:4px 6px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:12px;color:var(--editor-text);background:var(--editor-surface);min-width:0}.area-input-size{width:56px;padding:4px 6px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:12px;color:var(--editor-text);background:var(--editor-surface)}.area-input-align{display:flex;gap:2px}.align-btn{width:28px;height:28px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:var(--editor-surface);color:var(--editor-text);cursor:pointer;font-size:12px;font-weight:600;font-family:var(--editor-font)}.align-btn-active{background:var(--editor-primary);color:#fff;border-color:var(--editor-primary)}.area-input-color{width:32px;height:28px;padding:0;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);cursor:pointer;background:none}.area-upload-btn{width:100%;padding:10px;border:2px dashed var(--editor-border);border-radius:var(--editor-radius);background:var(--editor-bg);color:var(--editor-text-muted);cursor:pointer;font-family:var(--editor-font);font-size:12px;text-align:center;transition:all .15s;min-height:44px}.area-upload-btn:hover{border-color:var(--editor-primary);color:var(--editor-primary)}.area-image-preview{display:flex;gap:8px;align-items:center}.area-image-thumb{width:48px;height:48px;object-fit:cover;border-radius:var(--editor-radius-sm);border:1px solid var(--editor-border)}.area-image-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.area-image-name{font-size:12px;color:var(--editor-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.area-image-remove-btn{padding:2px 8px;border:1px solid var(--editor-danger);border-radius:var(--editor-radius-sm);background:none;color:var(--editor-danger);cursor:pointer;font-size:11px;font-family:var(--editor-font);width:fit-content}.area-image-remove-btn:hover{background:#fef2f2}.area-card-divider{height:1px;background:var(--editor-border);margin:8px 0}.transform-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.transform-title{font-weight:600;font-size:12px}.transform-reset-btn{padding:2px 8px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);background:none;color:var(--editor-text-muted);cursor:pointer;font-size:11px;font-family:var(--editor-font)}.transform-reset-btn:hover{background:var(--editor-bg)}.transform-label{font-size:11px;color:var(--editor-text-muted);white-space:nowrap}.transform-input{width:60px;padding:3px 6px;border:1px solid var(--editor-border);border-radius:var(--editor-radius-sm);font-family:var(--editor-font);font-size:12px;color:var(--editor-text);background:var(--editor-surface)}.transform-slider-row{flex-direction:column;align-items:stretch}.transform-slider{width:100%;accent-color:var(--editor-primary)}.loading-container{display:flex;justify-content:center;align-items:center;width:100%;height:100%;min-height:200px}.loading-spinner{width:32px;height:32px;border:3px solid var(--editor-border);border-top-color:var(--editor-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error-container{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%;min-height:200px;padding:20px;text-align:center}.error-title{font-weight:600;font-size:16px;color:var(--editor-danger);margin-bottom:8px}.error-message{font-size:13px;color:var(--editor-text-muted);max-width:400px;white-space:pre-wrap}:host(:focus){outline:2px solid var(--editor-primary);outline-offset:-2px}input:focus,select:focus,button:focus-visible{outline:2px solid var(--editor-primary);outline-offset:-1px}.context-menu{position:absolute;z-index:100;min-width:160px;background:var(--editor-surface);border:1px solid var(--editor-border);border-radius:var(--editor-radius);box-shadow:0 4px 12px #00000026;padding:4px 0;font-size:13px}.context-menu-header{padding:6px 12px;font-weight:600;font-size:12px;color:var(--editor-text-muted);user-select:none}.context-menu-divider{height:1px;background:var(--editor-border);margin:4px 0}.context-menu-item{padding:6px 12px;cursor:pointer;color:var(--editor-text);user-select:none;transition:background .1s}.context-menu-item:hover{background:var(--editor-bg)}.context-menu-item:active{background:var(--editor-border)}.context-menu-item-disabled{color:var(--editor-text-muted);cursor:default;pointer-events:none}.editor-toast{position:absolute;top:16px;left:50%;transform:translate(-50%);padding:10px 20px;border-radius:var(--editor-radius);font-size:13px;font-family:var(--editor-font);line-height:1.4;z-index:200;max-width:400px;text-align:center;animation:toast-in .25s ease-out,toast-out .25s ease-in forwards;animation-delay:0s,var(--toast-duration, 3.75s);pointer-events:none;box-shadow:0 4px 12px #00000026}.editor-toast-warning{background:#fef3c7;color:#92400e;border:1px solid #f59e0b}.editor-toast-error{background:#fef2f2;color:#991b1b;border:1px solid var(--editor-danger)}.editor-toast-info{background:#eff6ff;color:#1e40af;border:1px solid var(--editor-primary)}@keyframes toast-in{0%{opacity:0;transform:translate(-50%) translateY(-10px)}to{opacity:1;transform:translate(-50%) translateY(0)}}@keyframes toast-out{0%{opacity:1;transform:translate(-50%) translateY(0)}to{opacity:0;transform:translate(-50%) translateY(-10px)}}.editor-modal-overlay{position:absolute;inset:0;background:#0006;z-index:300;display:flex;align-items:center;justify-content:center;animation:modal-overlay-in .2s ease-out}@keyframes modal-overlay-in{0%{opacity:0}to{opacity:1}}.editor-modal{background:var(--editor-surface);border-radius:var(--editor-radius);box-shadow:0 8px 32px #0003;max-width:380px;width:calc(100% - 32px);padding:20px;animation:modal-in .2s ease-out}@keyframes modal-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.editor-modal-title{font-weight:600;font-size:15px;margin-bottom:8px;color:var(--editor-text)}.editor-modal-body{font-size:13px;color:var(--editor-text-muted);margin-bottom:16px;line-height:1.5}.editor-modal-actions{display:flex;justify-content:flex-end;gap:8px}.editor-modal-btn{padding:8px 16px;border-radius:var(--editor-radius-sm);font-size:13px;font-family:var(--editor-font);cursor:pointer;border:1px solid var(--editor-border);background:var(--editor-surface);color:var(--editor-text);transition:background .15s}.editor-modal-btn:hover{background:var(--editor-bg)}.editor-modal-btn-primary{background:var(--editor-primary);color:#fff;border-color:var(--editor-primary)}.editor-modal-btn-primary:hover{background:var(--editor-primary-hover)}.area-validation-error{font-size:11px;color:var(--editor-danger);margin-top:4px}@media(pointer:coarse){.zoom-btn{min-width:44px;min-height:44px}.area-input-text,.area-input-font,.area-input-size{min-height:44px;font-size:16px}.align-btn{min-width:44px;min-height:44px}.area-upload-btn{min-height:48px}}',re="2.0.0",se=768;class oe extends HTMLElement{constructor(){super(),this.resizeObserver=null,this.isReady=!1,this.currentTemplate=null,this.loadingTemplateId=null,this.isMobileLayout=!1,this.subscriptions=[],this.storageUsage=null,this.storageUsageLastRefresh=0,this.emitChange=W(()=>{this.dispatchEvent(new CustomEvent("change",{detail:{design:this.getDesign()},bubbles:!0,composed:!0}))},300),this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["template-id","theme","mode","store-id","api-url"]}async connectedCallback(){try{this.hasAttribute("tabindex")||this.setAttribute("tabindex","0"),this.renderLoading(),await this.initialize()}catch(e){this.showError("Failed to initialize editor",e)}}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,i){t!==i&&e==="template-id"&&this.isReady&&i&&this.loadTemplate(i)}getDesign(){if(!this.currentTemplate)throw new Error("No design loaded");return{templateId:this.currentTemplate.metadata.id,engineVersion:re,contents:this.contentManager.toJSON(),userData:{}}}setDesign(e){if(e.templateId!==this.currentTemplate?.metadata.id)throw new Error("Design template ID does not match current template");this.contentManager.fromJSON(e.contents),this.syncEngineContents(),this.stateManager.setState({contents:this.contentManager.toJSON(),isDirty:!0})}undo(){this.stateManager.undo()&&this.syncFromState()}redo(){this.stateManager.redo()&&this.syncFromState()}clear(){this.contentManager.reset(),this.syncEngineContents(),this.stateManager.setState({contents:this.contentManager.toJSON(),selectedAreaId:null,isDirty:!1}),this.engine.setSelectedArea(null),this.inputPanel.setSelectedArea(null),this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()})}selectArea(e){this.handleAreaSelect(e)}getSelectedAreaId(){return this.stateManager.getState().selectedAreaId}setAreaContent(e,t){t.type==="text"?this.contentManager.setTextContent(e,t):this.contentManager.setImageContent(e,t.dataUrl,t.filename),this.syncEngineContents(),this.saveContentState()}getAreaContent(e){return this.contentManager.getContent(e)}async finalize(){const e=this.engine.checkSafeAreaViolations();if(e.length>0){const a=this.currentTemplate?.areas||[],s=e.map(r=>a.find(o=>o.id===r)?.name||r).join(", ");if(!await this.showConfirmation("Content outside safe area",`Content in ${s} extends beyond the safe area. It may be trimmed during printing. Continue?`,"Cancel","Proceed Anyway"))throw new Error("Finalization cancelled by user")}const t=this.getDesign(),i=this.getAttribute("store-id")||"demo-shop",n=await this.apiClient.finalizeDesign(i,t);return this.dispatchEvent(new CustomEvent("customizer:finalize",{detail:{designId:n.designId,proofUrl:n.proofUrl,templateId:t.templateId,designJson:t,status:n.status},bubbles:!0,composed:!0})),n}renderLoading(){const e=document.createElement("style");e.textContent=R,this.shadow.appendChild(e);const t=c("div",{class:"loading-container"},c("div",{class:"loading-spinner"}));this.shadow.appendChild(t)}async initialize(){const e=this.getAttribute("api-url")||"http://localhost:4000/public";this.apiClient=new X(e);const t=this.getAttribute("template-id");if(!t)throw new Error("template-id attribute is required");await this.loadTemplate(t),this.isReady=!0,this.dispatchEvent(new CustomEvent("ready",{bubbles:!0,composed:!0}))}async loadTemplate(e){if(this.loadingTemplateId!==e){this.loadingTemplateId=e;try{const t=await this.apiClient.getTemplate(e);if(this.loadingTemplateId!==e)return;this.currentTemplate=t;const i=t.areas||[];this.contentManager=new B(i);const n={template:t,contents:this.contentManager.toJSON(),selectedAreaId:null,zoom:1,pan:{x:0,y:0},isDirty:!1,warnings:[]};this.stateManager=new q(n),this.buildUI(t,i),this.engine=new Z(this.canvas),this.engine.setArtboard({width:t.artboard.width,height:t.artboard.height,backgroundColor:t.artboard.backgroundColor??"#ffffff"}),this.engine.setAreas(i),this.engine.setContents(this.contentManager.getContents()),t.backgroundImage&&this.engine.setBackgroundImage(t.backgroundImage);const a=t.artboard.safeArea??t.safeArea;a&&this.engine.setSafeArea(a),this.engine.start(),this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom()),this.interaction=new j(this.canvas,this.engine,()=>this.contentManager.getContents(),()=>this.stateManager.getState().selectedAreaId),this.wireInteractionEvents(),this.subscriptions.push(this.contentManager.subscribe(()=>{this.syncEngineContents(),this.inputPanel.setContents(this.contentManager.getContents())})),this.keyboard=new ee(this),this.setupKeyboardShortcuts(),this.inputPanel.setContents(this.contentManager.getContents());const s=this.getAttribute("store-id");s&&this.apiClient.getStorageUsage(s).then(r=>{this.storageUsage=r,r.usagePercent>=100?this.showToast("Storage quota exceeded. Upgrade your plan for more storage.","error"):r.usagePercent>=80&&this.showToast(`Storage ${r.usagePercent}% full. Consider upgrading your plan.`,"warning")}).catch(()=>{}),this.loadingTemplateId=null}catch(t){throw this.loadingTemplateId=null,new Error(`Failed to load template: ${t.message}`)}}}buildUI(e,t){this.shadow.innerHTML="";const i=document.createElement("style");i.textContent=R,this.shadow.appendChild(i),this.container=c("div",{class:"editor-container"}),this.zoomToolbar=new G,this.subscriptions.push(this.zoomToolbar.on("zoom-in",()=>this.handleZoomIn())),this.subscriptions.push(this.zoomToolbar.on("zoom-out",()=>this.handleZoomOut())),this.subscriptions.push(this.zoomToolbar.on("zoom-fit",()=>this.handleZoomFit()));const n=c("div",{class:"canvas-area"});n.appendChild(this.zoomToolbar.getElement()),this.canvasWrapper=c("div",{class:"canvas-wrapper"}),this.canvas=document.createElement("canvas"),this.canvas.className="editor-canvas",this.canvasWrapper.appendChild(this.canvas),n.appendChild(this.canvasWrapper),this.inputPanel=new _(t),this.wireInputPanelEvents();const a=c("div",{class:"editor-main"});a.appendChild(n),a.appendChild(this.inputPanel.getBackdrop()),a.appendChild(this.inputPanel.getElement()),this.container.appendChild(a),this.shadow.appendChild(this.container),this.resizeObserver=new ResizeObserver(s=>{for(const r of s)r.target===this.canvasWrapper&&this.handleCanvasResize(r.contentRect),r.target===this.container&&this.handleLayoutResize(r.contentRect)}),this.resizeObserver.observe(this.canvasWrapper),this.resizeObserver.observe(this.container)}wireInteractionEvents(){this.subscriptions.push(this.interaction.on("area:select",({areaId:e})=>{this.handleAreaSelect(e)})),this.subscriptions.push(this.interaction.on("content:drag",({areaId:e,offset:t})=>{this.contentManager.setContentOffset(e,t),this.saveContentState()})),this.subscriptions.push(this.interaction.on("content:scale",({areaId:e,scale:t})=>{this.contentManager.setImageScale(e,t),this.saveContentState()})),this.subscriptions.push(this.interaction.on("content:rotate",({areaId:e,rotation:t})=>{this.contentManager.setImageRotation(e,t),this.saveContentState()})),this.subscriptions.push(this.interaction.on("zoom",({zoom:e})=>{this.engine.setZoom(e);const t=this.engine.getCenteredPan(e);t&&this.engine.setPan(t),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())})),this.subscriptions.push(this.interaction.on("pan",({pan:e})=>{this.engine.setPan(e),this.stateManager.update({pan:e})})),this.subscriptions.push(this.interaction.on("cursor",({cursor:e})=>{this.canvas.style.cursor=e})),this.subscriptions.push(this.interaction.on("context-menu",({areaId:e,clientX:t,clientY:i})=>{this.handleContextMenu(e,t,i)}))}wireInputPanelEvents(){this.subscriptions.push(this.inputPanel.on("text:change",({areaId:e,updates:t})=>{this.contentManager.setTextContent(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("image:change",async({areaId:e,dataUrl:t,filename:i})=>{const n=this.contentManager.getContents();let a=0;for(const[r,o]of n)o.type==="image"&&r!==e&&a++;if(a>=10){this.showToast("Maximum of 10 images per design reached","error");return}if(await this.refreshStorageUsage(),this.storageUsage&&this.storageUsage.usagePercent>=100){this.showToast("Storage quota exceeded. Upgrade your plan for more storage.","error");return}const s=this.currentTemplate?.areas.find(r=>r.id===e);if(s&&this.currentTemplate){const r=this.currentTemplate.print.targetDpi;try{const o=new Image,d=await new Promise((g,m)=>{o.onload=()=>g({width:o.naturalWidth,height:o.naturalHeight}),o.onerror=()=>m(new Error("Failed to load image")),o.src=t}),l=s.location.width/r,h=s.location.height/r,u=ae(d.width,d.height,l,h,r);if(u.actualDPI<150){if(!await this.showConfirmation("Low resolution detected",`This image is ${u.actualDPI} DPI at print size. Print may appear blurry. Recommended: ${r} DPI.`,"Cancel","Use Anyway"))return}else u.actualDPI<r&&(this.showToast(`Image resolution is ${u.actualDPI} DPI (${r} recommended)`,"warning"),this.stateManager.update({warnings:[...this.stateManager.getState().warnings,{type:"dpi",message:`${u.actualDPI} DPI`,areaId:e}]}))}catch{}}if(this.contentManager.setImageContent(e,t,i),this.saveContentState(),this.storageUsage){const r=Math.round(t.length*.75);this.storageUsage.storageUsed+=r,this.storageUsage.usagePercent=this.storageUsage.storageQuota>0?Math.round(this.storageUsage.storageUsed/this.storageUsage.storageQuota*100):0}})),this.subscriptions.push(this.inputPanel.on("validation:error",({message:e})=>{this.showToast(e,"error")})),this.subscriptions.push(this.inputPanel.on("clear",({areaId:e})=>{this.contentManager.clearContent(e),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("select",({areaId:e})=>{this.handleAreaSelect(e)})),this.subscriptions.push(this.inputPanel.on("offset:change",({areaId:e,offset:t})=>{this.contentManager.setContentOffset(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("scale:change",({areaId:e,scale:t})=>{this.contentManager.setImageScale(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("rotation:change",({areaId:e,rotation:t})=>{this.contentManager.setImageRotation(e,t),this.saveContentState()})),this.subscriptions.push(this.inputPanel.on("dismiss",()=>{this.handleAreaSelect(null)}))}handleAreaSelect(e,t=!1){this.stateManager.update({selectedAreaId:e}),this.engine.setSelectedArea(e),this.inputPanel.setSelectedArea(t?e:null),e&&document.activeElement!==this&&this.focus(),this.dispatchEvent(new CustomEvent("area:select",{detail:{areaId:e},bubbles:!0,composed:!0}))}handleContextMenu(e,t,i){this.handleAreaSelect(e,!!e)}handleZoomIn(){const e=this.engine.getZoom(),t=Math.min(e*1.25,5),i=this.engine.getCenteredPan(t);this.engine.setZoom(t),i&&this.engine.setPan(i),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())}handleZoomOut(){const e=this.engine.getZoom(),t=Math.max(e*.8,.1),i=this.engine.getCenteredPan(t);this.engine.setZoom(t),i&&this.engine.setPan(i),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())}handleZoomFit(){this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom())}handleCanvasResize(e){const{width:t,height:i}=e;if(t===0||i===0)return;const n=window.devicePixelRatio||1;this.canvas.width=t*n,this.canvas.height=i*n,this.canvas.style.width=`${t}px`,this.canvas.style.height=`${i}px`,this.engine&&(this.engine.fitToView(),this.stateManager.update({zoom:this.engine.getZoom(),pan:this.engine.getPan()}),this.zoomToolbar.setZoom(this.engine.getZoom()))}handleLayoutResize(e){const t=e.width<se;t!==this.isMobileLayout&&(this.isMobileLayout=t,this.container.classList.toggle("layout-desktop",!t),this.container.classList.toggle("layout-mobile",t),this.inputPanel.setMobile(t))}async refreshStorageUsage(){if(Date.now()-this.storageUsageLastRefresh<3e4)return;const e=this.getAttribute("store-id");if(e)try{this.storageUsage=await this.apiClient.getStorageUsage(e),this.storageUsageLastRefresh=Date.now()}catch{}}saveContentState(){this.stateManager.setState({contents:this.contentManager.toJSON(),isDirty:!0}),this.engine.checkSafeAreaViolations(),this.emitChange()}syncEngineContents(){this.engine?.setContents(this.contentManager.getContents())}syncFromState(){const e=this.stateManager.getState();this.contentManager.setContentsQuiet(e.contents),this.syncEngineContents(),this.inputPanel.setContents(this.contentManager.getContents()),this.engine.setSelectedArea(e.selectedAreaId),this.inputPanel.setSelectedArea(e.selectedAreaId)}setupKeyboardShortcuts(){const e=ie();this.keyboard.register({key:"z",[e]:!0,handler:()=>this.undo()}),this.keyboard.register({key:"z",[e]:!0,shift:!0,handler:()=>this.redo()}),this.keyboard.register({key:"Escape",handler:()=>this.handleAreaSelect(null)})}showToast(e,t="info"){const i=c("div",{class:`editor-toast editor-toast-${t}`},e);this.shadow.appendChild(i),setTimeout(()=>i.remove(),4e3)}showConfirmation(e,t,i="Cancel",n="Continue"){return new Promise(a=>{const s=c("div",{class:"editor-modal-overlay"}),r=c("div",{class:"editor-modal"});r.appendChild(c("div",{class:"editor-modal-title"},e)),r.appendChild(c("div",{class:"editor-modal-body"},t));const o=c("div",{class:"editor-modal-actions"}),d=c("button",{class:"editor-modal-btn"},i);d.addEventListener("click",()=>{s.remove(),a(!1)});const l=c("button",{class:"editor-modal-btn editor-modal-btn-primary"},n);l.addEventListener("click",()=>{s.remove(),a(!0)}),o.appendChild(d),o.appendChild(l),r.appendChild(o),s.appendChild(r),s.addEventListener("click",h=>{h.target===s&&(s.remove(),a(!1))}),this.shadow.appendChild(s)})}showError(e,t){this.shadow.innerHTML="";const i=document.createElement("style");i.textContent=R,this.shadow.appendChild(i);const n=c("div",{class:"error-container"});n.appendChild(c("div",{class:"error-title"},e)),n.appendChild(c("div",{class:"error-message"},t?.message??"")),this.shadow.appendChild(n),this.dispatchEvent(new CustomEvent("error",{detail:{message:e,error:t},bubbles:!0,composed:!0}))}cleanup(){for(const e of this.subscriptions)e();this.subscriptions=[],this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.engine?.destroy(),this.interaction?.destroy(),this.keyboard?.destroy(),this.isReady=!1,this.currentTemplate=null}}customElements.get("customizer-editor")||customElements.define("customizer-editor",oe);function F(f,e){const t=typeof f=="string"?document.querySelector(f):f;if(!t)throw new Error(`Container not found: ${typeof f=="string"?f:"provided element is null"}`);const i=document.createElement("customizer-editor");i.setAttribute("template-id",e.templateId),e.theme&&i.setAttribute("theme",e.theme),e.mode&&i.setAttribute("mode",e.mode),e.className&&i.classList.add(e.className),i.style.width="100%",i.style.height="100%";const n=[],a=(r,o)=>{i.addEventListener(r,o),n.push({event:r,handler:o})};t.innerHTML="",t.appendChild(i);const s={getDesign(){if(typeof i.getDesign!="function")throw new Error("Editor not ready: getDesign method not available");return i.getDesign()},setDesign(r){if(typeof i.setDesign!="function")throw new Error("Editor not ready: setDesign method not available");i.setDesign(r)},undo(){if(typeof i.undo!="function")throw new Error("Editor not ready: undo method not available");i.undo()},redo(){if(typeof i.redo!="function")throw new Error("Editor not ready: redo method not available");i.redo()},canUndo(){return typeof i.canUndo!="function"?!1:i.canUndo()},canRedo(){return typeof i.canRedo!="function"?!1:i.canRedo()},async finalize(){const r=this.getDesign(),o=e.apiUrl||"https://api.varianta.io";try{const d=await fetch(`${o}/public/finalize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({templateId:e.templateId,designJson:r})});if(!d.ok){const h=await d.json().catch(()=>({message:"Finalization failed"}));throw new Error(h.message||"Finalization failed")}const l=await d.json();return e.onFinalize&&e.onFinalize(l),l}catch(d){const l={code:"FINALIZE_ERROR",message:d instanceof Error?d.message:"Unknown error",details:d};throw e.onError&&e.onError(l),d}},addTextLayer(r){if(typeof i.addTextLayer!="function")throw new Error("Editor not ready: addTextLayer method not available");i.addTextLayer(r)},async addImageLayer(r){if(typeof i.addImageLayer!="function")throw new Error("Editor not ready: addImageLayer method not available");return i.addImageLayer(r)},removeLayer(r){if(typeof i.removeLayer!="function")throw new Error("Editor not ready: removeLayer method not available");i.removeLayer(r)},selectLayer(r){if(typeof i.selectLayer!="function")throw new Error("Editor not ready: selectLayer method not available");i.selectLayer(r)},getSelectedLayerId(){return typeof i.getSelectedLayerId!="function"?null:i.getSelectedLayerId()},setTheme(r){i.setAttribute("theme",r)},setMode(r){i.setAttribute("mode",r)},destroy(){n.forEach(({event:r,handler:o})=>{i.removeEventListener(r,o)}),i.parentNode&&i.parentNode.removeChild(i)},getElement(){return i}};return e.onReady&&a("ready",(()=>{e.onReady?.(s)})),e.onChange&&a("change",(r=>{const o=r.detail.design;e.onChange?.(o)})),e.onLayerSelect&&a("layer:select",(r=>{e.onLayerSelect?.(r.detail.layerId)})),e.onLayerAdd&&a("layer:add",(r=>{e.onLayerAdd?.(r.detail.layerId)})),e.onLayerRemove&&a("layer:remove",(r=>{e.onLayerRemove?.(r.detail.layerId)})),e.onLayerUpdate&&a("layer:update",(r=>{e.onLayerUpdate?.(r.detail.layerId)})),e.onError&&a("error",(r=>{const o=r.detail.error;e.onError?.(o)})),e.initialDesign&&i.addEventListener("ready",()=>{e.initialDesign&&i.setDesign(e.initialDesign)},{once:!0}),e.debug&&(console.log("[Customizer SDK] Initialized with options:",e),console.log("[Customizer SDK] Instance:",s)),s}const O=x.forwardRef((f,e)=>{const{templateId:t,apiUrl:i,theme:n="light",mode:a="edit",debug:s=!1,className:r,style:o,initialDesign:d,onReady:l,onChange:h,onLayerSelect:u,onLayerAdd:g,onLayerRemove:m,onLayerUpdate:b,onError:y,onFinalize:v}=f,C=x.useRef(null),p=x.useRef(null),I=x.useRef({onReady:l,onChange:h,onLayerSelect:u,onLayerAdd:g,onLayerRemove:m,onLayerUpdate:b,onError:y,onFinalize:v});return x.useEffect(()=>{I.current={onReady:l,onChange:h,onLayerSelect:u,onLayerAdd:g,onLayerRemove:m,onLayerUpdate:b,onError:y,onFinalize:v}},[l,h,u,g,m,b,y,v]),x.useEffect(()=>{if(!C.current)return;const E={templateId:t,apiUrl:i,theme:n,mode:a,debug:s,initialDesign:d,onReady:()=>I.current.onReady?.(),onChange:w=>I.current.onChange?.(w),onLayerSelect:w=>I.current.onLayerSelect?.(w),onLayerAdd:w=>I.current.onLayerAdd?.(w),onLayerRemove:w=>I.current.onLayerRemove?.(w),onLayerUpdate:w=>I.current.onLayerUpdate?.(w),onError:w=>I.current.onError?.(w),onFinalize:w=>I.current.onFinalize?.(w)};try{const w=F(C.current,E);p.current=w}catch(w){console.error("[Customizer React] Failed to initialize:",w),I.current.onError?.({code:"INIT_ERROR",message:w instanceof Error?w.message:"Unknown error",details:w})}return()=>{p.current&&(p.current.destroy(),p.current=null)}},[t,i,s,d]),x.useEffect(()=>{p.current&&p.current.setTheme(n)},[n]),x.useEffect(()=>{p.current&&p.current.setMode(a)},[a]),x.useImperativeHandle(e,()=>({getDesign:()=>{if(!p.current)throw new Error("Editor not initialized");return p.current.getDesign()},setDesign:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.setDesign(E)},undo:()=>{if(!p.current)throw new Error("Editor not initialized");p.current.undo()},redo:()=>{if(!p.current)throw new Error("Editor not initialized");p.current.redo()},canUndo:()=>p.current?p.current.canUndo():!1,canRedo:()=>p.current?p.current.canRedo():!1,finalize:async()=>{if(!p.current)throw new Error("Editor not initialized");return p.current.finalize()},addTextLayer:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.addTextLayer(E)},addImageLayer:async E=>{if(!p.current)throw new Error("Editor not initialized");return p.current.addImageLayer(E)},removeLayer:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.removeLayer(E)},selectLayer:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.selectLayer(E)},getSelectedLayerId:()=>p.current?p.current.getSelectedLayerId():null,setTheme:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.setTheme(E)},setMode:E=>{if(!p.current)throw new Error("Editor not initialized");p.current.setMode(E)},destroy:()=>{p.current&&(p.current.destroy(),p.current=null)},getElement:()=>{if(!p.current)throw new Error("Editor not initialized");return p.current.getElement()}}),[]),N.jsx("div",{ref:C,className:r,style:{width:"100%",height:"100%",...o}})});O.displayName="Customizer";function de(f={}){const{autoSave:e=!1,autoSaveKey:t="customizer-design",autoSaveDebounce:i=1e3}=f,n=x.useRef(null),[a,s]=x.useState(null),[r,o]=x.useState(!1),[d,l]=x.useState(!1),[h,u]=x.useState(null),[g,m]=x.useState(!1),[b,y]=x.useState(null),v=x.useRef(void 0);x.useEffect(()=>{if(!(!e||!a))return v.current&&clearTimeout(v.current),v.current=setTimeout(()=>{try{localStorage.setItem(t,JSON.stringify(a))}catch(z){console.error("[useCustomizer] Auto-save failed:",z)}},i),()=>{v.current&&clearTimeout(v.current)}},[a,e,t,i]);const C=x.useCallback(()=>{if(!n.current)return null;try{return n.current.getDesign()}catch(z){return console.error("[useCustomizer] getDesign failed:",z),null}},[]),p=x.useCallback(z=>{if(n.current)try{n.current.setDesign(z),s(z)}catch(S){console.error("[useCustomizer] setDesign failed:",S)}},[]),I=x.useCallback(()=>{if(n.current)try{n.current.undo(),o(n.current.canUndo()),l(n.current.canRedo())}catch(z){console.error("[useCustomizer] undo failed:",z)}},[]),E=x.useCallback(()=>{if(n.current)try{n.current.redo(),o(n.current.canUndo()),l(n.current.canRedo())}catch(z){console.error("[useCustomizer] redo failed:",z)}},[]),w=x.useCallback(async()=>{if(!n.current||g)return null;m(!0);try{const z=await n.current.finalize();return y(z),z}catch(z){return console.error("[useCustomizer] finalize failed:",z),null}finally{m(!1)}},[g]),T=x.useCallback(z=>{if(n.current)try{n.current.addTextLayer(z)}catch(S){console.error("[useCustomizer] addTextLayer failed:",S)}},[]),P=x.useCallback(async z=>{if(n.current)try{await n.current.addImageLayer(z)}catch(S){console.error("[useCustomizer] addImageLayer failed:",S)}},[]),A=x.useCallback(z=>{if(n.current)try{n.current.removeLayer(z)}catch(S){console.error("[useCustomizer] removeLayer failed:",S)}},[]),H=x.useCallback(z=>{if(n.current)try{n.current.selectLayer(z),u(z)}catch(S){console.error("[useCustomizer] selectLayer failed:",S)}},[]);return{customizerRef:n,design:a,canUndo:r,canRedo:d,selectedLayerId:h,isFinalizing:g,finalizeResult:b,getDesign:C,setDesign:p,undo:I,redo:E,finalize:w,addTextLayer:T,addImageLayer:P,removeLayer:A,selectLayer:H}}exports.Customizer=O;exports.initCustomizer=F;exports.useCustomizer=de;
8
8
  //# sourceMappingURL=index.cjs.js.map