@reffy/infinite-canvas 0.0.10 → 0.0.12

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.umd.js DELETED
@@ -1,276 +0,0 @@
1
- (function(w,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("mobx"),require("lit"),require("dexie"),require("uuid"),require("eventemitter3"),require("stats.js")):typeof define=="function"&&define.amd?define(["exports","mobx","lit","dexie","uuid","eventemitter3","stats.js"],m):(w=typeof globalThis<"u"?globalThis:w||self,m(w.ReffyInfiniteCanvas={},w.mobx,w.Lit,w.Dexie,w.uuid,w.EventEmitter3,w.Stats))})(this,(function(w,m,z,k,Ge,Xe,Ne){"use strict";var We=w=>{throw TypeError(w)};var Fe=(w,m,z)=>m.has(w)||We("Cannot "+z);var l=(w,m,z)=>(Fe(w,m,"read from private field"),z?z.call(w):m.get(w)),D=(w,m,z)=>m.has(w)?We("Cannot add the same private member more than once"):m instanceof WeakSet?m.add(w):m.set(w,z),A=(w,m,z,k)=>(Fe(w,m,"write to private field"),k?k.call(w,z):m.set(w,z),z);var G,H,J,ht,v,Y,ct,tt,$,Z,P,dt,Wt,lt;const ut=["TOP","BOTTOM","LEFT","RIGHT"],Ct=["TOPLEFT","TOPRIGHT","BOTTOMLEFT","BOTTOMRIGHT"],te={TOPLEFT:"TOPRIGHT",TOPRIGHT:"TOPLEFT",BOTTOMLEFT:"BOTTOMRIGHT",BOTTOMRIGHT:"BOTTOMLEFT"};function ee(s){return te[s]?te[s]:s}const ie=8,Gt=2,b={identity:function(){return[1,0,0,0,1,0,0,0,1]},translation:function(s,t){return[1,0,0,0,1,0,s,t,1]},rotation:function(s){var t=Math.cos(s),e=Math.sin(s);return[t,-e,0,e,t,0,0,0,1]},scaling:function(s,t){return[s,0,0,0,t,0,0,0,1]},multiply:function(s,t){var e=s[0],i=s[1],r=s[2],n=s[3],a=s[4],o=s[5],h=s[6],c=s[7],u=s[8],f=t[0],p=t[1],g=t[2],C=t[3],x=t[4],M=t[5],S=t[6],L=t[7],R=t[8];return[f*e+p*n+g*h,f*i+p*a+g*c,f*r+p*o+g*u,C*e+x*n+M*h,C*i+x*a+M*c,C*r+x*o+M*u,S*e+L*n+R*h,S*i+L*a+R*c,S*r+L*o+R*u]},inverse(s){const t=[9],e=s[0],i=s[1],r=s[2],n=s[3],a=s[4],o=s[5],h=s[6],c=s[7],u=s[8],f=u*a-o*c,p=-u*n+o*h,g=c*n-a*h,x=1/(e*f+i*p+r*g);return t[0]=f*x,t[1]=(-u*i+r*c)*x,t[2]=(o*i-r*a)*x,t[3]=p*x,t[4]=(u*e-r*h)*x,t[5]=(-o*e+r*n)*x,t[6]=g*x,t[7]=(-c*e+i*h)*x,t[8]=(a*e-i*n)*x,t},projection(s,t){const e=[9];return e[0]=2/s,e[1]=0,e[2]=0,e[3]=0,e[4]=-2/t,e[5]=0,e[6]=-1,e[7]=1,e[8]=1,e},transformPoint(s,t){var e=t[0],i=t[1],r=e*s[2]+i*s[5]+s[8];return[(e*s[0]+i*s[3]+s[6])/r,(e*s[1]+i*s[4]+s[7])/r]}};function Xt(s,t,e){const i=se(s,s.VERTEX_SHADER,t),r=se(s,s.FRAGMENT_SHADER,e),n=s.createProgram();if(s.attachShader(n,i),s.attachShader(n,r),s.linkProgram(n),!s.getProgramParameter(n,s.LINK_STATUS))throw s.deleteProgram(n),s.deleteShader(i),s.deleteShader(r),new Error("Program was not created or the link to shaders was not successful.");return s.detachShader(n,i),s.detachShader(n,r),n}function se(s,t,e){const i=s.createShader(t);if(s.shaderSource(i,e),s.compileShader(i),s.getShaderParameter(i,s.COMPILE_STATUS))return i;throw s.deleteShader(i),new Error("Shader was not created.")}function He(s,t,e,i,r,n){const a=r.getBoundingClientRect(),o=window.devicePixelRatio||1,h=(s-a.left)*o,c=(t-a.top)*o,u=h/e*2-1,f=c/i*-2+1,p=b.projection(e,i),g=b.multiply(p,n),C=b.inverse(g),[x,M]=b.transformPoint(C,[u,f]);return[x,M]}function ft(s,t,e){const{gl:i,canvas:r}=e;return He(s,t,i.canvas.width,i.canvas.height,r,e.worldMatrix)}function U(s,t,e){const i=t??0,r=e??0;return[s[0]*i+s[3]*r+s[6],s[1]*i+s[4]*r+s[7]]}function Ye(s){return Math.hypot(s[0],s[1])}function $e(s){return Math.hypot(s[3],s[4])}function K(s){return[Ye(s),$e(s)]}function re(s){return s/Math.abs(s)}function St(s){return[re(s[0]),re(s[4])]}const bt=(s,t)=>Math.abs(s)<t?0:Math.sign(s),Mt=(s,t,e)=>{const i=s*t;return bt(s,e)!==bt(i,e)};async function je(s){return new Promise((t,e)=>{let i=new FileReader;i.onload=r=>{t(r.target.result)},i.onerror=e,i.readAsDataURL(s)})}const Ve=["image/webp","image/png","image/jpeg","image/jpg","image/svg+xml","image/avif","image/gif","image/apng"];function qe(s){return Ve.includes(s)}async function Nt(s){const e=new TextEncoder().encode(s),i=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(i)).map(n=>n.toString(16).padStart(2,"0")).join("")}function Ze(s){const t=/^data:([^;]+);base64,/.exec(s);return t?t[1]:void 0}async function Ke(s,t){const e=[];if(s.length>0)for(let i=0;i<s.length;i++){const r=s[i];if(qe(r.type))try{const n=await je(r);typeof n=="string"?e.push(await t(n)):console.error("Image not added")}catch{console.error("Failed to copy image.")}}return e}function Qe(s,t){const e=JSON.stringify(t,null,2),i=new Blob([e],{type:"application/json"}),r=URL.createObjectURL(i),n=document.createElement("a");n.href=r,n.download=s,document.body.appendChild(n),n.click(),n.remove(),URL.revokeObjectURL(r)}async function Je(s){const t=await s.text();return JSON.parse(t)}function ne(s,t=1){return new Promise((e,i)=>{const r=new Image;r.onload=()=>{const n=document.createElement("canvas");n.width=r.width,n.height=r.height;const a=n.getContext("2d");a.clearRect(0,0,n.width,n.height),a.drawImage(r,0,0);const o=n.toDataURL("image/png",t);e(o)},r.onerror=i,r.src=s})}const et=[.33,.6,.95,1],Et=[.33,.6,.95,.6],ti=[.33,.6,.95,.4];function Tt(s,t,e="Add Child"){return{label:e,do(){for(const i of t)s.appendChild(i)},undo(){for(const i of t)s.removeChild(i)}}}function ei(s,t,e="Remove Child"){let i=-1;return{label:e,do(){i=s.children.indexOf(t),i>=0&&s.children.splice(i,1)},undo(){if(i<0){s.children.push(t);return}s.children.splice(i,0,t)}}}function ii(s,t,e="Remove Children"){let i=[];return{label:e,do(){const r=new Set(t);i=[],s.children.forEach((n,a)=>{r.has(n)&&i.push({child:n,idx:a})}),i.slice().sort((n,a)=>a.idx-n.idx).forEach(({child:n})=>{s.removeChild(n)})},undo(){i.slice().sort((r,n)=>r.idx-n.idx).forEach(({child:r,idx:n})=>{s.children.includes(r)||(s.children.splice(Math.min(n,s.children.length),0,r),r.addParent(s))}),s.markOrderDirty()}}}const si=["image/","text/plain"],ri=()=>"clipboard"in navigator&&"writeText"in navigator.clipboard;async function ae(s,t){const e={type:"infinite_canvas",elements:s.map(n=>({src:n.src,x:n.x,y:n.y,sx:n.sx,sy:n.sy}))},i=JSON.stringify(e),r=new ClipboardItem({"text/plain":new Blob([i],{type:"text/plain"})});if(ri())try{await navigator.clipboard.write([r]);return}catch(n){console.error(n)}if(!ni(i))throw new Error("Error copying to clipboard.")}function ni(s){s||(s=" ");const t=document.documentElement.getAttribute("dir")==="rtl",e=document.createElement("textarea");e.style.border="0",e.style.padding="0",e.style.margin="0",e.style.position="absolute",e.style[t?"right":"left"]="-9999px";const i=window.pageYOffset||document.documentElement.scrollTop;e.style.top=`${i}px`,e.style.fontSize="12pt",e.setAttribute("readonly",""),e.value=s,document.body.appendChild(e);let r=!1;try{e.select(),e.setSelectionRange(0,e.value.length),r=document.execCommand("copy")}catch(n){console.error(n)}return e.remove(),r}async function oe(s,t,e,i,r=!0){const n=await navigator.clipboard.read(),a=n[0].types,[o,h]=r?[s,t]:ft(s,t,e);for(const c of a){if(!si.find(g=>g.endsWith("/")?c.startsWith(g):c===g))continue;const f=await n[0].getType(c);try{if(c==="text/plain"){const g=JSON.parse(await f.text());if(g.elements.length===0)return;let C=1/0,x=1/0;for(const S of g.elements)S.x<C&&(C=S.x),S.y<x&&(x=S.y);const M=await Promise.all(g.elements.map(S=>e.addImageToCanvas(S.src,o+S.x-C,h+S.y-x,S.sx,S.sy)));i.push(Tt(e,M));return}}catch(g){console.error("Failed to parse clipboard data",g);continue}let p;if(c.startsWith("image/svg"))try{const g=await f.text();p=await ne(`data:image/svg+xml;base64,${btoa(g)}`)}catch(g){console.error("SVG conversion failed",g);continue}else try{p=await new Promise((g,C)=>{const x=new FileReader;x.onloadend=()=>g(x.result),x.onerror=C,x.readAsDataURL(f)})}catch(g){console.error("Image read failed",g);continue}try{const g=await e.addImageToCanvas(p,o,h);i.push(Tt(e,[g]));return}catch(g){console.error("Failed to add image to canvas",g);continue}}}const X={Open:"opencontextmenu",Close:"closecontextmenu"},N={Save:"save",Change:"statechange"},it={start:"startloading",done:"completeloading"},st={Save:"save",SaveCompleted:"savecompleted",SaveFailed:"savefailed"},ai=`
2
- attribute vec2 a_position;
3
-
4
- uniform vec2 u_resolution;
5
- uniform mat3 u_matrix;
6
- uniform float u_z;
7
-
8
- // all shaders have a main function
9
- void main() {
10
- vec2 position = (u_matrix * vec3(a_position, 1)).xy;
11
-
12
- vec2 zeroToOne = position / u_resolution;
13
- vec2 zeroToTwo = zeroToOne * 2.0;
14
- vec2 clipSpace = zeroToTwo - 1.0;
15
- float z = mix(1.0, -1.0, u_z);
16
-
17
- gl_Position = vec4(clipSpace * vec2(1, -1), z, 1);
18
- }
19
- `,oi=`
20
- precision mediump float;
21
- uniform vec4 u_color;
22
-
23
- void main() {
24
- gl_FragColor = u_color;
25
- }
26
- `,hi=`
27
- #extension GL_OES_standard_derivatives : enable
28
- #ifdef GL_FRAGMENT_PRECISION_HIGH
29
- precision highp float;
30
- precision highp int;
31
- #else
32
- precision mediump float;
33
- precision mediump int;
34
- #endif
35
-
36
- uniform mat3 u_ViewProjectionInvMatrix;
37
- uniform float u_ZoomScale;
38
- uniform float u_CheckboardStyle;
39
- uniform float u_z;
40
-
41
- attribute vec2 a_Position;
42
-
43
- varying vec2 v_Position;
44
-
45
- vec2 project_clipspace_to_world(vec2 p) {
46
- return (u_ViewProjectionInvMatrix * vec3(p, 1.0)).xy;
47
- }
48
-
49
- void main() {
50
- v_Position = project_clipspace_to_world(a_Position);
51
- float z = mix(1.0, -1.0, u_z);
52
- gl_Position = vec4(a_Position, z, 1.0);
53
- }
54
- `,ci=`
55
- #extension GL_OES_standard_derivatives : enable
56
- #ifdef GL_FRAGMENT_PRECISION_HIGH
57
- precision highp float;
58
- precision highp int;
59
- #else
60
- precision mediump float;
61
- precision mediump int;
62
- #endif
63
-
64
- uniform mat3 u_ViewProjectionInvMatrix;
65
- uniform float u_ZoomScale;
66
- uniform float u_CheckboardStyle;
67
-
68
- varying vec2 v_Position;
69
-
70
- const vec4 GRID_COLOR = vec4(0.87, 0.87, 0.87, 1.0);
71
- const vec4 PAGE_COLOR = vec4(0.986, 0.986, 0.986, 1.0);
72
- const int CHECKERBOARD_STYLE_NONE = 0;
73
- const int CHECKERBOARD_STYLE_GRID = 1;
74
- const int CHECKERBOARD_STYLE_DOTS = 2;
75
- const float BASE_GRID_PIXEL_SIZE = 100.0;
76
-
77
- vec2 scale_grid_size(float zoom) {
78
- if (zoom < 0.125) return vec2(BASE_GRID_PIXEL_SIZE * 125.0, 0.125);
79
- else if (zoom < 0.25) return vec2(BASE_GRID_PIXEL_SIZE * 25.0, 0.25);
80
- else if (zoom < 0.5) return vec2(BASE_GRID_PIXEL_SIZE * 5.0, 0.5);
81
- return vec2(BASE_GRID_PIXEL_SIZE, 4.0);
82
- }
83
-
84
- vec4 render_grid_checkerboard(vec2 coord) {
85
- float alpha = 0.0;
86
-
87
- vec2 size = scale_grid_size(u_ZoomScale);
88
- float gridSize1 = size.x;
89
- float gridSize2 = gridSize1 / 10.0;
90
- float zoomStep = size.y;
91
- int checkboardStyle = int(floor(u_CheckboardStyle + 0.5));
92
-
93
- if (checkboardStyle == CHECKERBOARD_STYLE_GRID) {
94
- vec2 grid1 = abs(fract(coord / gridSize1 - 0.5) - 0.5) / fwidth(coord) * gridSize1 / 2.0;
95
- vec2 grid2 = abs(fract(coord / gridSize2 - 0.5) - 0.5) / fwidth(coord) * gridSize2;
96
- float v1 = 1.0 - min(min(grid1.x, grid1.y), 1.0);
97
- float v2 = 1.0 - min(min(grid2.x, grid2.y), 1.0);
98
-
99
- if (v1 > 0.0) {
100
- alpha = v1;
101
- } else {
102
- alpha = v2 * clamp(u_ZoomScale / zoomStep, 0.0, 1.0);
103
- }
104
- }
105
-
106
- return mix(PAGE_COLOR, GRID_COLOR, alpha);
107
- }
108
-
109
- void main() {
110
- gl_FragColor = render_grid_checkerboard(v_Position);
111
- }
112
- `,di=`
113
- attribute vec2 a_position;
114
- attribute vec2 a_texCoord;
115
-
116
- uniform vec2 u_resolution;
117
- uniform mat3 u_matrix;
118
- uniform float u_z;
119
-
120
- varying vec2 v_texCoord;
121
-
122
- void main() {
123
- vec2 position = (u_matrix * vec3(a_position, 1)).xy;
124
- vec2 zeroToOne = position / u_resolution;
125
- vec2 zeroToTwo = zeroToOne * 2.0;
126
- vec2 clipSpace = zeroToTwo - 1.0;
127
- float z = mix(1.0, -1.0, u_z);
128
-
129
- gl_Position = vec4(clipSpace * vec2(1, -1), z, 1);
130
-
131
- v_texCoord = a_texCoord;
132
- }
133
- `,li=`
134
- #ifdef GL_FRAGMENT_PRECISION_HIGH
135
- precision highp float;
136
- #else
137
- precision mediump float;
138
- #endif
139
-
140
- uniform sampler2D u_image;
141
-
142
- varying vec2 v_texCoord;
143
-
144
- void main() {
145
- gl_FragColor = texture2D(u_image, v_texCoord);
146
- }
147
- `;var W=(s=>(s[s.ACTIVE=0]="ACTIVE",s[s.PASSIVE=1]="PASSIVE",s))(W||{});class he{constructor(t,e){this.sides=new Map,this.corners=new Map,this.borderSize=0,this.boxSize=0,this.mode=W.ACTIVE,this.target=t,this.setDimension(),this.mode=e??W.ACTIVE,this.borderSize=Gt,this.boxSize=ie/2,this.addSides(),this.mode===W.ACTIVE&&this.addCorners()}setDimension(){const t=this.target.getEdge();this.width=t.maxX-t.minX,this.height=t.maxY-t.minY}getSidesInScreenSpace(t,e){const[i,r]=e?K(e):[1,1],{width:n,height:a,borderSize:o}=this,[h,c]=U(e),[u,f]=St(e);return{TOP:{x:u>0?h:h-n*i,y:c,width:n*i,height:o},BOTTOM:{x:u>0?h:h-n*i,y:c+a*r*f,width:n*i,height:o},LEFT:{x:h,y:f>0?c:c-a*r,width:o,height:a*r},RIGHT:{x:h+n*i*u,y:f>0?c:c-a*r,width:o,height:a*r}}[t]}getCornersInScreenSpace(t,e){const[i,r]=e?K(e):[1,1],{width:n,height:a,boxSize:o}=this,[h,c]=U(e),[u,f]=St(e);return{TOPLEFT:{x:h-o,y:c-o,width:o*2,height:o*2},TOPRIGHT:{x:h-o+n*i*u,y:c-o,width:o*2,height:o*2},BOTTOMLEFT:{x:h-o,y:c-o+a*r*f,width:o*2,height:o*2},BOTTOMRIGHT:{x:h-o+n*i*u,y:c-o+a*r*f,width:o*2,height:o*2}}[t]}setPassive(){this.mode=W.PASSIVE,this.removeCorners()}setActive(){this.mode=W.ACTIVE,this.addCorners()}getPositions(){return this.target.getPositions()}hitTest(t,e,i){if(this.mode===W.PASSIVE)return;const[r,n]=K(this.target.worldMatrix),[a,o]=St(this.target.worldMatrix),[h,c]=U(i,t,e),u=4;for(const R of Ct){const E=this.getCornersInScreenSpace(R,this.target.worldMatrix);if(h>=E.x-u&&h<=E.x+E.width+u&&c>=E.y-u&&c<=E.y+E.height+u)return R}for(const R of ut){const E=this.getSidesInScreenSpace(R,this.target.worldMatrix);if(h>=E.x-u&&h<=E.x+E.width+u&&c>=E.y-u&&c<=E.y+E.height+u)return R}const[f,p]=U(this.target.worldMatrix),g=this.width*r*a,C=this.height*n*o,x=Math.min(f,f+g),M=Math.max(f,f+g),S=Math.min(p,p+C),L=Math.max(p,p+C);if(h>=x&&h<=M&&c>=S&&c<=L)return"CENTER"}update(){this.updateSides(),this.updateCorners()}render(t,e){this.update();for(const[i,r]of this.sides.entries())r.render(t,e);for(const[i,r]of this.corners.entries())r.render(t,e)}destroy(){for(const[t,e]of this.sides.entries())e.destroy();for(const[t,e]of this.corners.entries())e.destroy()}move(t,e){this.target.updateTranslation(t,e)}resize(t,e,i){if(this.target instanceof j){const r=Math.abs(this.width),n=Math.abs(this.height),a=r/n,o=this.target.sx,h=this.target.sy,c=1e-6,u=Math.abs(r*o)<c?c*bt(r*o||1,c):r*o,f=Math.abs(n*h)<c?c*bt(n*h||1,c):n*h,p=t/u,g=e/f,C=c,x=i==="LEFT"||i==="BOTTOMLEFT"||i==="TOPLEFT"?1-p:i==="RIGHT"||i==="BOTTOMRIGHT"||i==="TOPRIGHT"?1+p:i==="TOP"?1-g:1+g;if(Mt(o,x,C)||Mt(h,x,C))return;const M=r*o*x,S=n*h*x;if(Math.abs(M)<C||Math.abs(S)<C)return;if(this.target.updateScale(x,x),i==="LEFT"){const L=n*h,R=n*this.target.sy;this.target.updateTranslation(t,(L-R)/2)}else if(i==="RIGHT"){const L=n*h,R=n*this.target.sy;this.target.updateTranslation(0,(L-R)/2)}else if(i==="TOP"){const L=r*o,R=r*this.target.sx;this.target.updateTranslation((L-R)/2,e)}else if(i==="BOTTOM"){const L=r*o,R=r*this.target.sx;this.target.updateTranslation((L-R)/2,0)}else i==="BOTTOMLEFT"?this.target.updateTranslation(t,0):i==="TOPLEFT"?this.target.updateTranslation(t,t/a*Math.sign(this.target.sx)):i==="TOPRIGHT"&&this.target.updateTranslation(0,-t/a*Math.sign(this.target.sx))}}reset(){this.target.setScale(1,1)}flip(t){const{x:e,y:i,sx:r,sy:n}=this.target;return t==="vertical"?this.target.flipVertical(this.height):this.target.flipHorizontal(this.width),{ref:this.target,start:{x:e,y:i,sx:r,sy:n},end:{x:this.target.x,y:this.target.y,sx:this.target.sx,sy:this.target.sy}}}addCorners(){for(const t of Ct){const e=new j(this.getCornersInScreenSpace(t,this.target.worldMatrix));e.color=this.mode===W.ACTIVE?et:Et,this.corners.set(t,e)}}removeCorners(){this.corners.clear()}updateCorners(){for(const t of Ct){const e=this.getCornersInScreenSpace(t,this.target.worldMatrix),i=this.corners.get(t);i&&(i.setTranslation(e.x,e.y),i.width=e.width,i.height=e.height,i.color=this.mode===W.ACTIVE?et:Et)}}addSides(){for(const t of ut){const e=new j(this.getSidesInScreenSpace(t,this.target.worldMatrix));e.color=this.mode===W.ACTIVE?et:Et,this.sides.set(t,e)}}updateSides(){for(const t of ut){const e=this.getSidesInScreenSpace(t,this.target.worldMatrix),i=this.sides.get(t);i&&(i.setTranslation(e.x,e.y),i.width=e.width,i.height=e.height,i.color=this.mode===W.ACTIVE?et:Et)}}}const Ht=[...Ct,...ut];class ui{constructor(t){this.targets=[],this.handles=new Map,this.borderSize=0,this.boxSize=0,this.scale=[1,1],t&&t.forEach(e=>this.add(e)),this.addHandles()}add(t){this.targets.includes(t)||this.targets.push(t)}remove(t){const e=this.targets.indexOf(t);e!=-1&&this.targets.splice(e,1)}render(t,e){this.update();for(const[i,r]of this.handles.entries())r.render(t,e)}update(){this.borderSize=Gt,this.boxSize=ie/2,this.recalculateBounds(),this.updateHandles()}destroy(){for(const[t,e]of this.handles.entries())e.destroy()}move(t,e){for(const i of this.targets)i.updateTranslation(t,e)}resize(t,e,i,r){const n=this.width,a=this.height,o=i.includes("TOP"),h=i.includes("BOTTOM"),c=i.includes("LEFT"),u=i.includes("RIGHT"),f=c?this.x+n:u?this.x:this.x+n/2,p=o?this.y+a:h?this.y:this.y+a/2,g=1e-6,C=Math.abs(n)<g?n<0?-g:g:n,x=Math.abs(a)<g?a<0?-g:g:a,[M,S]=K(r),L=t*M/C,R=e*S/x,E=i.includes("LEFT")?1-L:i.includes("RIGHT")?1+L:i==="TOP"?1-R:1+R;if(Mt(this.scale[0],E,g)||Mt(this.scale[1],E,g))return;const hs=n*E,cs=a*E;if(!(Math.abs(hs)<g||Math.abs(cs)<g))for(const Ft of this.targets){const ds=Ft.x,ls=Ft.y,[ke,Ue]=U(r,ds,ls),us=f+(ke-f)*E,fs=p+(Ue-p)*E,gs=us-ke,ms=fs-Ue,ps=Math.abs(M)<g?M<0?-g:g:M,ys=Math.abs(S)<g?S<0?-g:g:S,xs=gs/ps,ws=ms/ys;Ft.updateScale(E,E),Ft.updateTranslation(xs,ws)}}flip(t,e,i){K(t);const r=[],[n,a]=i(this.x,this.y);for(const o of this.targets){const h={ref:o,start:{x:o.x,y:o.y,sx:o.sx,sy:o.sy}};if(e==="vertical"){const c=o.height*o.sy;o.setTranslation(o.x,-o.y-c),o.flipVertical(o.height)}else{const c=o.width*o.sx;o.setTranslation(-o.x-c,o.y),o.flipHorizontal(o.width)}h.end={x:o.x,y:o.y,sx:o.sx,sy:o.sy},r.push(h)}return r}align(t){if(this.targets.length<=1)return;const e=[],i=[t==="top"?1:t==="bottom"?-1:0,t==="left"?1:t==="right"?-1:0];let r=i[0]!==0?1/0*i[0]:1/0*i[1];for(const[n,a]of this.targets.entries()){const o=a.getBoundingBox();r=t==="top"||t==="left"?Math.min(t==="top"?o.minY:o.minX,r):Math.max(t==="bottom"?o.maxY:o.maxX,r)}for(const n of this.targets){const a={ref:n,start:{x:n.x,y:n.y,sx:n.sx,sy:n.sy}},o=n.getBoundingBox();n.updateTranslation(t==="top"||t==="bottom"?0:r-(t==="left"?o.minX:o.maxX),t==="top"||t==="bottom"?r-(t==="top"?o.minY:o.maxY):0),a.end={x:n.x,y:n.y,sx:n.sx,sy:n.sy},e.push(a)}return e}normalize(t,e){const i=[],r=this.targets[0],n=t==="height"?e==="first"?r.height*r.sy:this.targets.reduce((a,o)=>a+Math.abs(o.height*o.sy),0)/this.targets.length:t==="width"?e==="first"?r.width*r.sx:this.targets.reduce((a,o)=>a+Math.abs(o.width*o.sx),0)/this.targets.length:t==="scale"?e==="first"?r.sx:this.targets.reduce((a,o)=>a+Math.abs(o.sx),0)/this.targets.length:e==="first"?r.width*r.height*r.sx*r.sy:this.targets.reduce((a,o)=>a+Math.abs(o.sx*o.width*o.height*o.sy),0)/this.targets.length;for(const a of this.targets){const o={ref:a,start:{x:a.x,y:a.y,sx:a.sx,sy:a.sy}},h=[(a.x+a.width*a.sx)/2,(a.y+a.height*a.sy)/2];if(t==="height"){const u=a.height*a.sy,f=Math.abs(n/u);a.updateScale(f,f)}else if(t==="width"){const u=a.width*a.sx,f=Math.abs(n/u);a.updateScale(f,f)}else if(t==="scale"){const u=Math.sign(a.sx),f=Math.sign(a.sy);a.setScale(n*u,n*f)}else if(t==="size"){const u=a.width*a.height*a.sx*a.sy,f=Math.sqrt(Math.abs(n/u));a.updateScale(f,f)}const c=[(a.x+a.width*a.sx)/2,(a.y+a.height*a.sy)/2];a.updateTranslation(h[0]-c[0],h[1]-c[1]),o.end={x:a.x,y:a.y,sx:a.sx,sy:a.sy},i.push(o)}return i}getPositions(){return[this.x,this.y,this.x+this.width,this.y,this.x+this.width,this.y+this.height,this.x,this.y+this.height]}hitTest(t,e,i){const[r,n]=U(i,t,e),a=4;for(const f of Ht){const p=this.getHandleConfig(f);if(r>=p.x-a&&r<=p.x+p.width+a&&n>=p.y-a&&n<=p.y+p.height+a)return f}const o=Math.min(this.x,this.x+this.width),h=Math.max(this.x,this.x+this.width),c=Math.min(this.y,this.y+this.height),u=Math.max(this.y,this.y+this.height);if(r>=o&&r<=h&&n>=c&&n<=u)return"CENTER"}getBounds(){const t=Array.from(this.targets);let e=1/0,i=1/0,r=-1/0,n=-1/0;for(const a of t){const[o,h]=U(a.worldMatrix),[c,u]=U(a.worldMatrix,a.width,a.height);e=Math.min(e,a.sx<0?c:o),i=Math.min(i,a.sy<0?u:h),r=Math.max(r,a.sx<0?o:c),n=Math.max(n,a.sy<0?h:u)}return{minX:e,minY:i,maxX:r,maxY:n}}recalculateBounds(){const{minX:t,minY:e,maxX:i,maxY:r}=this.getBounds();this.x=this.scale[0]<0?i:t,this.y=this.scale[1]<0?r:e,this.width=this.scale[0]*(i-t),this.height=this.scale[1]*(r-e)}addHandles(){for(const t of Ht){const e=this.getHandleConfig(t),i=new j(e);i.color=et,this.handles.set(t,i)}}updateHandles(){for(const t of Ht){const e=this.handles.get(t),i=this.getHandleConfig(t);e&&(e.setTranslation(i.x,i.y),e.width=i.width,e.height=i.height)}}getHandleConfig(t){let{x:e,y:i,width:r,height:n,borderSize:a,boxSize:o}=this;return{TOP:{x:e,y:i,width:r,height:a},BOTTOM:{x:e,y:i+n,width:r,height:a},LEFT:{x:e,y:i,width:a,height:n},RIGHT:{x:e+r,y:i,width:a,height:n},TOPLEFT:{x:e-o,y:i-o,width:o*2,height:o*2},TOPRIGHT:{x:e-o+r,y:i-o,width:o*2,height:o*2},BOTTOMLEFT:{x:e-o,y:i-o+n,width:o*2,height:o*2},BOTTOMRIGHT:{x:e-o+r,y:i-o+n,width:o*2,height:o*2}}[t]}}class rt{constructor(t,e,i,r){this.minX=t,this.minY=e,this.maxX=i,this.maxY=r}getArea(){return(this.maxY-this.minY)*(this.maxX-this.minX)}static isColliding(t,e){return t.minX<=e.maxX&&t.maxX>=e.minX&&t.minY<=e.maxY&&t.maxY>=e.minY}}const ce=["CENTER",...ut];class fi{constructor(t,e,i){this.width=0,this.height=0,this.rects=new Map,this.borderSize=0;const[r,n]=U(i,t,e);this.x=r,this.y=n,this.addRects()}getRectConfig(t){let{x:e,y:i,width:r,height:n,borderSize:a}=this;return{TOP:{x:e,y:i,width:r<0?r:r+a,height:a},BOTTOM:{x:e,y:i+n,width:r<0?r:r+a,height:a},LEFT:{x:n<0&&r<0?e-a:e,y:i,width:a,height:n<0&&r<0?n:n+a},RIGHT:{x:e+r,y:i,width:a,height:n<0?n:n+a},CENTER:{x:e,y:i,width:r,height:n}}[t]}render(t,e){this.update();for(const[i,r]of this.rects.entries())r.render(t,e)}update(){this.borderSize=Gt,this.updateRects()}destroy(){for(const[t,e]of this.rects.entries())e.destroy()}getBoundingBox(t){const[e,i]=t(this.x,this.y),[r,n]=t(this.x+this.width,this.y+this.height),a=Math.min(e,r),o=Math.max(e,r),h=Math.min(i,n),c=Math.max(i,n);return new rt(a,h,o,c)}resize(t,e,i){const[r,n]=K(i);this.width+=t*r,this.height+=e*n}addRects(){for(const t of ce){const e=this.getRectConfig(t),i=new j(e);i.color=et,this.rects.set(t,i)}}updateRects(){for(const t of ce){const e=this.rects.get(t),i=this.getRectConfig(t);e&&(e.setTranslation(i.x,i.y),e.width=i.width,e.height=i.height,t==="CENTER"&&(e.color=ti))}}}class gi{constructor(t={}){const{x:e=0,y:i=0,width:r=0,height:n=0,rotation:a=0,zoom:o=1}=t;this.x=e,this.y=i,this.width=r,this.height=n,this.rotation=a,this.zoom=o,m.makeObservable(this,{x:m.observable,y:m.observable,width:m.observable,height:m.observable,rotation:m.observable,zoom:m.observable,setX:m.action,setY:m.action,setPosition:m.action,incrementPosition:m.action,setWidth:m.action,setHeight:m.action,setSize:m.action,setZoom:m.action,setRotation:m.action,stateVector:m.computed})}setX(t){this.x=t}setY(t){this.y=t}setPosition(t,e){this.x=t,this.y=e}incrementPosition(t,e){this.x+=t,this.y+=e}setWidth(t){this.width=t}setHeight(t){this.height=t}setSize(t,e){this.width=t,this.height=e}setZoom(t){this.zoom=t}setRotation(t){this.rotation=t}get dimension(){return[this.width,this.height]}get position(){return[this.x,this.y]}get stateVector(){return[this.x,this.y,this.width,this.height,this.rotation,this.zoom]}get translationMatrix(){return b.translation(this.x,this.y)}get rotationMatrix(){return b.rotation(this.rotation)}get scaleMatrix(){return b.scaling(this.zoom,this.zoom)}get cameraMatrix(){const t=b.multiply(this.translationMatrix,this.rotationMatrix);return b.multiply(t,this.scaleMatrix)}get canvasMatrix(){return b.inverse(this.cameraMatrix)}}function de(s,t){s.setTranslation(t.x,t.y),s.setScale(t.sx,t.sy)}function le(s,t,e){return{label:"Flip",do(){for(const i of s)de(i.ref,i.end);e&&(e.scale[t==="horizontal"?0:1]*=-1)},undo(){for(const i of s)de(i.ref,i.start);e&&(e.scale[t==="horizontal"?0:1]*=-1)}}}function ue(s,t){s.setTranslation(t.x,t.y),s.setScale(t.sx,t.sy)}function Yt(s,t="Transform"){return{label:t,do(){for(const e of s)ue(e.ref,e.end)},undo(){for(const e of s)ue(e.ref,e.start)}}}class mi{#s;#i=new Set;#e=new Set;#t;#r;#a;get multiBoundingBox(){return this.#t}get boundingBoxes(){return this.#e}#o=!0;#n;#h;get selected(){return Array.from(this.#i)}set selected(t){this.#i.clear(),t.forEach(e=>{this.#i.add(e),this.#e.add(new he(e))})}get marqueeBox(){return this.#r}set marqueeBox(t){this.#r=new fi(t.x,t.y,this.getWorldMatrix())}constructor(t,e,i,r,n,a,o,h){this.#n=i,this.#h=r,this.#s=t,this.#a=e,this.getWorldMatrix=n,this.getCanvasChildren=a,this.getWorldCoords=o,this.getMarqueeCoords=h;const c=Object.getPrototypeOf(this);for(const u of Object.getOwnPropertyNames(c)){const f=this[u];typeof f=="function"&&u!=="constructor"&&(this[u]=f.bind(this))}}add(t){t.forEach(e=>{this.#i.has(e)||(this.#i.add(e),this.#e.add(new he(e)))}),this.#e.size>1&&(this.#e.forEach(e=>e.setPassive()),this.#t||(this.#t=new ui([])),this.selected.forEach(e=>this.#t.add(e)))}remove(t){t.forEach(e=>{if(!this.#i.has(e))return;this.#i.delete(e);const i=Array.from(this.#e.values()).find(r=>r.target===e);i?this.#e.delete(i):console.error("No matching bounding box found"),this.#t&&this.#t.remove(e)}),this.#e.size<=1&&(this.#e.forEach(e=>e.setActive()),this.#t=null)}deleteSelected(t){const e=[...this.#i];this.remove(e);for(const i of e)i.destroy();this.#s.push(ii(t,e))}hitTest(t,e){if(this.#t){const i=this.#t.hitTest(t,e,this.getWorldMatrix());if(i)return i}for(const i of this.#e.values()){const r=i.hitTest(t,e,this.getWorldMatrix());if(r)return r}return null}isMultiBoundingBoxHit(t,e){return this.#t&&this.#t.hitTest(t,e,this.getWorldMatrix())}isBoundingBoxHit(t,e){return this.#e.size===1&&Array.from(this.#e)[0].hitTest(t,e,this.getWorldMatrix())}hitTestAdjustedCorner(t,e){if(this.#t){const i=this.#t.hitTest(t,e,this.getWorldMatrix());if(i)return this.#t.scale[0]*this.#t.scale[1]<0?ee(i):i}for(const i of this.#e.values()){const r=i.hitTest(t,e,this.getWorldMatrix());if(r)return i.target.sx*i.target.sy<0?ee(r):r}}update(){this.#e.forEach(t=>t.update()),this.#t&&this.#t.update()}render(t){if(!this.#r&&!this.#t&&this.#e.size===0)return;this.#n.useProgram(t);const e=this.#n.getUniformLocation(t,"u_z");e&&this.#n.uniform1f(e,1),this.#o&&this.#e.forEach(i=>i.render(this.#n,t)),this.#t&&this.#t.render(this.#n,t),this.#r&&this.#r.render(this.#n,t)}isRectSelected(t){return this.#i.has(t)}clear(){this.#i.clear(),this.#e.clear(),this.#t=null}clearMarquee(){this.#r&&(this.#r=null)}move(t,e){if(this.#t)this.#t.move(t,e);else for(const i of this.#e)i.move(t,e);this.#a.emit(N.Change)}resize(t,e,i){this.multiBoundingBox&&this.multiBoundingBox.resize(t,e,i,this.getWorldMatrix());for(const r of this.boundingBoxes)this.multiBoundingBox?r.update():r.resize(t,e,i);this.#a.emit(N.Change)}flip(t){if(this.multiBoundingBox){const e=this.multiBoundingBox.flip(this.getWorldMatrix(),t,this.getWorldCoords);this.#s.push(le(e,t,this.multiBoundingBox))}else{const e=[];for(const i of this.boundingBoxes)e.push(i.flip(t));this.#s.push(le(e,t))}this.#a.emit(N.Change)}alignSelection(t){if(!this.multiBoundingBox)return;const e=this.multiBoundingBox.align(t);this.#s.push(Yt(e)),this.#a.emit(N.Change)}normalize(t,e="first"){if(!this.multiBoundingBox)return;const i=this.multiBoundingBox.normalize(t,e);this.#s.push(Yt(i)),this.#a.emit(N.Change)}onPointerMove(t,e,i,r,n,a,o,h){if(a())o(t,e);else if(n&&n!=="CENTER")this.resize(i,r,n);else if(this.marqueeBox){this.marqueeBox.resize(i,r,h());const c=this.getCanvasChildren(),u=this.marqueeBox.getBoundingBox(this.getMarqueeCoords);for(const f of c){const p=f.getBoundingBox();rt.isColliding(p,u)&&!this.#i.has(f)?this.add([f]):!rt.isColliding(p,u)&&this.#i.has(f)&&this.remove([f])}}else this.move(i,r)}onSelectionPointerDown(t,e,i,r){e?(t||this.clear(),this.add([e])):(this.clear(),this.marqueeBox?this.clearMarquee():this.marqueeBox={x:i,y:r})}}var gt=(s=>(s[s.SELECT=0]="SELECT",s[s.PAN=1]="PAN",s))(gt||{});const pi={TOP:"ns-resize",BOTTOM:"ns-resize",LEFT:"ew-resize",RIGHT:"ew-resize",TOPLEFT:"nwse-resize",BOTTOMRIGHT:"nwse-resize",TOPRIGHT:"nesw-resize",BOTTOMLEFT:"nesw-resize",CENTER:"grab"};class yi{constructor(t){for(const e in t)e in t&&t[e]!==void 0&&(this[e]=t[e]);this.onPointerDown=this.onPointerDown.bind(this),this.onPointerMoveWhileDown=this.onPointerMoveWhileDown.bind(this),this.onPointerUp=this.onPointerUp.bind(this),this.addOnPointerMove(),this.addOnWheel(t.onWheel),this.addOnPointerDown(),window.addEventListener("copy",async e=>{e.preventDefault(),!this.isContextMenuActive()&&await ae(this.getSelected())}),window.addEventListener("paste",async e=>{e.preventDefault(),!this.isContextMenuActive()&&await t.paste(this.state.lastPointerPos.x,this.state.lastPointerPos.y)})}changeMode(){this.state.toggleMode()}addOnPointerDown(){this.assignEventListener("pointerdown",this.onPointerDown)}addOnPointerMove(){this.assignEventListener("pointermove",t=>{[this.state.lastPointerPos.x,this.state.lastPointerPos.y]=this.getWorldCoords(t.clientX,t.clientY);let e=this.hitTestAdjustedCorner(this.state.lastPointerPos.x,this.state.lastPointerPos.y);this.setCursorStyle(pi[e]||"default")})}addOnWheel(t){this.assignEventListener("wheel",e=>{this.isContextMenuActive()||t(e)},{passive:!1})}onPointerDown(t){t.stopPropagation(),t.preventDefault(),this.eventHub.emit(X.Close);const[e,i]=this.getWorldCoords(t.clientX,t.clientY);this.state.initialize(e,i),this.currentTransform=void 0,this.state.mode===1?this.handlePanPointerDown():this.state.mode===0&&this.handleSelectPointerDown(t,e,i),document.addEventListener("pointermove",this.onPointerMoveWhileDown),document.addEventListener("pointerup",this.onPointerUp)}handlePanPointerDown(){this.setCanvasGlobalClick(!0),this.clearSelection()}handleSelectPointerDown(t,e,i){this.setCanvasGlobalClick(!1);const r=this.checkCollidingChild(e,i),n=this.checkIfSelectionHit(e,i);if(t.button===2)n||this.clearSelection(),r&&!this.isSelection(r)&&this.addSelection([r]);else{n?this.state.resizingDirection=n:this.onSelectionPointerDown(t.shiftKey,r,e,i);const a=this.getSelected();a.length&&(this.currentTransform={targets:a.map(o=>({ref:o,start:{x:o.x,y:o.y,sx:o.sx,sy:o.sy}}))})}}onPointerMoveWhileDown(t){if(t.buttons===2)return;const[e,i]=this.getWorldCoords(t.clientX,t.clientY),r=e-this.state.lastWorldX,n=i-this.state.lastWorldY;this.selectionPointerMove(this.state.startWorldX-e,this.state.startWorldY-i,r,n,this.state.resizingDirection),this.state.updateLastWorldCoord(e,i),this.setCursorStyle("grabbing")}onPointerUp(){if(document.removeEventListener("pointermove",this.onPointerMoveWhileDown),document.removeEventListener("pointerup",this.onPointerUp),this.setCanvasGlobalClick(!0),this.setCursorStyle("default"),this.currentTransform){const t=this.currentTransform.targets.map(e=>({ref:e.ref,start:e.start,end:{x:e.ref.x,y:e.ref.y,sx:e.ref.sx,sy:e.ref.sy}})).filter(e=>e.start.x!==e.end.x||e.start.y!==e.end.y||e.start.sx!==e.end.sx||e.start.sy!==e.end.sy);t.length&&this.history.push(Yt(t))}this.currentTransform=void 0,this.state.resizingDirection=null,this.closeMarquee(),this.eventHub.emit("save")}checkCollidingChild(t,e){const i=this.getChildren();for(let r=i.length-1;r>=0;r--){const n=i[r];if(n instanceof nt&&n.hitTest&&n.hitTest(t,e))return n}return null}}class xi{constructor(t,e,i,r){this.history=t,this.deleteSelected=i,this.save=()=>e.emit(N.Save),this.assignEventListener=r,this.onKeyPressed=this.onKeyPressed.bind(this),this.addOnKeyPressed()}addOnKeyPressed(){document.addEventListener("keydown",this.onKeyPressed)}onKeyPressed(t){if(this.isCtrlZ(t)){t.preventDefault(),this.history.undo();return}if(this.isCtrlY(t)){t.preventDefault(),this.history.redo();return}if(this.isDelete(t)){this.deleteSelected();return}if(this.isSave(t)){t.preventDefault(),this.save();return}}isCtrlZ(t){return t.key.toLowerCase()==="z"&&(t.ctrlKey||t.metaKey)&&!t.shiftKey}isCtrlY(t){return t.key.toLowerCase()==="y"&&(t.ctrlKey||t.metaKey)&&!t.shiftKey}isDelete(t){return t.key==="Delete"}isSave(t){return t.key.toLowerCase()==="s"&&t.ctrlKey}}class wi{#s=!1;get isActive(){return this.#s}constructor(t,e,i,r,n){this.customContextMenu=a=>{a.preventDefault(),a.stopPropagation();const[o,h]=r(a.clientX,a.clientY);e(o,h)?t.emit(X.Open,a.clientX,a.clientY,"multi"):i(o,h)?t.emit(X.Open,a.clientX,a.clientY):t.emit(X.Open,a.clientX,a.clientY,"canvas")},t.on(X.Open,()=>{this.#s=!0}),t.on(X.Close,()=>{this.#s=!1}),n("contextmenu",this.customContextMenu)}}function fe(s,t){s.renderOrder=t.renderOrder}function vi(s,t="Order"){return{label:t,do(){for(const e of s)fe(e.ref,e.end)},undo(){for(const e of s)fe(e.ref,e.start)}}}class Ci{constructor(t=gt.SELECT){this.lastPointerPos={x:0,y:0},this.startWorldX=0,this.startWorldY=0,this.lastWorldX=0,this.lastWorldY=0,this.resizingDirection=null,this.mode=t}get isResizing(){return this.resizingDirection!==null}get dragDXFromStart(){return this.lastWorldX-this.startWorldX}get dragDYFromStart(){return this.lastWorldY-this.startWorldY}setMode(t){this.mode=t}toggleMode(){this.mode=this.mode===gt.PAN?gt.SELECT:gt.PAN}setResizingDirection(t){this.resizingDirection=t}clearResizingDirection(){this.resizingDirection=null}initialize(t,e){this.startWorldX=t,this.startWorldY=e,this.lastWorldX=t,this.lastWorldY=e,this.resizingDirection=null}updateLastWorldCoord(t,e){this.lastWorldX=t,this.lastWorldY=e}}class Si{constructor(){this.translation=[0,0],this.angleRadians=0,this.scale=[1,1],this.localMatrix=b.identity(),this.worldMatrix=b.identity(),this.children=[],this.parent=null,this.renderDirtyFlag=!0,m.makeObservable(this,{translation:m.observable.struct,angleRadians:m.observable,scale:m.observable.struct,localMatrix:m.observable.ref,worldMatrix:m.observable.ref,children:m.observable.shallow,parent:m.observable.ref,renderDirtyFlag:m.observable,x:m.computed,y:m.computed,scaleX:m.computed,scaleY:m.computed,dirty:m.computed,setTranslation:m.action,setScale:m.action,flipVertical:m.action,setAngle:m.action,getChild:m.action,appendChild:m.action,appendChildren:m.action,removeChild:m.action,clearChildren:m.action,setParent:m.action,markDirty:m.action,clearDirty:m.action,updateLocalMatrix:m.action,updateWorldMatrix:m.action,setWorldMatrix:m.action}),this.updateLocalMatrix(),this.updateWorldMatrix()}get x(){return this.translation[0]}get y(){return this.translation[1]}get scaleX(){return this.scale[0]}get scaleY(){return this.scale[1]}get dirty(){return this.renderDirtyFlag}setTranslation(t,e){this.translation[0]=t,this.translation[1]=e,this.markDirty()}updateTranslation(t,e){this.translation[0]+=t,this.translation[1]+=e,this.markDirty()}setScale(t,e){t===this.scale[0]&&e===this.scale[1]||(this.scale[0]=t,this.scale[1]=e,this.markDirty())}updateScale(t,e){this.scale[0]*=t,this.scale[1]*=e,this.markDirty()}flipVertical(t){this.translation[1]+=this.scale[1]*t,this.scale[1]*=-1,this.markDirty()}flipHorizontal(t){this.translation[0]+=this.scale[0]*t,this.scale[0]*=-1,this.markDirty()}setAngle(t){const i=(360-t)*Math.PI/180;i!==this.angleRadians&&(this.angleRadians=i,this.markDirty())}getChild(t){return this.children[t]}appendChild(t){this.children.includes(t)||(this.children.push(t),this.markDirty())}appendChildren(t){for(const e of t){if(this.children.includes(e))return;this.children.push(e)}this.markDirty()}removeChild(t){const e=this.children.indexOf(t);if(e<0)return;const i=this.children.splice(e,1);return t.state.setParent(null),this.markDirty(),i[0]}clearChildren(){if(this.children){for(const t of this.children)t.destroy();this.children=[],this.markDirty()}}setParent(t){this.parent!==t&&(this.parent=t,this.markDirty())}markDirty(){this.renderDirtyFlag||(this.renderDirtyFlag=!0,this.updateLocalMatrix())}clearDirty(){this.renderDirtyFlag&&(this.renderDirtyFlag=!1,this.updateLocalMatrix())}updateLocalMatrix(){const t=b.translation(this.translation[0],this.translation[1]),e=b.rotation(this.angleRadians),i=b.scaling(this.scale[0],this.scale[1]);this.localMatrix=b.multiply(b.multiply(t,e),i)}updateWorldMatrix(t){this.worldMatrix=t?b.multiply(t,this.localMatrix):this.localMatrix.slice();const e=this.worldMatrix;this.children.forEach(i=>{i.updateWorldMatrix(e)})}setWorldMatrix(t){this.worldMatrix=t}}class ge{get x(){return this.state.x}get y(){return this.state.y}get sx(){return this.state.scaleX}get sy(){return this.state.scaleY}get dirty(){return this.state.dirty}get localMatrix(){return this.state.localMatrix}get worldMatrix(){return this.state.worldMatrix}get children(){return this.state.children}get parent(){return this.state.parent}get angleRadians(){return this.state.angleRadians}updateTranslation(t,e){this.state.updateTranslation(t,e)}setTranslation(t,e){this.state.setTranslation(t,e)}updateScale(t,e){this.state.updateScale(t,e)}setScale(t,e){this.state.setScale(t,e)}setAngle(t){return this.state.setAngle(t)}flipVertical(t){this.state.flipVertical(t)}flipHorizontal(t){this.state.flipHorizontal(t)}markDirty(){this.state.markDirty()}clearDirty(){this.state.clearDirty()}updateLocalMatrix(){this.state.updateLocalMatrix()}setWorldMatrix(t){this.state.setWorldMatrix(t)}addChild(t){this.state.appendChild(t)}addParent(t){return this.state.setParent(t)}clearChildren(){return this.state.clearChildren()}constructor(){this.state=new Si,this.setWorldMatrix=this.setWorldMatrix.bind(this),this.updateWorldMatrix=this.updateWorldMatrix.bind(this)}appendChild(t){return t.setParent(this),!t._emitter&&this._emitter&&(t._emitter=this._emitter),t}setParent(t){if(this.parent){const e=this.parent.children.indexOf(this);e>=0&&this.parent.children.splice(e,1)}t&&t.addChild(this),this.addParent(t)}updateWorldMatrix(t){this.updateLocalMatrix(),this.state.updateWorldMatrix(t)}addEventListener(t,e,i){const r=typeof e=="function"?e:e.handleEvent.bind(e);this._emitter.on(t,r)}removeEventListener(t,e,i){}dispatchEvent(t){return this._emitter.emit(t.type,t),!t.defaultPrevented}}class me extends ge{constructor(){super(...arguments),this.initialized=!1}updateVertexData(t){const e=this.getPositions();(!this.vertexArray||this.vertexArray.length!==e.length)&&(this.vertexArray=new Float32Array(e.length)),this.vertexArray.set(e),t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.bufferData(t.ARRAY_BUFFER,this.vertexArray,t.STATIC_DRAW)}setUpVertexData(t,e){this.positionBuffer||(this.positionBuffer=t.createBuffer()),this.attributeLocation=t.getAttribLocation(e,"a_position")}setUpUniforms(t,e){this.resolutionLocation=t.getUniformLocation(e,"u_resolution"),this.matrixLocation=t.getUniformLocation(e,"u_matrix")}updateUniforms(t){t.uniform2f(this.resolutionLocation,t.canvas.width,t.canvas.height),t.uniformMatrix3fv(this.matrixLocation,!1,this.worldMatrix)}}const Ut=class Ut extends me{constructor(t,e,i=1,r=1){super(),this._seq=Ut._seqCounter++,this.culled=!1,this._renderOrder=0,this.color=[1,0,.5,1],this.setTranslation(t,e),this.setScale(i,r)}get renderOrder(){return this._renderOrder}set renderOrder(t){this._renderOrder!==t&&(this._renderOrder=t,this.markDirty())}get seq(){return this._seq}getZ(){const e=this.renderOrder*1e-4+.5;return Math.max(0,Math.min(1,e))}render(t,e){this.updateWorldMatrix(this.parent?this.parent.worldMatrix:void 0),t.useProgram(e),this.dirty&&!this.culled&&(this.initialized||(this.setUpVertexData(t,e),this.setUpUniforms(t,e),this.initialized=!0),this.updateVertexData(t),this.clearDirty()),this.updateUniforms(t);const i=t.getUniformLocation(e,"u_color");i&&t.uniform4fv(i,this.color),this.culled||this.draw(t)}draw(t){t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer);const e=2,i=t.FLOAT;t.vertexAttribPointer(this.attributeLocation,e,i,!1,0,0),t.enableVertexAttribArray(this.attributeLocation),t.drawArrays(t.TRIANGLES,0,this.getVertexCount()),t.bindBuffer(t.ARRAY_BUFFER,null),t.disableVertexAttribArray(this.attributeLocation)}destroy(){this.positionBuffer&&(this.positionBuffer=void 0),this.initialized=!1}};Ut._seqCounter=0;let nt=Ut;class j extends nt{constructor(t){super(t.x,t.y,t.sx,t.sy),this._width=t.width??100,this._height=t.height??100}get width(){return this._width}set width(t){this._width!==t&&(this._width=t,this.markDirty())}get height(){return this._height}set height(t){this._height!==t&&(this._height=t,this.markDirty())}getVertexCount(){return 6}getPositions(){const i=this.width,r=this.height;return[0,0,0,r,i,0,i,0,0,r,i,r]}getBoundingBox(){const t=this.state.translation[0],e=t+this.width*this.state.scaleX,i=this.state.translation[1],r=i+this.height*this.state.scaleY,n=Math.min(t,e),a=Math.max(t,e),o=Math.min(i,r),h=Math.max(i,r);return this.AABB=new rt(n,o,a,h),this.AABB}getEdge(){const t=this.x,e=this.y;return{minX:Math.min(t,t+this.width),maxX:Math.max(t,t+this.width),minY:Math.min(e,e+this.height),maxY:Math.max(e,e+this.height)}}hitTest(t,e){const[i,r]=K(this.worldMatrix),[n,a]=St(this.worldMatrix),[o,h]=U(this.parent.worldMatrix,t,e),[c,u]=U(this.worldMatrix),f=this.width*i*n,p=this.height*r*a,g=Math.min(c,c+f),C=Math.max(c,c+f),x=Math.min(u,u+p),M=Math.max(u,u+p);return o>=g&&o<=C&&h>=x&&h<=M}}class mt extends j{constructor(t){super(t),this.texCoordArray=new Float32Array([0,0,0,1,1,0,1,0,0,1,1,1]),this.useLowRes=!1,this.lowResNeedsRefresh=!0,this._src=t.src,this.loadImage(t.src,t.width,t.height)}get src(){return this._src}set src(t){this._src!==t&&(this._src=t,this.updateImageTexture(t),this.markDirty())}get fileId(){return this._fileId}set fileId(t){this._fileId=t}determineIfLowRes(t,e,i=.1){const r=t.getArea();return this.getBoundingBox().getArea()/r<i/e}async setUseLowRes(t,e){this.useLowRes===t&&!this.lowResNeedsRefresh||(this.useLowRes=t,(t&&e||this.lowResNeedsRefresh)&&await this.ensureLowResUploaded(e),this.markDirty(),this.lowResNeedsRefresh=!1)}loadImage(t,e,i){this.culled||this.updateImageTexture(t,e,i)}updateImageTexture(t,e,i){this._image=new Image,this._image.crossOrigin="anonymous",this._image.onload=async()=>{this.width=e??this._image.naturalWidth,this.height=i??this._image.naturalHeight;try{if(this.bitmap){try{this.bitmap.close()}catch{}this.bitmap=void 0}typeof createImageBitmap=="function"&&(this.bitmap=await createImageBitmap(this._image))}catch(r){console.warn("createImageBitmap failed, falling back to HTMLImageElement",r),this.bitmap=void 0}if(this.gl&&this.program)try{this.texture&&this.gl&&(this.gl.deleteTexture(this.texture),this.texture=void 0),this.initialiseTexture(),this.initialized=!0,this.markDirty()}catch(r){console.error("Failed to initialise texture on image load",r)}this.lowResNeedsRefresh=!0},this._image.onerror=r=>{console.error("Failed to load image:",t,r)},this._image.src=t}async ensureLowResUploaded(t){if(!(this.lowResTexture&&!this.lowResNeedsRefresh)&&!(!this._image||!this._image.complete))try{const i=this._image.naturalWidth,r=this._image.naturalHeight,n=Math.min(1,256/Math.max(1,Math.max(i,r))),a=Math.max(1,Math.round(i*n)),o=Math.max(1,Math.round(r*n));let h;typeof OffscreenCanvas<"u"?h=new OffscreenCanvas(a,o):(h=document.createElement("canvas"),h.width=a,h.height=o);const c=h.getContext("2d");c.clearRect(0,0,a,o);const u=Math.min(a/i,o/r),f=Math.round(i*u),p=Math.round(r*u),g=Math.round((a-f)/2),C=Math.round((o-p)/2);c.drawImage(this._image,0,0,i,r,g,C,f,p),this.lowResBitmap=await createImageBitmap(h),this.setLowResTextureFromBitmap(t,this.lowResBitmap)}catch(e){console.error("Failed to create/upload low-res image",e)}}setLowResTextureFromBitmap(t,e){if(this.lowResTexture){try{t.deleteTexture(this.lowResTexture)}catch{}this.lowResTexture=void 0}this.lowResTexture=t.createTexture(),t.bindTexture(t.TEXTURE_2D,this.lowResTexture),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,e),t.bindTexture(t.TEXTURE_2D,null),this.markDirty()}initialiseTexture(){!this.gl||!this.program||!this._image||!this._image.complete||this._image.naturalWidth===0||(this.setUpVertexData(this.gl,this.program),this.setUpTexData(this.gl,this.program),this.setTexture(this.gl),super.setUpUniforms(this.gl,this.program),this.samplerLocation=this.gl.getUniformLocation(this.program,"u_image"),this.samplerLocation&&this.gl.uniform1i(this.samplerLocation,0))}setUpTexData(t,e){this.texcoordBuffer||(this.texcoordBuffer=t.createBuffer()),this.texcoordLocation=t.getAttribLocation(e,"a_texCoord")}setTexture(t){if(this.texture){try{try{t.deleteTexture(this.texture)}catch{}}catch{}this.texture=void 0}this.texture=t.createTexture(),t.bindTexture(t.TEXTURE_2D,this.texture),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR);const e=this.bitmap??this._image;e&&t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,e),t.bindTexture(t.TEXTURE_2D,null)}updateVertexData(t){super.updateVertexData(t),t.bindBuffer(t.ARRAY_BUFFER,this.texcoordBuffer),t.bufferData(t.ARRAY_BUFFER,this.texCoordArray,t.STATIC_DRAW)}getVertexCount(){return 6}render(t,e){if(this.dirty&&!this.culled){if(this.updateWorldMatrix(this.parent?this.parent.worldMatrix:void 0),!this.initialized)if(this.gl=t,this.program=e,this.initialiseTexture(),this._image.complete&&this._image.naturalWidth>0)this.initialized=!0;else return;this.updateVertexData(t),this.clearDirty()}super.updateUniforms(t),this.culled||this.draw(t)}draw(t){t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer);const e=2,i=t.FLOAT,r=!1,n=0,a=0;t.vertexAttribPointer(this.attributeLocation,e,i,r,n,a),t.enableVertexAttribArray(this.attributeLocation),t.bindBuffer(t.ARRAY_BUFFER,this.texcoordBuffer),t.vertexAttribPointer(this.texcoordLocation,e,i,r,n,a),t.enableVertexAttribArray(this.texcoordLocation),t.activeTexture(t.TEXTURE0);try{const o=this.useLowRes&&this.lowResTexture?this.lowResTexture:this.texture;t.bindTexture(t.TEXTURE_2D,o),t.drawArrays(t.TRIANGLES,0,this.getVertexCount()),t.bindBuffer(t.ARRAY_BUFFER,null),t.disableVertexAttribArray(this.attributeLocation),t.disableVertexAttribArray(this.texcoordLocation)}catch(o){console.error(o)}}destroy(){if(this.texcoordBuffer){try{this.gl.deleteBuffer(this.texcoordBuffer)}catch{}this.texcoordBuffer=void 0}if(this.texture){try{this.gl.deleteTexture(this.texture)}catch{}this.texture=void 0}if(this.lowResTexture){try{this.gl.deleteTexture(this.lowResTexture)}catch{}this.lowResTexture=void 0}if(this.bitmap){try{this.bitmap.close()}catch{}this.bitmap=void 0}if(this.lowResBitmap){try{this.lowResBitmap.close()}catch{}this.lowResBitmap=void 0}this.texcoordLocation=void 0,this.samplerLocation=void 0;try{super.destroy()}catch{}}}var _t=(s=>(s[s.NONE=0]="NONE",s[s.GRID=1]="GRID",s))(_t||{});class pe extends me{constructor(){super(...arguments),this.buffer=null,this.vertexCount=0,this.gridType=1,this.zoom=1}getPositions(){return new Float32Array([-1,-1,3,-1,-1,3])}changeGridType(t){this.gridType=t}render(t,e){if(this.buffer)t.bindBuffer(t.ARRAY_BUFFER,this.buffer);else{if(this.buffer=t.createBuffer(),!this.buffer)throw new Error("Failed to create grid buffer");const c=this.getPositions();this.vertexCount=c.length/2,t.bindBuffer(t.ARRAY_BUFFER,this.buffer),t.bufferData(t.ARRAY_BUFFER,c,t.STATIC_DRAW)}this.initialized||(this.setUpVertexData(t,e),this.setUpUniforms(t,e),this.initialized=!0);const i=t.drawingBufferWidth,r=t.drawingBufferHeight,n=b.inverse(b.projection(i,r)),a=b.inverse(this.worldMatrix),o=b.multiply(a,n);this.viewProjectionInvLocation&&t.uniformMatrix3fv(this.viewProjectionInvLocation,!1,new Float32Array(o)),this.zoomScaleLocation&&t.uniform1f(this.zoomScaleLocation,this.zoom),this.checkboardStyleLocation&&t.uniform1f(this.checkboardStyleLocation,this.gridType);const h=t.getAttribLocation(e,"a_Position");if(h===-1)throw new Error("Attribute a_Position not found in grid program");t.vertexAttribPointer(h,2,t.FLOAT,!1,0,0),t.enableVertexAttribArray(h),t.drawArrays(t.TRIANGLES,0,this.vertexCount),t.bindBuffer(t.ARRAY_BUFFER,null),t.disableVertexAttribArray(h)}destroy(){this.buffer&&(this.buffer=null)}hitTest(t,e){return!1}setUpUniforms(t,e){const i=new Float32Array([1,0,0,0,1,0,0,0,1]);this.viewProjectionInvLocation=t.getUniformLocation(e,"u_ViewProjectionInvMatrix"),this.zoomScaleLocation=t.getUniformLocation(e,"u_ZoomScale"),this.checkboardStyleLocation=t.getUniformLocation(e,"u_CheckboardStyle"),t.uniformMatrix3fv(this.viewProjectionInvLocation,!1,i),t.uniform1f(this.zoomScaleLocation,this.zoom),t.uniform1f(this.checkboardStyleLocation,1)}}const ye=.02,xe=20;class we{constructor(t,e,i,r){this.viewportX=0,this.viewportY=0,this.state=t,this.updateCameraPos=this.updateCameraPos.bind(this),this.updateZoom=this.updateZoom.bind(this),this.onWheel=this.onWheel.bind(this),this.worldToCamera=this.worldToCamera.bind(this),this.getWorldCoords=r,this.setWorldMatrix=e,this.updateWorldMatrix=i,this.updateReaction=m.reaction(()=>this.state.stateVector,()=>this.updateViewMatrix()),this.updateViewMatrix()}updateViewMatrix(){this.setWorldMatrix(this.state.canvasMatrix),this.updateWorldMatrix()}setViewPortDimension(t,e){this.state.width!==t&&this.state.setWidth(t),this.state.height!==e&&this.state.setHeight(e)}getBoundingBox(){const[t,e]=this.getWorldCoords(this.viewportX,this.viewportY),[i,r]=this.getWorldCoords(this.state.width+this.viewportX,this.state.height+this.viewportY);return new rt(t,e,i,r)}onWheel(t){t.preventDefault();const i=Math.exp(-t.deltaY*.003);this.updateZoom(t.clientX,t.clientY,i)}updateCameraPos(t,e){this.state.incrementPosition(t,e)}updateZoom(t,e,i){const[r,n]=this.getWorldCoords(t,e);this.state.setZoom(Math.min(xe,Math.max(ye,this.state.zoom*i)));const[a,o]=this.getWorldCoords(t,e);this.state.incrementPosition(r-a,n-o)}worldToCamera(t,e){const i=this.state.cameraMatrix,r=i[0]*t+i[1]*e+i[2],n=i[3]*t+i[4]*e+i[5];return[r,n]}dispose(){this.updateReaction&&(this.updateReaction(),this.updateReaction=void 0)}}const ve="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjYjNiM2IzIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xLjUgNmEyLjI1IDIuMjUgMCAwIDEgMi4yNS0yLjI1aDE2LjVBMi4yNSAyLjI1IDAgMCAxIDIyLjUgNnYxMmEyLjI1IDIuMjUgMCAwIDEtMi4yNSAyLjI1SDMuNzVBMi4yNSAyLjI1IDAgMCAxIDEuNSAxOHpNMyAxNi4wNlYxOGMwIC40MTQuMzM2Ljc1Ljc1Ljc1aDE2LjVBLjc1Ljc1IDAgMCAwIDIxIDE4di0xLjk0bC0yLjY5LTIuNjg5YTEuNSAxLjUgMCAwIDAtMi4xMiAwbC0uODguODc5bC45Ny45N2EuNzUuNzUgMCAxIDEtMS4wNiAxLjA2bC01LjE2LTUuMTU5YTEuNSAxLjUgMCAwIDAtMi4xMiAwem0xMC4xMjUtNy44MWExLjEyNSAxLjEyNSAwIDEgMSAyLjI1IDBhMS4xMjUgMS4xMjUgMCAwIDEtMi4yNSAwIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=",at=240;function Ce(s){return{x:s.x??0,y:s.y??0,sx:s.sx??1,sy:s.sy??1}}function $t(s){return s.children.map(Se)}function Se(s){return s instanceof mt?{type:"Img",id:s.seq,renderOrder:s.renderOrder,transform:Ce(s),width:s.width,height:s.height,fileId:s.fileId,children:s.children?.length?$t(s):void 0}:s instanceof j?{type:"Rect",id:s.seq,renderOrder:s.renderOrder,transform:Ce(s),width:s.width,height:s.height,color:s.color,children:s.children?.length?$t(s):void 0}:s instanceof pe?{type:"Grid",style:s.gridType}:{type:"Renderable",children:s.children?.length?$t(s):void 0}}function jt(s,t){const{gl:e}=s;return{version:1,canvas:{width:e.canvas.width,height:e.canvas.height,dpr:window.devicePixelRatio||1},camera:{x:s.camera.state.x,y:s.camera.state.y,zoom:s.camera.state.zoom},root:Se(s),files:t}}async function Vt(s,t,e,i){t.children.length=0,s.camera&&(t.camera.state.setZoom(s.camera.zoom),t.camera.state.setX(s.camera.x),t.camera.state.setY(s.camera.y));async function r(n,a){let o;switch(n.type){case"Rect":o=new j({x:n.transform.x,y:n.transform.y,width:n.width,height:n.height}),o.setScale(n.transform.sx,n.transform.sy),t.appendChild(o);break;case"Img":let h;try{h=s.files&&Array.isArray(s.files)?s.files.find(g=>g.id===n.fileId)?.dataURL??ve:ve,i&&i(h);const c=n.width,u=n.height,f=await Mi(h,c*n.transform.sx,u*n.transform.sy);o=new mt({x:n.transform.x,y:n.transform.y,src:f,width:c,height:u}),e(n.fileId).then(p=>{o.src=p.dataURL}).catch(p=>console.error("Image not loaded",p)),o.fileId=n.fileId??await Nt(h),o.setScale(n.transform.sx,n.transform.sy),t.appendChild(o),typeof n.renderOrder=="number"&&(o.renderOrder=n.renderOrder)}catch{console.error(`Failed to match image to restore with source: ${h}`)}finally{break}case"Grid":a instanceof pt&&(a.grid.gridType=n.style);break}if(n.children)for(const h of n.children)await r(h,o)}return await r(s.root,t),t}async function bi(s){const t=new Image;return t.crossOrigin="anonymous",new Promise((e,i)=>{t.onload=()=>e(t),t.onerror=r=>i(r),t.src=s})}async function Mi(s,t,e,i="#d6d6d6ff"){let r=null,n;s instanceof Blob?(r=URL.createObjectURL(s),n=r):n=s;try{let a=null;try{a=await bi(n)}catch{}const o=t&&t>0?t:a?.naturalWidth??at,h=e&&e>0?e:a?.naturalHeight??at,c=document.createElement("canvas");c.width=o,c.height=h;const u=c.getContext("2d");if(u.fillStyle=i,u.fillRect(0,0,o,h),a){const f=Math.min(o/a.naturalWidth,h/a.naturalHeight),p=a.naturalHeight*f,g=a.naturalWidth*f;let C=at,x=at;(at>p||at>g)&&(C=g,x=p);const M=Math.round((o-C)/2),S=Math.round((h-x)/2);u.drawImage(a,0,0,a.naturalWidth,a.naturalHeight,M,S,C,x)}return c.toDataURL("image/png")}finally{r&&URL.revokeObjectURL(r)}}const I=class I extends ge{constructor(e,i,r,n,a,o){super();D(this,G);D(this,H);D(this,J);D(this,ht);D(this,v);D(this,Y);D(this,ct);D(this,tt);D(this,$);D(this,Z);D(this,P);D(this,dt);D(this,Wt);D(this,lt);A(this,Z,!0),this.orderDirty=!0,this.renderList=[],A(this,G,e),A(this,H,r),A(this,J,i),A(this,$,new pe),A(this,v,e.getContext("webgl",{alpha:!0,premultipliedAlpha:!1})),l(this,v).enable(l(this,v).BLEND),l(this,v).blendFunc(l(this,v).SRC_ALPHA,l(this,v).ONE_MINUS_SRC_ALPHA),l(this,v).getExtension("OES_standard_derivatives"),l(this,v).enable(l(this,v).DEPTH_TEST),l(this,v).depthFunc(l(this,v).LEQUAL),A(this,Y,Xt(l(this,v),ai,oi)),A(this,ct,Xt(l(this,v),di,li)),A(this,tt,Xt(l(this,v),hi,ci)),this.writeToStorage=n,this.saveImgFileToStorage=a,this.getContainerDimension=o,this.engine=this.engine.bind(this),this.getBoundingClientRect=this.getBoundingClientRect.bind(this),this.appendChild=this.appendChild.bind(this),this.addImageToCanvas=this.addImageToCanvas.bind(this),this.setShapeZOrder=this.setShapeZOrder.bind(this),this.toggleGrid=this.toggleGrid.bind(this),this.changeMode=this.changeMode.bind(this),this.getSelected=this.getSelected.bind(this),this.updateZoomByFixedAmount=this.updateZoomByFixedAmount.bind(this),this.assignEventListener=this.assignEventListener.bind(this),this.getWorldsCoordsFromCanvas=(p,g)=>ft(p,g,this);const h=(p,g)=>ft(p+this.camera.viewportX,g+this.camera.viewportY,this);this.exportState=this.exportState.bind(this),this.importState=this.importState.bind(this),this.clearChildren=this.clearChildren.bind(this),A(this,P,new mi(i,r,this.gl,l(this,Y),()=>this.worldMatrix,()=>this.children,this.getWorldsCoordsFromCanvas,h));const c=new gi({});A(this,ht,new we(c,this.setWorldMatrix,this.updateWorldMatrix,this.getWorldsCoordsFromCanvas)),A(this,Wt,new xi(i,r,()=>this.selectionManager.deleteSelected(this),this.assignEventListener)),A(this,lt,new wi(r,this.selectionManager.isMultiBoundingBoxHit,this.selectionManager.isBoundingBoxHit,this.getWorldsCoordsFromCanvas,this.assignEventListener));const u=new Ci,f={history:i,eventHub:r,state:u,isContextMenuActive:()=>l(this,lt).isActive,getSelected:()=>l(this,P).selected,getChildren:()=>this.children,getWorldMatrix:()=>this.worldMatrix,getCanvasGlobalClick:()=>this.isGlobalClick,setCanvasGlobalClick:p=>this.isGlobalClick=p,getWorldCoords:this.getWorldsCoordsFromCanvas,updateCameraPos:this.camera.updateCameraPos,onWheel:this.camera.onWheel,setCursorStyle:p=>e.style.cursor=p,paste:(p,g)=>oe(p,g,this,i),assignEventListener:this.assignEventListener,closeMarquee:l(this,P).clearMarquee,selectionPointerMove:(p,g,C,x,M)=>l(this,P).onPointerMove(p,g,C,x,M,()=>this.isGlobalClick,this.camera.updateCameraPos,()=>this.worldMatrix),onSelectionPointerDown:this.selectionManager.onSelectionPointerDown,checkIfSelectionHit:this.selectionManager.hitTest,addSelection:this.selectionManager.add,clearSelection:this.selectionManager.clear,isSelection:this.selectionManager.isRectSelected,hitTestAdjustedCorner:this.selectionManager.hitTestAdjustedCorner};A(this,dt,new yi(f)),l(this,H).on("save",this.writeToStorage)}markOrderDirty(){this.orderDirty=!0}get gl(){return l(this,v)}get grid(){return l(this,$)}get history(){return l(this,J)}get eventHub(){return l(this,H)}get pointerEventManager(){return l(this,dt)}get selectionManager(){return l(this,P)}get contextMenuManager(){return l(this,lt)}get canvas(){return l(this,G)}get camera(){return l(this,ht)}get isGlobalClick(){return l(this,Z)}set isGlobalClick(e){A(this,Z,e)}get basicShapeProgram(){return l(this,Y)}engine(){return this}get totalNumberOfChildren(){return this.children.length}get numberOfChildrenRendered(){return this.renderList.length}appendChild(e){if(super.appendChild(e),e instanceof nt){const i=this.children.map(n=>n.renderOrder),r=i.length?Math.max(...i):0;e.renderOrder=r+1}return this.markOrderDirty(),e}removeChild(e){this.state.removeChild(e),l(this,P)&&l(this,P).remove([e]),e.destroy(),this.markOrderDirty()}getChild(e){return this.state.getChild(e)}updateWorldMatrix(){l(this,$).updateWorldMatrix(this.worldMatrix),this.children.forEach(e=>{e.updateWorldMatrix(this.worldMatrix)}),l(this,P).update()}render(){l(this,v).clearColor(0,0,0,0),l(this,v).clear(l(this,v).COLOR_BUFFER_BIT|l(this,v).DEPTH_BUFFER_BIT),l(this,v).viewport(0,0,l(this,v).canvas.width,l(this,v).canvas.height);const e=this.canvas.parentElement.getBoundingClientRect();this.camera.setViewPortDimension(e.width,e.height),l(this,v).useProgram(l(this,tt));const i=l(this,v).getUniformLocation(l(this,tt),"u_z");l(this,v).uniform1f(i,0),l(this,$).render(l(this,v),l(this,tt));const r=this.camera.getBoundingBox();this.renderList=[];for(const n of this.children)rt.isColliding(r,n.getBoundingBox())?(this.renderList.push(n),n.culled=!1):n.culled=!0;this.renderList.forEach(n=>{if(n instanceof mt){const a=n.determineIfLowRes(r,this.camera.state.zoom);n.setUseLowRes(a,this.gl)}});for(const n of this.renderList){let a;n instanceof mt?a=l(this,ct):n instanceof nt&&(a=l(this,Y)),l(this,v).useProgram(a);const o=l(this,v).getUniformLocation(a,"u_z");l(this,v).uniform1f(o,n.getZ()),n.render(l(this,v),a)}l(this,P).render(l(this,Y))}destroy(){l(this,v).deleteProgram(l(this,Y)),l(this,v).deleteProgram(l(this,ct)),this.children.forEach(e=>{"destroy"in e&&e.destroy()}),this.clearChildren()}getDOM(){return l(this,G)}assignEventListener(e,i,r){l(this,G).addEventListener(e,i,r)}hitTest(e,i){return A(this,Z,!0),l(this,Z)}async addImageToCanvas(e,i,r,n=1,a=1,o=!1){const h=new mt({x:i,y:r,src:e,sx:n,sy:a});if(this.saveImgFileToStorage(e).then(c=>h.fileId=c),o){const c=new Image;c.src=e.startsWith("data:image/png")?e:await ne(e),c.onload=()=>{const u=c.naturalWidth||c.width||0,f=c.naturalHeight||c.height||0;(u||f)&&h.updateTranslation(-u/2,-f/2),h.src=c.src,this.appendChild(h)}}return l(this,H).emit("save"),l(this,H).emit(N.Change),h}exportState(){return jt(this)}async importState(e,i){return await Vt(e,this,i)}clearChildren(){this.selectionManager.clear(),this.state.clearChildren(),l(this,J).clear()}toggleGrid(){l(this,$).changeGridType(l(this,$).gridType===_t.GRID?_t.NONE:_t.GRID)}getSelected(){return l(this,P).selected}setShapeZOrder(e=!0){if(l(this,P).multiBoundingBox||l(this,P).boundingBoxes.size!=1)return;const i=Array.from(l(this,P).boundingBoxes)[0].target,r={ref:i,start:{renderOrder:i.renderOrder}},n=this.children.map(h=>h.renderOrder);if(n.length===0)throw new Error("Order unexpected missing.");const a=Math.max(...n),o=Math.min(...n);i.renderOrder=e?a+1:o-1,r.end={renderOrder:i.renderOrder},this.markOrderDirty(),l(this,J).push(vi([r])),l(this,H).emit(N.Change)}changeMode(){l(this,dt).changeMode(),l(this,P).clear()}updateZoomByFixedAmount(e=1){l(this,ht).updateZoom(l(this,G).width/2,l(this,G).height/2,Math.exp(.5*.3*e))}getBoundingClientRect(){return l(this,G).getBoundingClientRect()}wrapWebGLContext(e){const i=e.createTexture.bind(e);e.createTexture=()=>(I.webglStats.texturesCreated++,console.log(`Textures created: ${I.webglStats.texturesCreated}`),i());const r=e.deleteTexture.bind(e);e.deleteTexture=o=>(o&&(I.webglStats.texturesDeleted++,console.log(`Textures deleted: ${I.webglStats.texturesDeleted}`)),r(o));const n=e.createShader.bind(e);e.createShader=o=>(I.webglStats.shadersCreated++,console.log(`Shaders created: ${I.webglStats.shadersCreated}`),n(o));const a=e.deleteShader.bind(e);return e.deleteShader=o=>(o&&(I.webglStats.shadersDeleted++,console.log(`Shaders deleted: ${I.webglStats.shadersDeleted}`)),a(o)),e}static getWebGLStats(){return{...I.webglStats,buffersLeaked:I.webglStats.buffersCreated-I.webglStats.buffersDeleted,programsLeaked:I.webglStats.programsCreated-I.webglStats.programsDeleted,texturesLeaked:I.webglStats.texturesCreated-I.webglStats.texturesDeleted,shadersLeaked:I.webglStats.shadersCreated-I.webglStats.shadersDeleted}}};G=new WeakMap,H=new WeakMap,J=new WeakMap,ht=new WeakMap,v=new WeakMap,Y=new WeakMap,ct=new WeakMap,tt=new WeakMap,$=new WeakMap,Z=new WeakMap,P=new WeakMap,dt=new WeakMap,Wt=new WeakMap,lt=new WeakMap,I.webglStats={buffersCreated:0,buffersDeleted:0,programsCreated:0,programsDeleted:0,texturesCreated:0,texturesDeleted:0,shadersCreated:0,shadersDeleted:0};let pt=I;const be=25;class Ei{constructor(){this._undoStack=[],this._redoStack=[],this._openGroup=null}get undoStack(){return this._undoStack}begin(t){if(this._openGroup)throw new Error("History group already open");this._openGroup=[],this._openLabel=t}push(t){if(this._openGroup)this._openGroup.push(t);else{for(;this._undoStack.length>=be;)this._undoStack.shift();this._undoStack.push([t]),t.do(),this._redoStack.length=0}}commit(){if(!this._openGroup)return;const t=this._openGroup;this._openGroup=null;for(const e of t)e.do();for(;this._undoStack.length>=be;)this._undoStack.shift();this._undoStack.push(t),this._redoStack.length=0,this._openLabel=void 0}cancel(){this._openGroup=null,this._openLabel=void 0}canUndo(){return this._undoStack.length>0}canRedo(){return this._redoStack.length>0}undo(){const t=this._undoStack.pop();if(t){for(let e=t.length-1;e>=0;e--)t[e].undo();this._redoStack.push(t)}}redo(){const t=this._redoStack.pop();if(t){for(const e of t)e.do();this._undoStack.push(t)}}clear(){this._undoStack.length=0,this._redoStack.length=0,this._openGroup=null,this._openLabel=void 0}}const Ti=s=>(t,e)=>{e!==void 0?e.addInitializer((()=>{customElements.define(s,t)})):customElements.define(s,t)};const It=globalThis,qt=It.ShadowRoot&&(It.ShadyCSS===void 0||It.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Me=Symbol(),Ee=new WeakMap;let _i=class{constructor(t,e,i){if(this._$cssResult$=!0,i!==Me)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const e=this.t;if(qt&&t===void 0){const i=e!==void 0&&e.length===1;i&&(t=Ee.get(e)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),i&&Ee.set(e,t))}return t}toString(){return this.cssText}};const Ii=s=>new _i(typeof s=="string"?s:s+"",void 0,Me),Ri=(s,t)=>{if(qt)s.adoptedStyleSheets=t.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet));else for(const e of t){const i=document.createElement("style"),r=It.litNonce;r!==void 0&&i.setAttribute("nonce",r),i.textContent=e.cssText,s.appendChild(i)}},Te=qt?s=>s:s=>s instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return Ii(e)})(s):s;const{is:Pi,defineProperty:Ai,getOwnPropertyDescriptor:Oi,getOwnPropertyNames:Li,getOwnPropertySymbols:Di,getPrototypeOf:Bi}=Object,Rt=globalThis,_e=Rt.trustedTypes,zi=_e?_e.emptyScript:"",ki=Rt.reactiveElementPolyfillSupport,yt=(s,t)=>s,Zt={toAttribute(s,t){switch(t){case Boolean:s=s?zi:null;break;case Object:case Array:s=s==null?s:JSON.stringify(s)}return s},fromAttribute(s,t){let e=s;switch(t){case Boolean:e=s!==null;break;case Number:e=s===null?null:Number(s);break;case Object:case Array:try{e=JSON.parse(s)}catch{e=null}}return e}},Ie=(s,t)=>!Pi(s,t),Re={attribute:!0,type:String,converter:Zt,reflect:!1,useDefault:!1,hasChanged:Ie};Symbol.metadata??=Symbol("metadata"),Rt.litPropertyMetadata??=new WeakMap;class xt extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=Re){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),r=this.getPropertyDescriptor(t,i,e);r!==void 0&&Ai(this.prototype,t,r)}}static getPropertyDescriptor(t,e,i){const{get:r,set:n}=Oi(this.prototype,t)??{get(){return this[e]},set(a){this[e]=a}};return{get:r,set(a){const o=r?.call(this);n?.call(this,a),this.requestUpdate(t,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??Re}static _$Ei(){if(this.hasOwnProperty(yt("elementProperties")))return;const t=Bi(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(yt("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(yt("properties"))){const e=this.properties,i=[...Li(e),...Di(e)];for(const r of i)this.createProperty(r,e[r])}const t=this[Symbol.metadata];if(t!==null){const e=litPropertyMetadata.get(t);if(e!==void 0)for(const[i,r]of e)this.elementProperties.set(i,r)}this._$Eh=new Map;for(const[e,i]of this.elementProperties){const r=this._$Eu(e,i);r!==void 0&&this._$Eh.set(r,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const r of i)e.unshift(Te(r))}else t!==void 0&&e.push(Te(t));return e}static _$Eu(t,e){const i=e.attribute;return i===!1?void 0:typeof i=="string"?i:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach((t=>t(this)))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Ri(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach((t=>t.hostConnected?.()))}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach((t=>t.hostDisconnected?.()))}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),r=this.constructor._$Eu(t,i);if(r!==void 0&&i.reflect===!0){const n=(i.converter?.toAttribute!==void 0?i.converter:Zt).toAttribute(e,i.type);this._$Em=t,n==null?this.removeAttribute(r):this.setAttribute(r,n),this._$Em=null}}_$AK(t,e){const i=this.constructor,r=i._$Eh.get(t);if(r!==void 0&&this._$Em!==r){const n=i.getPropertyOptions(r),a=typeof n.converter=="function"?{fromAttribute:n.converter}:n.converter?.fromAttribute!==void 0?n.converter:Zt;this._$Em=r;const o=a.fromAttribute(e,n.type);this[r]=o??this._$Ej?.get(r)??o,this._$Em=null}}requestUpdate(t,e,i){if(t!==void 0){const r=this.constructor,n=this[t];if(i??=r.getPropertyOptions(t),!((i.hasChanged??Ie)(n,e)||i.useDefault&&i.reflect&&n===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,i))))return;this.C(t,e,i)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:r,wrapped:n},a){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,a??e??this[t]),n!==!0||a!==void 0)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),r===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[r,n]of this._$Ep)this[r]=n;this._$Ep=void 0}const i=this.constructor.elementProperties;if(i.size>0)for(const[r,n]of i){const{wrapped:a}=n,o=this[r];a!==!0||this._$AL.has(r)||o===void 0||this.C(r,void 0,n,o)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach((i=>i.hostUpdate?.())),this.update(e)):this._$EM()}catch(i){throw t=!1,this._$EM(),i}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach((e=>e.hostUpdated?.())),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach((e=>this._$ET(e,this[e]))),this._$EM()}updated(t){}firstUpdated(t){}}xt.elementStyles=[],xt.shadowRootOptions={mode:"open"},xt[yt("elementProperties")]=new Map,xt[yt("finalized")]=new Map,ki?.({ReactiveElement:xt}),(Rt.reactiveElementVersions??=[]).push("2.1.1");class Pe{constructor(t,e){this.options=[],this.rootNode=e,this._el=document.createElement("div"),this._el.classList.add("context-menu"),t.options.forEach((i,r)=>{this.createOptionGroup(i),r!==t.options.length-1&&this.addDivider()}),this._el.addEventListener("contextmenu",i=>{i.preventDefault()})}get el(){return this._el}attachToParent(t){t.appendChild(this.el)}createOptionGroup(t){const e=new Ui(t,this.rootNode);this.options.push(e),this.el.appendChild(e.el)}addDivider(){const t=document.createElement("hr");t.classList.add("context-menu-divider"),this.el.appendChild(t)}}class Ui{constructor(t,e){this.childOptions=[],this.rootNode=e,this._el=document.createElement("div"),this.createOptionElement=this.createOptionElement.bind(this),t.childOptions.forEach(i=>this.createOptionElement(i))}get el(){return this._el}attachToParent(t){t.appendChild(this.el)}createOptionElement(t){t.parent=this;const e=new Wi(t,this.rootNode);this.childOptions.push(e)}}class Wi{get el(){return this._el}constructor(t,e){this.displayText=t.text,this.rootNode=e,this.parent=t.parent,this._el=document.createElement("button"),this._el.textContent=t.text,this._el.classList.add("context-menu-option"),this.parent.el.appendChild(this._el),"onClick"in t&&this._el.addEventListener("click",t.onClick),this._el.addEventListener("pointerenter",i=>Fi(i,t,this._el,this.rootNode)),this._el.addEventListener("contextmenu",i=>{i.preventDefault()})}}function Fi(s,t,e,i){if(!i)return;const r=i.querySelector(".sub-context-menu");if(r&&r.remove(),t.subMenu){const n=new Pe(t.subMenu,this);i.appendChild(n.el),n.el.id=`${t.text}-context-menu`,n.el.classList.add("sub-context-menu");const a=i.getBoundingClientRect(),o=e.getBoundingClientRect(),h=n.el.getBoundingClientRect(),c=a.right-a.left,u=a.bottom-a.top,f=o.right+h.width;o.top+h.height>u?n._el.style.top=`${o.bottom-h.height}px`:n._el.style.top=`${o.top}px`,f>c?n._el.style.left=`${o.left-h.width}px`:n._el.style.left=`${o.right}px`}}const Pt=5;function At(s){const t=this;return function(...e){const i=s.apply(t,e);return t.clearContextMenu(),i}}function Gi(s,t,e="single"){const i=new Pe(e==="single"?this.singleImageMenuOptions:e==="multi"?this.multiImageMenuOptions:this.canvasImageMenuOptions,this.rootDiv);if(!this.rootDiv){console.error("Can't add to parent div");return}i.attachToParent(this.rootDiv);const r=this.getBoundingClientRect(),n=s-r.left,a=t-r.top,o=r.right-r.left,h=r.bottom-r.top,c=i.el.getBoundingClientRect(),u=[n+c.width>o?1:0,a+c.height>h?1:0],f=c.height*u[1],p=c.width*u[0];if(f>h){const g=h-2*Pt;i._el.style.height=`${g}px`,i._el.style.top=`${Pt}px`}else i._el.style.top=`${a-f}px`;p>o?(i._el.style.width=`${o-2*Pt}px`,i._el.style.left=`${Pt}px`):i._el.style.left=`${n-p}px`}function Xi(){const s=this.renderRoot.querySelector(".context-menu");s&&(s.remove(),this.eventHub.emit(X.Close))}function Ni(){return this.renderRoot.querySelector(".context-menu")!==null}function Hi(){const s=At.bind(this);return{options:[{childOptions:[{text:"Cut",onClick:async()=>{await this.copyImage.bind(this)(),s(this.deleteSelectedImages.bind(this))()}},{text:"Copy",onClick:s(this.copyImage.bind(this))},{text:"Paste",onClick:t=>s(this.pasteImage.bind(this))(t)},{text:"Delete",onClick:s(this.deleteSelectedImages.bind(this))}]},{childOptions:[{text:"Flip Horizontal",onClick:s(this.flipHorizontal.bind(this))},{text:"Flip Vertical",onClick:s(this.flipVertical.bind(this))}]}]}}function Yi(s){const t=At.bind(this);return{options:[...s??[],{childOptions:[{text:"Send to Front",onClick:()=>t(this.sendShapeToNewZOrder.bind(this))(!0)},{text:"Send to Back",onClick:()=>t(this.sendShapeToNewZOrder.bind(this))(!1)}]}]}}function $i(s){const t=At.bind(this);return{options:[...s??[],{childOptions:[{text:"Align",onHover:()=>{},subMenu:{options:[{childOptions:[{text:"Align Left",onClick:()=>t(this.align.bind(this))("left")},{text:"Align Right",onClick:()=>t(this.align.bind(this))("right")},{text:"Align Top",onClick:()=>t(this.align.bind(this))("top")},{text:"Align Bottom",onClick:()=>t(this.align.bind(this))("bottom")}]}]}},{text:"Normalize by First",onHover:()=>{},subMenu:{options:[{childOptions:[{text:"Height",onClick:()=>t(this.normalizeSelection.bind(this))("height","first")},{text:"Width",onClick:()=>t(this.normalizeSelection.bind(this))("width","first")},{text:"Size",onClick:()=>t(this.normalizeSelection.bind(this))("size","first")},{text:"Scale",onClick:()=>t(this.normalizeSelection.bind(this))("scale","first")}]}]}},{text:"Normalize by Average",onHover:()=>{},subMenu:{options:[{childOptions:[{text:"Height",onClick:()=>t(this.normalizeSelection.bind(this))("height","average")},{text:"Width",onClick:()=>t(this.normalizeSelection.bind(this))("width","average")},{text:"Size",onClick:()=>t(this.normalizeSelection.bind(this))("size","average")},{text:"Scale",onClick:()=>t(this.normalizeSelection.bind(this))("scale","average")}]}]}}]}]}}function ji(s){const t=At.bind(this);return{options:[...s??[],{childOptions:[{text:"Change mode",onClick:()=>t(this.togglePointerMode.bind(this))()},{text:"Toggle Grid",onClick:()=>t(this.toggleGrid.bind(this))()}]},{childOptions:[{text:"Save",onClick:()=>t(this.saveToCanvasStorage.bind(this))()},{text:"Paste",onClick:e=>t(this.pasteImage.bind(this))(e)}]}]}}class Kt{_touch(){this._lastRetrieved=Date.now()}get id(){return this._touch(),this._id}get dataURL(){return this._touch(),this._dataURL}get mimetype(){return this._touch(),this._mimetype}get created(){return this._touch(),this._created}get lastRetrieved(){return this._lastRetrieved}constructor(t){this._dataURL=t,this._mimetype=Ze(t),this._created=Date.now(),this._lastRetrieved=Date.now()}static async create(t){const e=new Kt(t);return e._id=await Nt(t),e}}class Vi{}class qi{}function Ae(s){s.Version.prototype._parseStoresSpec=k.override(s.Version.prototype._parseStoresSpec,Zi),s.open=k.override(s.open,Qi(s))}function Zi(s){return function(t,e){s.call(this,t,e),Object.keys(e).forEach(function(i){let r=e[i];r.primKey.name.indexOf("$$")===0&&(r.primKey.uuid=!0,r.primKey.name=r.primKey.name.substr(2),r.primKey.keyPath=r.primKey.keyPath.substr(2))})}}function Ki(s){return function(e,i){let r;return e===void 0&&s.schema.primKey.uuid&&(e=r=Ge.v4(),s.schema.primKey.keyPath&&k.setByKeyPath(i,s.schema.primKey.keyPath,e)),r}}function Qi(s){return function(e){return function(){return Object.keys(s._allTables).forEach(i=>{let r=s._allTables[i];r.hook("creating").subscribe(Ki(r))}),e.apply(this,arguments)}}}k.UUIDPrimaryKey=Ae,k.addons.push(Ae),k.UUIDPrimaryKey;const Ji={files:"$$id, mimetype, created, lastRetrieved"},Oe={MAX_IMAGE_ENTRIES:1e3};class Ot extends Vi{constructor(){super(),this.dbQueue=new De,this.cache=new Map,this.CACHE_LIMIT=500,this.dbQueue=new De,this.dbPromise=this.initDb()}async initDb(){return V(async()=>{let t=new k("InfiniteCanvas");return k.UUIDPrimaryKey(t),t.version(1).stores(Ji),await t.open(),t})}async getIndexDb(){return this.dbPromise}async write(t){const e=await Kt.create(t),i=is(e.dataURL);return this.dbQueue.add(()=>V(async()=>{const r=await this.getIndexDb();return await r.transaction("rw",r.files,async()=>(await es(r),await r.files.add({id:e.id,blob:i,dataURL:e.dataURL,mimetype:e.mimetype,created:e.created,lastRetrieved:e.lastRetrieved}))).catch(n=>{throw console.error("Failed to save image blob to local DB:",n),n})}))}async readAll(){return V(async()=>await(await this.getIndexDb()).files.toArray())}async readPage(t,e){return V(async()=>await(await this.getIndexDb()).files.offset(t).limit(e).toArray())}async read(t){return V(async()=>{const e=await this.getIndexDb();if(this.cache.has(t))return this.cache.get(t);const i=await e.files.get(t);if(!i)return null;if(this.dbQueue.add(async()=>{try{await e.files.update(t,{lastRetrieved:Date.now()})}catch(r){console.error("Failed to update lastRetrieved",r)}}).catch(()=>{}),this.cache.set(t,i),this.cache.size>this.CACHE_LIMIT){const r=this.cache.keys().next().value;this.cache.delete(r)}return i})}async delete(t){return this.dbQueue.add(()=>V(async()=>{const e=await this.getIndexDb();return await e.transaction("rw",e.files,async()=>{const i=await e.files.where("id").equals(t).first();return await e.files.delete(i.id),i}).catch(i=>{throw console.error("Failed to save image blob to local DB:",i),i})}))}async update(t){return this.dbQueue.add(()=>V(async()=>{const e=await this.getIndexDb();return await e.transaction("rw",e.files,async()=>{await e.files.update(t.id,{dataURL:t.dataURL,mimetype:t.mimetype,lastRetrieved:Date.now()})}),await e.files.where("id").equals(t.id).first()}))}async checkIfImageStored(t){return V(async()=>{const i=await(await this.getIndexDb()).files.where("id").equals(t).first();return i?i.id:null})}}class Qt extends qi{constructor(t){super(),this.key="infinite_canvas",this.key=t}async write(t){return new Promise((e,i)=>{try{localStorage.setItem(this.key,JSON.stringify(t)),e()}catch(r){i(r)}})}async read(){return new Promise((t,e)=>{try{t(localStorage.getItem(this.key))}catch(i){e(i)}})}async delete(){return new Promise((t,e)=>{try{localStorage.removeItem(this.key),t()}catch(i){e(i)}})}async update(t){return this.write(t)}}class Le extends Error{constructor(t){super(t),this.name="QuotaExceededError"}}class ts extends Error{constructor(t){super(t),this.name="DatabaseLimitError"}}class De{constructor(){this.queue=Promise.resolve()}async add(t){const e=this.queue.then(()=>t());return this.queue=e.catch(()=>{}),e}}const V=async s=>{try{return await s()}catch(t){throw t instanceof DOMException&&t.name==="QuotaExceededError"?new Le("Storage quota exceeded. Please free up space."):t instanceof k.QuotaExceededError?new Le("Database quota exceeded. Please free up space."):t}};async function es(s){if(await s.files.count()>=Oe.MAX_IMAGE_ENTRIES)throw new ts(`Cannot save image: limit of ${Oe.MAX_IMAGE_ENTRIES} reached`)}function is(s){const t=s.split(","),e=t[0],i=t[1],r=e.match(/:(.*?);/),n=r?r[1]:"application/octet-stream",a=atob(i),o=a.length,h=new Uint8Array(o);for(let c=0;c<o;c++)h[c]=a.charCodeAt(c);return new Blob([h],{type:n})}class ss{get el(){return this._el}constructor(t){this.type=t.type,this.message=t.message,this._el=document.createElement("div"),this._el.classList.add("canvas-loader"),this.render()}render(){if(this._el.innerHTML="",this.type==="spinner"){const t=document.createElement("div");if(t.classList.add("canvas-loader-spinner"),this._el.appendChild(t),this.message){const e=document.createElement("div");e.classList.add("canvas-loader-message"),e.textContent=this.message,this._el.appendChild(e)}}else if(this.type==="message"){const t=document.createElement("div");t.classList.add("canvas-loader-message"),t.textContent=this.message??"",this._el.appendChild(t)}}setMessage(t){this.message=t,this.render()}setProgress(t){this.progress=t,this.render()}attachToParent(t){t.appendChild(this.el)}remove(){this._el.parentNode&&this._el.parentNode.removeChild(this._el)}}function rs(s,t){const e=new ss({type:s,message:t});e.attachToParent(this.renderRoot);const i=this.getBoundingClientRect();return e.el.style.width=`${i.right}px`,e.el.style.height=`${i.bottom}px`,e._el.style.top=`${-i.bottom}px`,e}function ns(){const s=this.renderRoot.querySelector(".canvas-loader");s&&s.remove()}var as=Object.getOwnPropertyDescriptor,Be=s=>{throw TypeError(s)},os=(s,t,e,i)=>{for(var r=i>1?void 0:i?as(t,e):t,n=s.length-1,a;n>=0;n--)(a=s[n])&&(r=a(r)||r);return r},ze=(s,t,e)=>t.has(s)||Be("Cannot "+e),d=(s,t,e)=>(ze(s,t,"read from private field"),e?e.call(s):t.get(s)),B=(s,t,e)=>t.has(s)?Be("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(s):t.set(s,e),T=(s,t,e,i)=>(ze(s,t,"write to private field"),t.set(s,e),e),y,_,Lt,q,O,F,wt,Dt,vt,Q,ot,Bt,zt,kt;w.InfiniteCanvasElement=class extends z.LitElement{constructor(){super(...arguments),this.name="Reffy",this.displayMode="fullscreen",B(this,y),B(this,_),B(this,Lt),B(this,q),B(this,O),B(this,F),B(this,wt,3e5),B(this,Dt),B(this,vt),B(this,Q),B(this,ot),B(this,Bt),B(this,zt),B(this,kt),this.handleGlobalPointerDown=t=>{!this.contains(t.target)&&!this.renderRoot.contains(t.target)&&this.clearContextMenu()}}get singleImageMenuOptions(){return d(this,Bt)}get multiImageMenuOptions(){return d(this,zt)}get canvasImageMenuOptions(){return d(this,kt)}get canvas(){return d(this,y)}get onCanvasChange(){return d(this,ot)}set onCanvasChange(t){T(this,ot,t)}get eventHub(){return d(this,_)}get rootDiv(){return d(this,Q)}connectedCallback(){super.connectedCallback(),this.handleGlobalPointerDown=this.handleGlobalPointerDown.bind(this),document.addEventListener("pointerdown",this.handleGlobalPointerDown,!0)}disconnectedCallback(){document.removeEventListener("pointerdown",this.handleGlobalPointerDown,!0),d(this,Lt)?.disconnect(),T(this,Lt,void 0),d(this,y).destroy(),super.disconnectedCallback()}firstUpdated(t){try{this.initCanvas()}catch(e){throw console.error(e),e}}updated(t){if(!(t.has("width")||t.has("height")||t.has("displayMode")))return;const i=d(this,Q),r=this.renderRoot.querySelector("canvas");i&&r&&this.resizeCanvas(i,r)}async initCanvas(){await this.warmUpStorage(),T(this,q,new Ei),T(this,_,new Xe);const t=document.createElement("div");t.style.overflow="hidden",this.renderRoot.appendChild(t),T(this,Q,t);const e=document.createElement("canvas");this.assignFileStorage=this.assignFileStorage.bind(this),this.getImageFileMetadata=this.getImageFileMetadata.bind(this),this.getAllImageFileMetdata=this.getAllImageFileMetdata.bind(this),this.saveImageFileMetadata=this.saveImageFileMetadata.bind(this),this.restoreStateFromCanvasStorage=this.restoreStateFromCanvasStorage.bind(this),this.assignCanvasStorage=this.assignCanvasStorage.bind(this),this.saveToCanvasStorage=this.saveToCanvasStorage.bind(this),this.debounceSaveToCanvasStorage=this.debounceSaveToCanvasStorage.bind(this),this.importCanvas=this.importCanvas.bind(this),this.exportCanvas=this.exportCanvas.bind(this),this.addContextMenu=Gi.bind(this),this.clearContextMenu=Xi.bind(this),this.isContextMenuActive=Ni.bind(this),this.getContainerSize=this.getContainerSize.bind(this),t.contains(e)||t.appendChild(e),this.registerSignal(),T(this,y,new pt(e,d(this,q),d(this,_),this.debounceSaveToCanvasStorage,this.saveImageFileMetadata,this.getContainerSize));try{await this.restoreStateFromCanvasStorage()}catch{console.error("Failed to restore canvas")}this.resizeCanvas(t,e);const i=Hi.bind(this)();T(this,Bt,Yi.bind(this)(i.options)),T(this,kt,ji.bind(this)()),T(this,zt,$i.bind(this)(i.options)),this.dispatchEvent(new Event("load"));const r=new Ne;r.showPanel(0),this.renderRoot.contains(r.dom)||this.renderRoot.appendChild(r.dom);const n=()=>{r&&r.update(),d(this,y).render(),requestAnimationFrame(n)};n()}normalizeCssSize(t){if(!t)return t;const e=String(t).trim();return/^\d+$/.test(e)?`${e}px`:e}resizeCanvas(t,e){t.style.width=this.displayMode==="fullscreen"?"100vw":this.normalizeCssSize(this.width),t.style.height=this.displayMode==="fullscreen"?"100vh":this.normalizeCssSize(this.height),t.style.overflow="hidden";const i=window.devicePixelRatio||1;let r=window.screen.width,n=window.screen.height;const a=Math.round(r*i),o=Math.round(n*i);(e.width!==a||e.height!==o)&&(e.width=a,e.height=o),e.style.width=`${r}px`,e.style.height=`${n}px`;const h=t.getBoundingClientRect();this.canvas.camera.viewportX=h.x,this.canvas.camera.viewportY=h.y,this.canvas.camera.state.setHeight(h.height),this.canvas.camera.state.setWidth(h.width)}registerSignal(){d(this,_).on(it.start,rs.bind(this),"spinner"),d(this,_).on(it.done,ns.bind(this)),d(this,_).on(X.Open,this.addContextMenu),d(this,_).on(X.Close,this.clearContextMenu),d(this,_).on(N.Change,()=>{d(this,ot)&&d(this,ot).call(this)}),d(this,_).on(st.Save,this.saveToCanvasStorage),d(this,_).on(st.SaveCompleted,()=>{}),d(this,_).on(st.SaveFailed,()=>console.error("Failed to Save!"))}async warmUpStorage(){d(this,O)||T(this,O,new Ot);try{await d(this,O).readAll()}catch(t){console.error("Storage warm-up failed",t)}}getContainerSize(){if(!d(this,Q))return;const t=d(this,Q).getBoundingClientRect();return[t.width,t.height]}assignCanvasStorage(t,e=d(this,wt)){T(this,F,t),T(this,wt,e),d(this,vt)&&clearInterval(d(this,vt)),T(this,vt,setInterval(this.saveToCanvasStorage,d(this,wt)))}assignFileStorage(t){T(this,O,t)}async saveImageFileMetadata(t){d(this,O)||T(this,O,new Ot);try{const e=await Nt(t);return await d(this,O).checkIfImageStored(e)?e:await d(this,O).write(t)}catch(e){console.error(e)}}async getImageFileMetadata(t){d(this,O)||T(this,O,new Ot);try{return await d(this,O).read(t)}catch(e){console.error(e)}}async getAllImageFileMetdata(){d(this,O)||T(this,O,new Ot);try{return await d(this,O).readAll()}catch(t){console.error(t)}}debounceSaveToCanvasStorage(t=1e3){d(this,F)||T(this,F,new Qt(this.name)),clearTimeout(d(this,Dt)),T(this,Dt,setTimeout(this.saveToCanvasStorage,t))}async saveToCanvasStorage(){d(this,F)||T(this,F,new Qt(this.name)),d(this,F).write(jt(d(this,y))).then(()=>d(this,_).emit(st.SaveCompleted)).catch(()=>d(this,_).emit(st.SaveFailed))}async restoreStateFromCanvasStorage(){d(this,F)||T(this,F,new Qt(this.name));const t=await d(this,F).read(),e=JSON.parse(t);e&&await Vt(e,d(this,y),this.getImageFileMetadata)}togglePointerMode(){d(this,y)&&d(this,y).changeMode()}toggleGrid(){d(this,y)&&d(this,y).toggleGrid()}zoomIn(){d(this,y)&&d(this,y).updateZoomByFixedAmount(-1)}zoomOut(){d(this,y)&&d(this,y).updateZoomByFixedAmount()}async addImages(t){if(!d(this,y))return;const e=d(this,y).getBoundingClientRect(),i=e.left+e.width/2,r=e.top+e.height/2,[n,a]=ft(i,r,d(this,y)),o=await Ke(t,h=>d(this,y).addImageToCanvas(h,n,a,1,1,!0));d(this,q).push(Tt(d(this,y),o))}async removeImage(t){if(!d(this,y))return;const e=d(this,y).getChild(t);d(this,y).removeChild(e),d(this,q).push(ei(d(this,y),e))}async addImageFromUrl(t){if(!d(this,y))return;const e=d(this,y).getBoundingClientRect(),i=e.left+e.width/2,r=e.top+e.height/2,[n,a]=ft(i,r,d(this,y)),o=await d(this,y).addImageToCanvas(t,n,a,1,1,!0);d(this,q).push(Tt(d(this,y),[o]))}async copyImage(){d(this,y)&&await ae(d(this,y).getSelected())}async pasteImage(t){d(this,y)&&await oe(t.clientX,t.clientY,d(this,y),d(this,q),!1)}flipVertical(){d(this,y)&&d(this,y).selectionManager.flip("vertical")}flipHorizontal(){d(this,y)&&d(this,y).selectionManager.flip("horizontal")}align(t){d(this,y)&&d(this,y).selectionManager.alignSelection(t)}normalizeSelection(t,e){d(this,y)&&d(this,y).selectionManager.normalize(t,e)}sendShapeToNewZOrder(t){d(this,y)&&d(this,y).setShapeZOrder(t)}deleteSelectedImages(){d(this,y)&&d(this,y).selectionManager.deleteSelected(d(this,y))}async exportCanvas(t="infinite-canvas.json"){if(!d(this,y))return;d(this,_).emit(it.start,"spinner");const e=await this.getAllImageFileMetdata(),i=jt(d(this,y),e);Qe(t,i),d(this,_).emit(it.done)}async importCanvas(t){if(d(this,_).emit(it.start,"spinner"),!d(this,y)||!t||t.length!==1)return;const e=t[0];if(!e.type||!e.type.includes("json")&&!e.name.toLowerCase().endsWith(".json"))return;const i=await Je(e);await Vt(i,d(this,y),this.getImageFileMetadata,this.saveImageFileMetadata),d(this,_).emit(st.Save),d(this,_).emit(it.done)}clearCanvas(){d(this,y)&&d(this,y).clearChildren()}getTotalNumberOfChildren(){if(d(this,y))return d(this,y).totalNumberOfChildren}getNumberOfChildrenRendered(){if(d(this,y))return d(this,y).numberOfChildrenRendered}},y=new WeakMap,_=new WeakMap,Lt=new WeakMap,q=new WeakMap,O=new WeakMap,F=new WeakMap,wt=new WeakMap,Dt=new WeakMap,vt=new WeakMap,Q=new WeakMap,ot=new WeakMap,Bt=new WeakMap,zt=new WeakMap,kt=new WeakMap,w.InfiniteCanvasElement.properties={name:{type:String,reflect:!0},width:{type:String,reflect:!0},height:{type:String,reflect:!0},displayMode:{type:String,reflect:!0}},w.InfiniteCanvasElement.styles=z.css`
148
- :host {
149
- position: relative;
150
- overflow: hidden;
151
- }
152
-
153
- .context-menu {
154
- position: absolute;
155
- background: white;
156
- min-width: 180px;
157
- background: var(--menu-bg, #fff);
158
- border-radius: 6px;
159
- border: 1px solid var(--menu-border, #9f9f9fff);
160
- box-sizing: border-box;
161
- padding: 6px 0;
162
- display: flex;
163
- gap: 2px;
164
- flex-direction: column;
165
- font-family: system-ui, sans-serif;
166
- animation: fadeInMenu 0.13s cubic-bezier(0.4, 0, 0.2, 1);
167
- overflow: scroll;
168
- }
169
-
170
- @keyframes fadeInMenu {
171
- from {
172
- opacity: 0;
173
- transform: translateY(8px);
174
- }
175
- to {
176
- opacity: 1;
177
- transform: none;
178
- }
179
- }
180
-
181
- .context-menu button {
182
- all: unset;
183
- display: flex;
184
- align-items: center;
185
- box-sizing: border-box;
186
- width: 100%;
187
- padding: 8px 18px;
188
- font-size: 15px;
189
- color: var(--menu-fg, #222);
190
- background: none;
191
- cursor: pointer;
192
- transition:
193
- background 0.1s,
194
- color 0.1s;
195
- user-select: none;
196
- outline: none;
197
- }
198
-
199
- .context-menu button:hover,
200
- .context-menu button:focus-visible {
201
- background: var(--menu-hover, #c7d5eaff);
202
- color: var(--menu-accent, #155290ff);
203
- }
204
-
205
- .context-menu button:active {
206
- background: var(--menu-active, #e3eaf3);
207
- }
208
-
209
- .context-menu button[disabled] {
210
- color: #aaa;
211
- cursor: not-allowed;
212
- background: none;
213
- }
214
-
215
- .context-menu-divider {
216
- height: 1px;
217
- background: var(--menu-divider, #c7d5eaff);
218
- margin: 6px 12px;
219
- border: none;
220
- }
221
-
222
- canvas {
223
- width: 100%;
224
- height: 100%;
225
- outline: none;
226
- padding: 0;
227
- margin: 0;
228
- touch-action: none;
229
- display: block;
230
- }
231
-
232
- .canvas-loader {
233
- position: absolute;
234
- top: 0;
235
- left: 0;
236
- display: flex;
237
- flex-direction: column;
238
- align-items: center;
239
- justify-content: center;
240
- background: rgba(255, 255, 255, 0.7);
241
- z-index: 1000;
242
- pointer-events: all;
243
- }
244
-
245
- .canvas-loader-spinner {
246
- width: 48px;
247
- height: 48px;
248
- border: 6px solid #e0e0e0;
249
- border-top: 6px solid #1976d2;
250
- border-radius: 50%;
251
- animation: canvas-loader-spin 1s linear infinite;
252
- margin-bottom: 16px;
253
- }
254
-
255
- @keyframes canvas-loader-spin {
256
- 0% {
257
- transform: rotate(0deg);
258
- }
259
- 100% {
260
- transform: rotate(360deg);
261
- }
262
- }
263
-
264
- .canvas-loader-message {
265
- font-size: 1.1rem;
266
- color: #333;
267
- background: rgba(255, 255, 255, 0.9);
268
- padding: 8px 16px;
269
- border-radius: 4px;
270
- margin-top: 8px;
271
- text-align: center;
272
- max-width: 80%;
273
- word-break: break-word;
274
- }
275
- `,w.InfiniteCanvasElement=os([Ti("infinite-canvas")],w.InfiniteCanvasElement);class Jt{constructor(t){if(!t)throw new Error("InfiniteCanvasElement is required");this.el=t,this.assignCanvasStorage=this.assignCanvasStorage.bind(this),this.zoomIn=this.zoomIn.bind(this),this.zoomOut=this.zoomOut.bind(this),this.toggleMode=this.toggleMode.bind(this),this.addImageFromLocal=this.addImageFromLocal.bind(this),this.exportCanvas=this.exportCanvas.bind(this),this.importCanvas=this.importCanvas.bind(this),this.clearCanvas=this.clearCanvas.bind(this)}static async forElement(t){let e;if(typeof t=="string"?(await customElements.whenDefined("infinite-canvas"),e=document.querySelector(t)):e=t,!e)throw new Error("infinite-canvas element not found");return e.canvas||await new Promise(i=>e.addEventListener("load",()=>i(),{once:!0})),new Jt(e)}assignCanvasStorage(t,e=3e3){return this.el.assignCanvasStorage(t,e),this}async zoomIn(){console.log("zooming"),this.el.zoomIn()}async zoomOut(){this.el.zoomOut()}async toggleMode(){this.el.togglePointerMode()}async addImageFromLocal(t){if(!(!t||t.length===0)){for(let e=0;e<t.length;e++){const i=t[e];if(!i||!i.type||!i.type.startsWith("image/"))throw new Error("Only specific image files are supported. Please select image files only.")}await this.el.addImages(t)}}async exportCanvas(t){this.el.exportCanvas(t)}async importCanvas(t){!t||t.length!==1||await this.el.importCanvas(t)}async clearCanvas(){this.el.clearCanvas()}}w.Camera=we,w.Canvas=pt,w.InfiniteCanvasAPI=Jt,w.ZOOM_MAX=xe,w.ZOOM_MIN=ye,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})}));
276
- //# sourceMappingURL=index.umd.js.map