vuedit-image-editor 0.1.0

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.
@@ -0,0 +1,3412 @@
1
+ import { reactive as Oe, ref as F, shallowRef as Be, computed as V, readonly as qe, provide as We, inject as Q, toRaw as Xe, markRaw as Ye, defineComponent as Y, openBlock as C, createElementBlock as $, normalizeClass as U, renderSlot as Ue, createCommentVNode as Z, toDisplayString as q, createElementVNode as m, createVNode as O, unref as S, withCtx as J, onMounted as ce, watch as ne, onBeforeUnmount as ue, withModifiers as le, createBlock as re, resolveDynamicComponent as be, onUpdated as Ne, Fragment as X, renderList as N, Transition as _e, normalizeStyle as se, onUnmounted as Ze, nextTick as Je, Teleport as Ge, withKeys as Se } from "vue";
2
+ function ge() {
3
+ return {
4
+ crop: {
5
+ x: 0,
6
+ y: 0,
7
+ width: 1,
8
+ height: 1,
9
+ aspectRatio: null,
10
+ rotation: 0,
11
+ flipX: !1,
12
+ flipY: !1
13
+ },
14
+ finetune: {
15
+ brightness: 0,
16
+ contrast: 0,
17
+ saturation: 0,
18
+ exposure: 0,
19
+ temperature: 0,
20
+ gamma: 1,
21
+ clarity: 0,
22
+ vignette: 0
23
+ },
24
+ filter: {
25
+ id: null,
26
+ intensity: 1
27
+ },
28
+ stickers: [],
29
+ frame: {
30
+ style: null,
31
+ size: 0.025,
32
+ color: [1, 1, 1, 1],
33
+ radius: 0
34
+ },
35
+ resize: {
36
+ fit: "contain",
37
+ upscale: !1
38
+ },
39
+ backgroundColor: [0, 0, 0, 1]
40
+ };
41
+ }
42
+ function de(a) {
43
+ return JSON.parse(JSON.stringify(a));
44
+ }
45
+ class Qe {
46
+ constructor(e = 50) {
47
+ this.states = [], this.pointer = -1, this.maxSize = e;
48
+ }
49
+ /** Push a new state snapshot. Truncates any future (redo) states. */
50
+ push(e) {
51
+ this.states = this.states.slice(0, this.pointer + 1), this.states.push(de(e)), this.states.length > this.maxSize && this.states.shift(), this.pointer = this.states.length - 1;
52
+ }
53
+ /** Undo: return the previous state, or null if at the beginning. */
54
+ undo() {
55
+ return this.pointer <= 0 ? null : (this.pointer--, de(this.states[this.pointer]));
56
+ }
57
+ /** Redo: return the next state, or null if at the end. */
58
+ redo() {
59
+ return this.pointer >= this.states.length - 1 ? null : (this.pointer++, de(this.states[this.pointer]));
60
+ }
61
+ /** Reset history with a single initial state. */
62
+ reset(e) {
63
+ this.states = [de(e)], this.pointer = 0;
64
+ }
65
+ get canUndo() {
66
+ return this.pointer > 0;
67
+ }
68
+ get canRedo() {
69
+ return this.pointer < this.states.length - 1;
70
+ }
71
+ get currentIndex() {
72
+ return this.pointer;
73
+ }
74
+ get length() {
75
+ return this.states.length;
76
+ }
77
+ }
78
+ async function et(a) {
79
+ const e = await tt(a);
80
+ return new Promise((n, t) => {
81
+ const o = new Image();
82
+ o.crossOrigin = "anonymous", o.onload = () => {
83
+ typeof a != "string" && URL.revokeObjectURL(e), n(o);
84
+ }, o.onerror = () => {
85
+ typeof a != "string" && URL.revokeObjectURL(e), t(new Error(`Failed to load image: ${typeof a == "string" ? a : "Blob/File"}`));
86
+ }, o.src = e;
87
+ });
88
+ }
89
+ async function tt(a) {
90
+ return typeof a == "string" ? a : URL.createObjectURL(a);
91
+ }
92
+ const Ke = Symbol("vuedit-image-editor"), ee = Symbol("vuedit-locale");
93
+ function he(a) {
94
+ return JSON.parse(JSON.stringify(Xe(a)));
95
+ }
96
+ function nt(a) {
97
+ const e = Oe(
98
+ a.initialState ? { ...ge(), ...JSON.parse(JSON.stringify(a.initialState)) } : ge()
99
+ ), n = he(e), t = new Qe(50);
100
+ t.reset(he(e));
101
+ const o = F(null), d = F(!1), u = F(null);
102
+ let r = 0;
103
+ const i = Be([]), h = F(null), s = F(1), l = F(null), y = F({ x: 0, y: 0 }), c = F(0), p = V(() => h.value && i.value.find((P) => P.id === h.value) || null), w = V(() => (c.value, t.canUndo)), M = V(() => (c.value, t.canRedo)), k = V(() => (c.value, t.currentIndex > 0));
104
+ async function v(P) {
105
+ const j = ++r;
106
+ d.value = !0, u.value = null;
107
+ try {
108
+ const _ = await et(P);
109
+ if (j !== r) return;
110
+ o.value = _, W();
111
+ } catch (_) {
112
+ if (j !== r) return;
113
+ u.value = _ instanceof Error ? _.message : "Failed to load image";
114
+ } finally {
115
+ j === r && (d.value = !1);
116
+ }
117
+ }
118
+ function f(P) {
119
+ if (!P.id || !P.controls) {
120
+ console.warn("[VueditImageEditor] Plugin missing required fields (id, controls):", P);
121
+ return;
122
+ }
123
+ i.value.some((j) => j.id === P.id) || (i.value = [...i.value, Ye(P)], h.value || (h.value = P.id));
124
+ }
125
+ function g(P) {
126
+ var j;
127
+ i.value = i.value.filter((_) => _.id !== P), h.value === P && (h.value = ((j = i.value[0]) == null ? void 0 : j.id) || null);
128
+ }
129
+ function b(P) {
130
+ const j = p.value;
131
+ j != null && j.onDeactivate && j.onDeactivate(), h.value = P;
132
+ const _ = i.value.find((A) => A.id === P);
133
+ _ != null && _.onActivate && _.onActivate(), W();
134
+ }
135
+ function I(P) {
136
+ P(e), t.push(he(e)), c.value++, W();
137
+ }
138
+ function H() {
139
+ const P = t.undo();
140
+ P && (Object.assign(e, P), c.value++, W());
141
+ }
142
+ function T() {
143
+ const P = t.redo();
144
+ P && (Object.assign(e, P), c.value++, W());
145
+ }
146
+ function K() {
147
+ const P = p.value;
148
+ P != null && P.onDeactivate && P.onDeactivate(), Object.assign(e, JSON.parse(JSON.stringify(n))), t.reset(he(e)), c.value++, P != null && P.onActivate && P.onActivate(), W();
149
+ }
150
+ function D(P) {
151
+ s.value = Math.max(0.1, Math.min(10, P)), W();
152
+ }
153
+ function W() {
154
+ l.value && l.value();
155
+ }
156
+ return {
157
+ state: e,
158
+ readonlyState: qe(e),
159
+ sourceImage: o,
160
+ loading: d,
161
+ error: u,
162
+ plugins: i,
163
+ activePluginId: h,
164
+ activePlugin: p,
165
+ hasEdits: k,
166
+ canUndo: w,
167
+ canRedo: M,
168
+ zoom: s,
169
+ options: a,
170
+ load: v,
171
+ registerPlugin: f,
172
+ unregisterPlugin: g,
173
+ setActivePlugin: b,
174
+ updateState: I,
175
+ undo: H,
176
+ redo: T,
177
+ revert: K,
178
+ setZoom: D,
179
+ requestRender: W,
180
+ onRender: l,
181
+ cropDragPan: y
182
+ };
183
+ }
184
+ function it(a) {
185
+ We(Ke, a);
186
+ }
187
+ function G() {
188
+ const a = Q(Ke);
189
+ if (!a)
190
+ throw new Error("[VueditImageEditor] useEditor() called outside of editor context. Make sure to use it inside <EditorShell> or <ImageEditorModal>.");
191
+ return a;
192
+ }
193
+ const xe = [
194
+ 1,
195
+ 0,
196
+ 0,
197
+ 0,
198
+ 0,
199
+ 0,
200
+ 1,
201
+ 0,
202
+ 0,
203
+ 0,
204
+ 0,
205
+ 0,
206
+ 1,
207
+ 0,
208
+ 0,
209
+ 0,
210
+ 0,
211
+ 0,
212
+ 1,
213
+ 0
214
+ ];
215
+ function ot(a, e) {
216
+ const n = new Array(20).fill(0);
217
+ for (let t = 0; t < 4; t++)
218
+ for (let o = 0; o < 5; o++) {
219
+ let d = 0;
220
+ for (let u = 0; u < 4; u++)
221
+ d += a[t * 5 + u] * e[u * 5 + o];
222
+ o === 4 && (d += a[t * 5 + 4]), n[t * 5 + o] = d;
223
+ }
224
+ return n;
225
+ }
226
+ function De(...a) {
227
+ if (a.length === 0) return [...xe];
228
+ let e = a[0];
229
+ for (let n = 1; n < a.length; n++)
230
+ e = ot(a[n], e);
231
+ return e;
232
+ }
233
+ function Ae(a) {
234
+ return [
235
+ 1,
236
+ 0,
237
+ 0,
238
+ 0,
239
+ a,
240
+ 0,
241
+ 1,
242
+ 0,
243
+ 0,
244
+ a,
245
+ 0,
246
+ 0,
247
+ 1,
248
+ 0,
249
+ a,
250
+ 0,
251
+ 0,
252
+ 0,
253
+ 1,
254
+ 0
255
+ ];
256
+ }
257
+ function Le(a) {
258
+ const e = a + 1, n = -0.5 * e + 0.5;
259
+ return [
260
+ e,
261
+ 0,
262
+ 0,
263
+ 0,
264
+ n,
265
+ 0,
266
+ e,
267
+ 0,
268
+ 0,
269
+ n,
270
+ 0,
271
+ 0,
272
+ e,
273
+ 0,
274
+ n,
275
+ 0,
276
+ 0,
277
+ 0,
278
+ 1,
279
+ 0
280
+ ];
281
+ }
282
+ function Fe(a) {
283
+ const e = a + 1, n = 1 - e, t = 0.2126 * n, o = 0.7152 * n, d = 0.0722 * n;
284
+ return [
285
+ t + e,
286
+ o,
287
+ d,
288
+ 0,
289
+ 0,
290
+ t,
291
+ o + e,
292
+ d,
293
+ 0,
294
+ 0,
295
+ t,
296
+ o,
297
+ d + e,
298
+ 0,
299
+ 0,
300
+ 0,
301
+ 0,
302
+ 0,
303
+ 1,
304
+ 0
305
+ ];
306
+ }
307
+ function He(a) {
308
+ const e = Math.pow(2, a);
309
+ return [
310
+ e,
311
+ 0,
312
+ 0,
313
+ 0,
314
+ 0,
315
+ 0,
316
+ e,
317
+ 0,
318
+ 0,
319
+ 0,
320
+ 0,
321
+ 0,
322
+ e,
323
+ 0,
324
+ 0,
325
+ 0,
326
+ 0,
327
+ 0,
328
+ 1,
329
+ 0
330
+ ];
331
+ }
332
+ function Ve(a) {
333
+ return [
334
+ 1 + a,
335
+ 0,
336
+ 0,
337
+ 0,
338
+ 0,
339
+ 0,
340
+ 1,
341
+ 0,
342
+ 0,
343
+ 0,
344
+ 0,
345
+ 0,
346
+ 1 - a,
347
+ 0,
348
+ 0,
349
+ 0,
350
+ 0,
351
+ 0,
352
+ 1,
353
+ 0
354
+ ];
355
+ }
356
+ function Ce(a, e) {
357
+ const n = a.data, t = n.length, o = e[0], d = e[1], u = e[2], r = e[3], i = e[4] * 255, h = e[5], s = e[6], l = e[7], y = e[8], c = e[9] * 255, p = e[10], w = e[11], M = e[12], k = e[13], v = e[14] * 255, f = e[15], g = e[16], b = e[17], I = e[18], H = e[19] * 255;
358
+ for (let T = 0; T < t; T += 4) {
359
+ const K = n[T], D = n[T + 1], W = n[T + 2], P = n[T + 3];
360
+ n[T] = ie(K * o + D * d + W * u + P * r + i), n[T + 1] = ie(K * h + D * s + W * l + P * y + c), n[T + 2] = ie(K * p + D * w + W * M + P * k + v), n[T + 3] = ie(K * f + D * g + W * b + P * I + H);
361
+ }
362
+ }
363
+ function ye(a, e) {
364
+ if (e === 1) return;
365
+ const n = a.data, t = 1 / e, o = new Uint8Array(256);
366
+ for (let d = 0; d < 256; d++)
367
+ o[d] = ie(Math.pow(d / 255, t) * 255);
368
+ for (let d = 0; d < n.length; d += 4)
369
+ n[d] = o[n[d]], n[d + 1] = o[n[d + 1]], n[d + 2] = o[n[d + 2]];
370
+ }
371
+ function we(a, e, n, t) {
372
+ if (e === 0) return;
373
+ const o = a.data, d = n / 2, u = t / 2, r = Math.sqrt(d * d + u * u);
374
+ for (let i = 0; i < t; i++)
375
+ for (let h = 0; h < n; h++) {
376
+ const s = (i * n + h) * 4, l = h - d, y = i - u, c = Math.sqrt(l * l + y * y) / r, p = 1 - e * c * c;
377
+ o[s] = ie(o[s] * p), o[s + 1] = ie(o[s + 1] * p), o[s + 2] = ie(o[s + 2] * p);
378
+ }
379
+ }
380
+ function ke(a, e) {
381
+ if (e === 0) return;
382
+ const { data: n, width: t, height: o } = a, d = e * 4, u = new Uint8ClampedArray(n);
383
+ for (let r = 1; r < o - 1; r++)
384
+ for (let i = 1; i < t - 1; i++) {
385
+ const h = (r * t + i) * 4;
386
+ for (let s = 0; s < 3; s++) {
387
+ const l = u[h + s], y = l * 4 - u[((r - 1) * t + i) * 4 + s] - u[((r + 1) * t + i) * 4 + s] - u[(r * t + (i - 1)) * 4 + s] - u[(r * t + (i + 1)) * 4 + s], c = l + d * y;
388
+ n[h + s] = c < 0 ? 0 : c > 255 ? 255 : c + 0.5 | 0;
389
+ }
390
+ }
391
+ }
392
+ function ie(a) {
393
+ return a < 0 ? 0 : a > 255 ? 255 : a + 0.5 | 0;
394
+ }
395
+ const at = 16777216;
396
+ class st {
397
+ /**
398
+ * Process image at FULL RESOLUTION.
399
+ * Applies all transformations and exports as Blob.
400
+ */
401
+ async process(e, n, t = {}) {
402
+ const {
403
+ mimeType: o = "image/jpeg",
404
+ quality: d = 0.92,
405
+ maxCanvasPixels: u = at
406
+ } = t, r = n.crop, i = n.finetune;
407
+ let h = Math.round(r.x * e.naturalWidth), s = Math.round(r.y * e.naturalHeight), l = Math.round(r.width * e.naturalWidth), y = Math.round(r.height * e.naturalHeight);
408
+ h = Math.max(0, Math.min(h, e.naturalWidth)), s = Math.max(0, Math.min(s, e.naturalHeight)), l = Math.min(l, e.naturalWidth - h), y = Math.min(y, e.naturalHeight - s);
409
+ let c = l, p = y;
410
+ if (n.resize.width || n.resize.height) {
411
+ const T = n.resize.width, K = n.resize.height, D = n.resize.fit;
412
+ if (T && K)
413
+ if (D === "force")
414
+ c = T, p = K;
415
+ else if (D === "cover") {
416
+ const W = Math.max(T / l, K / y);
417
+ c = Math.round(l * W), p = Math.round(y * W);
418
+ } else {
419
+ const W = Math.min(T / l, K / y);
420
+ c = Math.round(l * W), p = Math.round(y * W);
421
+ }
422
+ else if (T) {
423
+ const W = T / l;
424
+ c = T, p = Math.round(y * W);
425
+ } else if (K) {
426
+ const W = K / y;
427
+ c = Math.round(l * W), p = K;
428
+ }
429
+ n.resize.upscale || (c = Math.min(c, l), p = Math.min(p, y));
430
+ }
431
+ const w = c * p;
432
+ if (w > u) {
433
+ const T = Math.sqrt(u / w);
434
+ c = Math.floor(c * T), p = Math.floor(p * T);
435
+ }
436
+ c = Math.max(1, c), p = Math.max(1, p);
437
+ const M = Math.abs(r.rotation);
438
+ let k = c, v = p;
439
+ if (M > 1e-3) {
440
+ const T = Math.abs(Math.cos(r.rotation)), K = Math.abs(Math.sin(r.rotation));
441
+ k = Math.ceil(c * T + p * K), v = Math.ceil(c * K + p * T);
442
+ }
443
+ const f = document.createElement("canvas");
444
+ f.width = k, f.height = v;
445
+ const g = f.getContext("2d"), b = n.backgroundColor;
446
+ b[3] > 0 && (g.fillStyle = `rgba(${Math.round(b[0] * 255)}, ${Math.round(b[1] * 255)}, ${Math.round(b[2] * 255)}, ${b[3]})`, g.fillRect(0, 0, k, v)), g.save(), g.translate(k / 2, v / 2), g.rotate(r.rotation), g.scale(r.flipX ? -1 : 1, r.flipY ? -1 : 1), g.drawImage(
447
+ e,
448
+ h,
449
+ s,
450
+ l,
451
+ y,
452
+ -c / 2,
453
+ -p / 2,
454
+ c,
455
+ p
456
+ ), g.restore();
457
+ const I = [];
458
+ if (i.brightness !== 0 && I.push(Ae(i.brightness)), i.contrast !== 0 && I.push(Le(i.contrast)), i.saturation !== 0 && I.push(Fe(i.saturation)), i.exposure !== 0 && I.push(He(i.exposure)), i.temperature !== 0 && I.push(Ve(i.temperature)), n.filter.matrix)
459
+ if (n.filter.intensity < 1) {
460
+ const T = n.filter.matrix, K = n.filter.intensity, D = xe.map((W, P) => W * (1 - K) + T[P] * K);
461
+ I.push(D);
462
+ } else
463
+ I.push(n.filter.matrix);
464
+ if (I.length > 0) {
465
+ const T = De(...I), K = g.getImageData(0, 0, k, v);
466
+ Ce(K, T), i.gamma !== 1 && ye(K, i.gamma), i.clarity !== 0 && ke(K, i.clarity), i.vignette !== 0 && we(K, i.vignette, k, v), g.putImageData(K, 0, 0);
467
+ } else if (i.gamma !== 1 || i.clarity !== 0 || i.vignette !== 0) {
468
+ const T = g.getImageData(0, 0, k, v);
469
+ i.gamma !== 1 && ye(T, i.gamma), i.clarity !== 0 && ke(T, i.clarity), i.vignette !== 0 && we(T, i.vignette, k, v), g.putImageData(T, 0, 0);
470
+ }
471
+ n.frame.style && rt(g, n.frame.style, n.frame.size, n.frame.color, n.frame.radius, k, v);
472
+ for (const T of n.stickers)
473
+ await ct(g, T, k, v);
474
+ return {
475
+ blob: await new Promise((T, K) => {
476
+ f.toBlob(
477
+ (D) => D ? T(D) : K(new Error("Failed to encode image")),
478
+ o,
479
+ d
480
+ );
481
+ }),
482
+ imageState: JSON.parse(JSON.stringify(n))
483
+ };
484
+ }
485
+ }
486
+ function rt(a, e, n, t, o, d, u) {
487
+ const r = Math.round(Math.max(d, u) * n), i = Math.round(o), h = `rgba(${Math.round(t[0] * 255)}, ${Math.round(t[1] * 255)}, ${Math.round(t[2] * 255)}, ${t[3]})`;
488
+ switch (a.strokeStyle = h, a.fillStyle = h, e) {
489
+ case "solidSharp":
490
+ a.lineWidth = r, a.strokeRect(r / 2, r / 2, d - r, u - r);
491
+ break;
492
+ case "solidRound":
493
+ a.lineWidth = r, lt(a, r / 2, r / 2, d - r, u - r, i + r / 2), a.stroke();
494
+ break;
495
+ case "lineSingle": {
496
+ const s = r * 2;
497
+ a.lineWidth = 1, a.strokeRect(s, s, d - s * 2, u - s * 2);
498
+ break;
499
+ }
500
+ case "lineMultiple": {
501
+ a.lineWidth = 1;
502
+ for (let s = 1; s <= 3; s++) {
503
+ const l = r * s;
504
+ a.strokeRect(l, l, d - l * 2, u - l * 2);
505
+ }
506
+ break;
507
+ }
508
+ case "hook": {
509
+ const s = Math.min(d, u) * 0.1;
510
+ a.lineWidth = r * 0.5;
511
+ const l = r;
512
+ a.beginPath(), a.moveTo(l, l + s), a.lineTo(l, l), a.lineTo(l + s, l), a.stroke(), a.beginPath(), a.moveTo(d - l - s, l), a.lineTo(d - l, l), a.lineTo(d - l, l + s), a.stroke(), a.beginPath(), a.moveTo(l, u - l - s), a.lineTo(l, u - l), a.lineTo(l + s, u - l), a.stroke(), a.beginPath(), a.moveTo(d - l - s, u - l), a.lineTo(d - l, u - l), a.lineTo(d - l, u - l - s), a.stroke();
513
+ break;
514
+ }
515
+ case "polaroid": {
516
+ const s = r, l = r * 4;
517
+ a.fillRect(0, 0, d, s), a.fillRect(0, 0, s, u), a.fillRect(d - s, 0, s, u), a.fillRect(0, u - l, d, l);
518
+ break;
519
+ }
520
+ default:
521
+ a.lineWidth = r * 0.5, a.strokeRect(r, r, d - r * 2, u - r * 2);
522
+ break;
523
+ }
524
+ }
525
+ function lt(a, e, n, t, o, d) {
526
+ a.beginPath(), a.moveTo(e + d, n), a.lineTo(e + t - d, n), a.arcTo(e + t, n, e + t, n + d, d), a.lineTo(e + t, n + o - d), a.arcTo(e + t, n + o, e + t - d, n + o, d), a.lineTo(e + d, n + o), a.arcTo(e, n + o, e, n + o - d, d), a.lineTo(e, n + d), a.arcTo(e, n, e + d, n, d), a.closePath();
527
+ }
528
+ async function ct(a, e, n, t) {
529
+ const o = e.x * n, d = e.y * t, u = e.width * n, r = e.height * t;
530
+ if (a.save(), a.globalAlpha = e.opacity, a.translate(o + u / 2, d + r / 2), a.rotate(e.rotation), a.scale(e.flipX ? -1 : 1, e.flipY ? -1 : 1), !e.src.startsWith("http") && !e.src.startsWith("data:") && !e.src.startsWith("blob:") && !e.src.startsWith("/") && !e.src.startsWith(".")) {
531
+ const i = Math.min(u, r) * 0.8;
532
+ a.font = `${i}px sans-serif`, a.textAlign = "center", a.textBaseline = "middle", a.fillText(e.src, 0, 0);
533
+ } else
534
+ try {
535
+ const i = new Image();
536
+ i.crossOrigin = "anonymous", await new Promise((h, s) => {
537
+ i.onload = () => h(), i.onerror = () => s(), i.src = e.src;
538
+ }), a.drawImage(i, -u / 2, -r / 2, u, r);
539
+ } catch {
540
+ }
541
+ a.restore();
542
+ }
543
+ const ut = {
544
+ // Toolbar
545
+ undo: "Undo",
546
+ redo: "Redo",
547
+ revert: "Revert",
548
+ zoomIn: "Zoom In",
549
+ zoomOut: "Zoom Out",
550
+ zoomToFit: "Zoom to Fit",
551
+ done: "Done",
552
+ cancel: "Cancel",
553
+ export: "Export",
554
+ close: "Close",
555
+ // Plugin tabs
556
+ crop: "Crop",
557
+ filter: "Filter",
558
+ finetune: "Finetune",
559
+ sticker: "Sticker",
560
+ frame: "Frame",
561
+ resize: "Resize",
562
+ // Crop controls
563
+ aspectRatio: "Aspect Ratio",
564
+ custom: "Custom",
565
+ square: "Square",
566
+ landscape: "Landscape",
567
+ portrait: "Portrait",
568
+ rotation: "Rotation",
569
+ rotateLeft: "Rotate Left",
570
+ rotateRight: "Rotate Right",
571
+ flipHorizontal: "Flip Horizontal",
572
+ flipVertical: "Flip Vertical",
573
+ // Finetune labels
574
+ brightness: "Brightness",
575
+ contrast: "Contrast",
576
+ saturation: "Saturation",
577
+ exposure: "Exposure",
578
+ temperature: "Temperature",
579
+ gamma: "Gamma",
580
+ clarity: "Clarity",
581
+ vignette: "Vignette",
582
+ // Filter labels
583
+ original: "Original",
584
+ intensity: "Intensity",
585
+ chrome: "Chrome",
586
+ fade: "Fade",
587
+ pastel: "Pastel",
588
+ cold: "Cold",
589
+ warm: "Warm",
590
+ mono: "Mono",
591
+ noir: "Noir",
592
+ wash: "Wash",
593
+ stark: "Stark",
594
+ sepia: "Sepia",
595
+ rust: "Rust",
596
+ blues: "Blues",
597
+ color: "Color",
598
+ // Frame style labels
599
+ solidSharp: "Solid Sharp",
600
+ solidRound: "Solid Round",
601
+ lineSingle: "Line Single",
602
+ lineMultiple: "Line Multiple",
603
+ hook: "Hook",
604
+ polaroid: "Polaroid",
605
+ edgeSeparate: "Edge Separate",
606
+ edgeCross: "Edge Cross",
607
+ edgeOverlap: "Edge Overlap",
608
+ // Fill labels
609
+ fill: "Fill",
610
+ transparent: "Transparent",
611
+ // Sticker labels
612
+ emoji: "Emoji",
613
+ shapes: "Shapes",
614
+ // Frame labels
615
+ none: "None",
616
+ frameSize: "Frame Size",
617
+ frameColor: "Frame Color",
618
+ // Resize labels
619
+ width: "Width",
620
+ height: "Height",
621
+ lockAspectRatio: "Lock Aspect Ratio",
622
+ // Loading/error
623
+ loading: "Loading image...",
624
+ loadError: "Failed to load image",
625
+ processing: "Processing...",
626
+ // Crop overlay
627
+ cropApply: "Apply",
628
+ // Confirmation
629
+ unsavedChanges: "You have unsaved changes. Are you sure you want to close?",
630
+ confirm: "Confirm"
631
+ }, dt = {
632
+ // Toolbar
633
+ undo: "تراجع",
634
+ redo: "إعادة",
635
+ revert: "استعادة",
636
+ zoomIn: "تكبير",
637
+ zoomOut: "تصغير",
638
+ zoomToFit: "ملاءمة العرض",
639
+ done: "تم",
640
+ cancel: "إلغاء",
641
+ export: "تصدير",
642
+ close: "إغلاق",
643
+ // Plugin tabs
644
+ crop: "قص",
645
+ filter: "فلتر",
646
+ finetune: "ضبط دقيق",
647
+ sticker: "ملصق",
648
+ frame: "إطار",
649
+ resize: "تغيير الحجم",
650
+ // Crop controls
651
+ aspectRatio: "نسبة العرض إلى الارتفاع",
652
+ custom: "مخصص",
653
+ square: "مربع",
654
+ landscape: "أفقي",
655
+ portrait: "عمودي",
656
+ rotation: "دوران",
657
+ rotateLeft: "تدوير لليسار",
658
+ rotateRight: "تدوير لليمين",
659
+ flipHorizontal: "قلب أفقي",
660
+ flipVertical: "قلب عمودي",
661
+ // Finetune labels
662
+ brightness: "السطوع",
663
+ contrast: "التباين",
664
+ saturation: "التشبع",
665
+ exposure: "التعريض",
666
+ temperature: "درجة الحرارة",
667
+ gamma: "جاما",
668
+ clarity: "الوضوح",
669
+ vignette: "تظليل الأطراف",
670
+ // Filter labels
671
+ original: "الأصلي",
672
+ intensity: "الكثافة",
673
+ chrome: "كروم",
674
+ fade: "باهت",
675
+ pastel: "باستيل",
676
+ cold: "بارد",
677
+ warm: "دافئ",
678
+ mono: "أحادي",
679
+ noir: "نوار",
680
+ wash: "مغسول",
681
+ stark: "حاد",
682
+ sepia: "بني داكن",
683
+ rust: "صدأ",
684
+ blues: "أزرق",
685
+ color: "ملون",
686
+ // Frame style labels
687
+ solidSharp: "صلب حاد",
688
+ solidRound: "صلب مستدير",
689
+ lineSingle: "خط واحد",
690
+ lineMultiple: "خطوط متعددة",
691
+ hook: "خطاف",
692
+ polaroid: "بولارويد",
693
+ edgeSeparate: "حواف منفصلة",
694
+ edgeCross: "حواف متقاطعة",
695
+ edgeOverlap: "حواف متداخلة",
696
+ // Fill labels
697
+ fill: "تعبئة",
698
+ transparent: "شفاف",
699
+ // Sticker labels
700
+ emoji: "رموز تعبيرية",
701
+ shapes: "أشكال",
702
+ // Frame labels
703
+ none: "بدون",
704
+ frameSize: "حجم الإطار",
705
+ frameColor: "لون الإطار",
706
+ // Resize labels
707
+ width: "العرض",
708
+ height: "الارتفاع",
709
+ lockAspectRatio: "قفل نسبة العرض إلى الارتفاع",
710
+ // Loading/error
711
+ loading: "جاري تحميل الصورة...",
712
+ loadError: "فشل تحميل الصورة",
713
+ processing: "جاري المعالجة...",
714
+ // Crop overlay
715
+ cropApply: "تطبيق",
716
+ // Confirmation
717
+ unsavedChanges: "لديك تغييرات غير محفوظة. هل أنت متأكد أنك تريد الإغلاق؟",
718
+ confirm: "تأكيد"
719
+ }, ht = ["disabled", "title"], vt = {
720
+ key: 0,
721
+ class: "vie-icon-btn__icon"
722
+ }, pt = {
723
+ key: 1,
724
+ class: "vie-icon-btn__label"
725
+ }, te = /* @__PURE__ */ Y({
726
+ __name: "IconButton",
727
+ props: {
728
+ title: {},
729
+ label: {},
730
+ disabled: { type: Boolean },
731
+ variant: {}
732
+ },
733
+ emits: ["click"],
734
+ setup(a) {
735
+ return (e, n) => (C(), $("button", {
736
+ class: U([
737
+ "vie-icon-btn",
738
+ { "vie-icon-btn--accent": a.variant === "accent" }
739
+ ]),
740
+ disabled: a.disabled,
741
+ title: a.title,
742
+ onClick: n[0] || (n[0] = (t) => e.$emit("click", t))
743
+ }, [
744
+ e.$slots.default ? (C(), $("span", vt, [
745
+ Ue(e.$slots, "default")
746
+ ])) : Z("", !0),
747
+ a.label ? (C(), $("span", pt, q(a.label), 1)) : Z("", !0)
748
+ ], 10, ht));
749
+ }
750
+ }), ft = { class: "vie-toolbar" }, mt = { class: "vie-toolbar-group" }, gt = { class: "vie-toolbar-group" }, yt = ["title"], wt = { class: "vie-toolbar-group" }, kt = {
751
+ key: 0,
752
+ class: "vie-spinner",
753
+ style: { width: "16px", height: "16px", "border-width": "2px" }
754
+ }, bt = {
755
+ key: 1,
756
+ viewBox: "0 0 24 24",
757
+ fill: "none",
758
+ stroke: "currentColor",
759
+ "stroke-width": "2.5",
760
+ "stroke-linecap": "round",
761
+ "stroke-linejoin": "round"
762
+ }, $e = /* @__PURE__ */ Y({
763
+ __name: "EditorToolbar",
764
+ props: {
765
+ processing: { type: Boolean }
766
+ },
767
+ emits: ["done"],
768
+ setup(a) {
769
+ const e = Q(ee, (t) => t), n = G();
770
+ return (t, o) => (C(), $("div", ft, [
771
+ m("div", mt, [
772
+ O(te, {
773
+ title: S(e)("undo"),
774
+ disabled: !S(n).canUndo.value,
775
+ onClick: o[0] || (o[0] = (d) => S(n).undo())
776
+ }, {
777
+ default: J(() => [...o[7] || (o[7] = [
778
+ m("svg", {
779
+ viewBox: "0 0 24 24",
780
+ fill: "none",
781
+ stroke: "currentColor",
782
+ "stroke-width": "2",
783
+ "stroke-linecap": "round",
784
+ "stroke-linejoin": "round"
785
+ }, [
786
+ m("path", { d: "M3 10h10a5 5 0 0 1 0 10H9" }),
787
+ m("path", { d: "M3 10l4-4" }),
788
+ m("path", { d: "M3 10l4 4" })
789
+ ], -1)
790
+ ])]),
791
+ _: 1
792
+ }, 8, ["title", "disabled"]),
793
+ O(te, {
794
+ title: S(e)("redo"),
795
+ disabled: !S(n).canRedo.value,
796
+ onClick: o[1] || (o[1] = (d) => S(n).redo())
797
+ }, {
798
+ default: J(() => [...o[8] || (o[8] = [
799
+ m("svg", {
800
+ viewBox: "0 0 24 24",
801
+ fill: "none",
802
+ stroke: "currentColor",
803
+ "stroke-width": "2",
804
+ "stroke-linecap": "round",
805
+ "stroke-linejoin": "round"
806
+ }, [
807
+ m("path", { d: "M21 10H11a5 5 0 0 0 0 10h4" }),
808
+ m("path", { d: "M21 10l-4-4" }),
809
+ m("path", { d: "M21 10l-4 4" })
810
+ ], -1)
811
+ ])]),
812
+ _: 1
813
+ }, 8, ["title", "disabled"]),
814
+ O(te, {
815
+ title: S(e)("revert"),
816
+ disabled: !S(n).hasEdits.value,
817
+ onClick: o[2] || (o[2] = (d) => S(n).revert())
818
+ }, {
819
+ default: J(() => [...o[9] || (o[9] = [
820
+ m("svg", {
821
+ viewBox: "0 0 24 24",
822
+ fill: "none",
823
+ stroke: "currentColor",
824
+ "stroke-width": "2",
825
+ "stroke-linecap": "round",
826
+ "stroke-linejoin": "round"
827
+ }, [
828
+ m("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
829
+ m("path", { d: "M3 3v5h5" })
830
+ ], -1)
831
+ ])]),
832
+ _: 1
833
+ }, 8, ["title", "disabled"])
834
+ ]),
835
+ m("div", gt, [
836
+ O(te, {
837
+ title: S(e)("zoomOut"),
838
+ onClick: o[3] || (o[3] = (d) => S(n).setZoom(S(n).zoom.value - 0.1))
839
+ }, {
840
+ default: J(() => [...o[10] || (o[10] = [
841
+ m("svg", {
842
+ viewBox: "0 0 24 24",
843
+ fill: "none",
844
+ stroke: "currentColor",
845
+ "stroke-width": "2",
846
+ "stroke-linecap": "round"
847
+ }, [
848
+ m("circle", {
849
+ cx: "11",
850
+ cy: "11",
851
+ r: "8"
852
+ }),
853
+ m("path", { d: "M8 11h6" })
854
+ ], -1)
855
+ ])]),
856
+ _: 1
857
+ }, 8, ["title"]),
858
+ m("button", {
859
+ class: "vie-zoom-label",
860
+ title: S(e)("zoomToFit"),
861
+ onClick: o[4] || (o[4] = (d) => S(n).setZoom(1))
862
+ }, q(Math.round(S(n).zoom.value * 100)) + "% ", 9, yt),
863
+ O(te, {
864
+ title: S(e)("zoomIn"),
865
+ onClick: o[5] || (o[5] = (d) => S(n).setZoom(S(n).zoom.value + 0.1))
866
+ }, {
867
+ default: J(() => [...o[11] || (o[11] = [
868
+ m("svg", {
869
+ viewBox: "0 0 24 24",
870
+ fill: "none",
871
+ stroke: "currentColor",
872
+ "stroke-width": "2",
873
+ "stroke-linecap": "round"
874
+ }, [
875
+ m("circle", {
876
+ cx: "11",
877
+ cy: "11",
878
+ r: "8"
879
+ }),
880
+ m("path", { d: "M8 11h6" }),
881
+ m("path", { d: "M11 8v6" })
882
+ ], -1)
883
+ ])]),
884
+ _: 1
885
+ }, 8, ["title"])
886
+ ]),
887
+ m("div", wt, [
888
+ O(te, {
889
+ variant: "accent",
890
+ label: a.processing ? S(e)("processing") : S(e)("done"),
891
+ disabled: a.processing,
892
+ onClick: o[6] || (o[6] = (d) => t.$emit("done"))
893
+ }, {
894
+ default: J(() => [
895
+ a.processing ? (C(), $("span", kt)) : (C(), $("svg", bt, [...o[12] || (o[12] = [
896
+ m("polyline", { points: "20 6 9 17 4 12" }, null, -1)
897
+ ])]))
898
+ ]),
899
+ _: 1
900
+ }, 8, ["label", "disabled"])
901
+ ])
902
+ ]));
903
+ }
904
+ });
905
+ class _t {
906
+ constructor(e) {
907
+ this.sourceImage = null, this.animFrameId = null, this.needsRender = !0, this.viewport = { zoom: 1, panX: 0, panY: 0 }, this.activePluginId = null, this.fullImageRect = { x: 0, y: 0, width: 0, height: 0 }, this.previewCanvas = null, this.previewCtx = null, this.previewCacheKey = "", this.previewMaxSize = 1024, this.stickerImageCache = /* @__PURE__ */ new Map(), this.afterRender = null, this.getState = null, this.canvas = e;
908
+ const n = e.getContext("2d");
909
+ if (!n) throw new Error("Failed to get 2D rendering context");
910
+ this.ctx = n;
911
+ }
912
+ setSource(e) {
913
+ this.sourceImage = e, this.previewCacheKey = "", this.previewCanvas = null, this.previewCtx = null, this.needsRender = !0;
914
+ }
915
+ /** Resize canvas to match container (handles DPR) */
916
+ resize(e, n) {
917
+ const t = window.devicePixelRatio || 1;
918
+ this.canvas.width = e * t, this.canvas.height = n * t, this.canvas.style.width = `${e}px`, this.canvas.style.height = `${n}px`, this.ctx.setTransform(t, 0, 0, t, 0, 0), this.needsRender = !0;
919
+ }
920
+ /** Request a render on the next animation frame */
921
+ requestRender() {
922
+ this.needsRender = !0, this.scheduleRender();
923
+ }
924
+ /** Start the render loop */
925
+ startRenderLoop(e) {
926
+ this.getState = e, this.scheduleRender();
927
+ }
928
+ /** Schedule a single render frame (only when needed) */
929
+ scheduleRender() {
930
+ this.animFrameId === null && (this.animFrameId = requestAnimationFrame(() => {
931
+ this.animFrameId = null, this.needsRender && this.getState && (this.render(this.getState()), this.needsRender = !1);
932
+ }));
933
+ }
934
+ /** Stop the render loop */
935
+ stopRenderLoop() {
936
+ this.animFrameId !== null && (cancelAnimationFrame(this.animFrameId), this.animFrameId = null);
937
+ }
938
+ /**
939
+ * Build a cache key from the finetune + filter state.
940
+ * Only regenerates the preview canvas when these values change.
941
+ */
942
+ buildEffectsCacheKey(e, n) {
943
+ return `${e.brightness},${e.contrast},${e.saturation},${e.exposure},${e.temperature},${e.gamma},${e.clarity},${e.vignette},${n.id},${n.intensity},${n.matrix ? "M" : "N"}`;
944
+ }
945
+ /**
946
+ * Check if any color effects are active.
947
+ */
948
+ hasColorEffects(e, n) {
949
+ return e.brightness !== 0 || e.contrast !== 0 || e.saturation !== 0 || e.exposure !== 0 || e.temperature !== 0 || e.gamma !== 1 || e.clarity !== 0 || e.vignette !== 0 || n.matrix != null;
950
+ }
951
+ /**
952
+ * Get a color-adjusted preview image.
953
+ * Returns the source image if no effects are active,
954
+ * otherwise returns a cached offscreen canvas with effects applied.
955
+ */
956
+ getPreviewSource(e) {
957
+ const n = this.sourceImage, { finetune: t, filter: o } = e;
958
+ if (!this.hasColorEffects(t, o))
959
+ return n;
960
+ const d = this.buildEffectsCacheKey(t, o);
961
+ if (d === this.previewCacheKey && this.previewCanvas)
962
+ return this.previewCanvas;
963
+ const u = Math.min(
964
+ this.previewMaxSize / n.naturalWidth,
965
+ this.previewMaxSize / n.naturalHeight,
966
+ 1
967
+ ), r = Math.round(n.naturalWidth * u), i = Math.round(n.naturalHeight * u);
968
+ (!this.previewCanvas || this.previewCanvas.width !== r || this.previewCanvas.height !== i) && (this.previewCanvas = document.createElement("canvas"), this.previewCanvas.width = r, this.previewCanvas.height = i, this.previewCtx = this.previewCanvas.getContext("2d"));
969
+ const h = this.previewCtx;
970
+ h.drawImage(n, 0, 0, r, i);
971
+ const s = [];
972
+ if (t.brightness !== 0 && s.push(Ae(t.brightness)), t.contrast !== 0 && s.push(Le(t.contrast)), t.saturation !== 0 && s.push(Fe(t.saturation)), t.exposure !== 0 && s.push(He(t.exposure)), t.temperature !== 0 && s.push(Ve(t.temperature)), o.matrix)
973
+ if (o.intensity < 1) {
974
+ const y = o.matrix, c = o.intensity;
975
+ s.push(xe.map((p, w) => p * (1 - c) + y[w] * c));
976
+ } else
977
+ s.push(o.matrix);
978
+ const l = h.getImageData(0, 0, r, i);
979
+ return s.length > 0 && Ce(l, De(...s)), t.gamma !== 1 && ye(l, t.gamma), t.clarity !== 0 && ke(l, t.clarity), t.vignette !== 0 && we(l, t.vignette, r, i), h.putImageData(l, 0, 0), this.previewCacheKey = d, this.previewCanvas;
980
+ }
981
+ /** Check if crop is not at full-image defaults */
982
+ isCropActive(e) {
983
+ return e.x > 1e-3 || e.y > 1e-3 || e.width < 0.999 || e.height < 0.999;
984
+ }
985
+ /**
986
+ * Main render method.
987
+ * Draws the image with color adjustments fitted to the canvas.
988
+ * On crop tab: renders full image (CropOverlay handles crop visualization).
989
+ * On other tabs: renders only the cropped region fitted to canvas.
990
+ */
991
+ render(e) {
992
+ const n = this.ctx, t = this.canvas, o = window.devicePixelRatio || 1, d = t.width / o, u = t.height / o;
993
+ if (n.clearRect(0, 0, d, u), !this.sourceImage) return;
994
+ const r = this.sourceImage, i = e.crop, h = 40, s = d - h * 2, l = u - h * 2, y = this.activePluginId !== "crop" && this.isCropActive(i), c = this.getPreviewSource(e);
995
+ y ? this.renderCroppedView(n, e, c, d, u, s, l) : this.renderFullView(n, e, c, r, d, u, s, l), this.afterRender && this.afterRender(n, e, this.fullImageRect);
996
+ }
997
+ /**
998
+ * Render full image view (used on the crop tab).
999
+ */
1000
+ renderFullView(e, n, t, o, d, u, r, i) {
1001
+ const h = n.crop, s = Math.min(r / o.naturalWidth, i / o.naturalHeight), l = o.naturalWidth * s, y = o.naturalHeight * s, c = (d - l) / 2, p = (u - y) / 2;
1002
+ this.fullImageRect = { x: c, y: p, width: l, height: y }, e.save();
1003
+ const w = this.viewport;
1004
+ e.translate(d / 2 + w.panX, u / 2 + w.panY), e.scale(w.zoom, w.zoom), e.translate(-d / 2, -u / 2);
1005
+ const M = c + l / 2, k = p + y / 2;
1006
+ e.translate(M, k), e.rotate(h.rotation), e.scale(h.flipX ? -1 : 1, h.flipY ? -1 : 1), e.translate(-M, -k);
1007
+ const v = n.backgroundColor;
1008
+ v[3] > 0 && (e.fillStyle = `rgba(${Math.round(v[0] * 255)}, ${Math.round(v[1] * 255)}, ${Math.round(v[2] * 255)}, ${v[3]})`, e.fillRect(c, p, l, y)), e.drawImage(t, c, p, l, y), n.frame.style && this.renderFramePreview(e, n, c, p, l, y), n.stickers.length > 0 && this.renderStickers(e, n.stickers, c, p, l, y), e.restore();
1009
+ }
1010
+ /**
1011
+ * Render cropped view (used on non-crop tabs).
1012
+ * Shows only the crop region fitted to the canvas.
1013
+ */
1014
+ renderCroppedView(e, n, t, o, d, u, r) {
1015
+ const i = this.sourceImage, h = n.crop, s = i.naturalWidth * h.width, l = i.naturalHeight * h.height, y = Math.min(u / s, r / l), c = s * y, p = l * y, w = (o - c) / 2, M = (d - p) / 2;
1016
+ this.fullImageRect = { x: w, y: M, width: c, height: p };
1017
+ const k = t instanceof HTMLImageElement ? t.naturalWidth : t.width, v = t instanceof HTMLImageElement ? t.naturalHeight : t.height;
1018
+ e.save();
1019
+ const f = this.viewport;
1020
+ e.translate(o / 2 + f.panX, d / 2 + f.panY), e.scale(f.zoom, f.zoom), e.translate(-o / 2, -d / 2);
1021
+ const g = w + c / 2, b = M + p / 2;
1022
+ e.translate(g, b), e.rotate(h.rotation), e.scale(h.flipX ? -1 : 1, h.flipY ? -1 : 1), e.translate(-g, -b);
1023
+ const I = n.backgroundColor;
1024
+ I[3] > 0 && (e.fillStyle = `rgba(${Math.round(I[0] * 255)}, ${Math.round(I[1] * 255)}, ${Math.round(I[2] * 255)}, ${I[3]})`, e.fillRect(w, M, c, p)), e.drawImage(
1025
+ t,
1026
+ h.x * k,
1027
+ h.y * v,
1028
+ // source x, y
1029
+ h.width * k,
1030
+ h.height * v,
1031
+ // source w, h
1032
+ w,
1033
+ M,
1034
+ c,
1035
+ p
1036
+ // dest x, y, w, h
1037
+ ), n.frame.style && this.renderFramePreview(e, n, w, M, c, p), n.stickers.length > 0 && this.renderStickersInCrop(e, n.stickers, h, w, M, c, p), e.restore();
1038
+ }
1039
+ /**
1040
+ * Render frame preview overlay on the canvas.
1041
+ */
1042
+ renderFramePreview(e, n, t, o, d, u) {
1043
+ const r = n.frame, i = Math.round(Math.max(d, u) * r.size), h = r.color, s = `rgba(${Math.round(h[0] * 255)}, ${Math.round(h[1] * 255)}, ${Math.round(h[2] * 255)}, ${h[3]})`, l = Math.round(r.radius);
1044
+ switch (e.strokeStyle = s, e.fillStyle = s, r.style) {
1045
+ case "solidSharp":
1046
+ e.lineWidth = i, e.strokeRect(t + i / 2, o + i / 2, d - i, u - i);
1047
+ break;
1048
+ case "solidRound":
1049
+ e.lineWidth = i, e.beginPath(), e.roundRect(t + i / 2, o + i / 2, d - i, u - i, l + i / 2), e.stroke();
1050
+ break;
1051
+ case "lineSingle": {
1052
+ const y = i * 2;
1053
+ e.lineWidth = 1, e.strokeRect(t + y, o + y, d - y * 2, u - y * 2);
1054
+ break;
1055
+ }
1056
+ case "lineMultiple":
1057
+ e.lineWidth = 1;
1058
+ for (let y = 1; y <= 3; y++) {
1059
+ const c = i * y;
1060
+ e.strokeRect(t + c, o + c, d - c * 2, u - c * 2);
1061
+ }
1062
+ break;
1063
+ case "hook": {
1064
+ const y = Math.min(d, u) * 0.1;
1065
+ e.lineWidth = i * 0.5;
1066
+ const c = i;
1067
+ e.beginPath(), e.moveTo(t + c, o + c + y), e.lineTo(t + c, o + c), e.lineTo(t + c + y, o + c), e.stroke(), e.beginPath(), e.moveTo(t + d - c - y, o + c), e.lineTo(t + d - c, o + c), e.lineTo(t + d - c, o + c + y), e.stroke(), e.beginPath(), e.moveTo(t + c, o + u - c - y), e.lineTo(t + c, o + u - c), e.lineTo(t + c + y, o + u - c), e.stroke(), e.beginPath(), e.moveTo(t + d - c - y, o + u - c), e.lineTo(t + d - c, o + u - c), e.lineTo(t + d - c, o + u - c - y), e.stroke();
1068
+ break;
1069
+ }
1070
+ case "polaroid": {
1071
+ const y = i, c = i * 4;
1072
+ e.fillRect(t, o, d, y), e.fillRect(t, o, y, u), e.fillRect(t + d - y, o, y, u), e.fillRect(t, o + u - c, d, c);
1073
+ break;
1074
+ }
1075
+ default:
1076
+ e.lineWidth = i * 0.5, e.strokeRect(t + i, o + i, d - i * 2, u - i * 2);
1077
+ break;
1078
+ }
1079
+ }
1080
+ /**
1081
+ * Get the full image display rect in CSS pixels.
1082
+ * The CropOverlay uses this to position crop handles correctly.
1083
+ */
1084
+ getImageRect() {
1085
+ return { ...this.fullImageRect };
1086
+ }
1087
+ /**
1088
+ * Render stickers on the canvas viewport.
1089
+ */
1090
+ renderStickers(e, n, t, o, d, u) {
1091
+ for (const r of n) {
1092
+ const i = t + r.x * d, h = o + r.y * u, s = r.width * d, l = r.height * u;
1093
+ if (e.save(), e.globalAlpha = r.opacity, e.translate(i + s / 2, h + l / 2), e.rotate(r.rotation), e.scale(r.flipX ? -1 : 1, r.flipY ? -1 : 1), !r.src.startsWith("http") && !r.src.startsWith("data:") && !r.src.startsWith("blob:") && !r.src.startsWith("/") && !r.src.startsWith(".")) {
1094
+ const c = Math.min(s, l) * 0.8;
1095
+ e.font = `${c}px sans-serif`, e.textAlign = "center", e.textBaseline = "middle", e.fillText(r.src, 0, 0);
1096
+ } else {
1097
+ let c = this.stickerImageCache.get(r.src);
1098
+ if (!c) {
1099
+ if (this.stickerImageCache.size >= 50) {
1100
+ const p = this.stickerImageCache.keys().next().value;
1101
+ this.stickerImageCache.delete(p);
1102
+ }
1103
+ c = new Image(), c.crossOrigin = "anonymous", c.src = r.src, this.stickerImageCache.set(r.src, c), c.onload = () => {
1104
+ this.requestRender();
1105
+ }, c.onerror = () => {
1106
+ this.stickerImageCache.delete(r.src);
1107
+ };
1108
+ }
1109
+ c.complete && c.naturalWidth > 0 && e.drawImage(c, -s / 2, -l / 2, s, l);
1110
+ }
1111
+ e.restore();
1112
+ }
1113
+ }
1114
+ /**
1115
+ * Render stickers with positions remapped relative to the crop region.
1116
+ */
1117
+ renderStickersInCrop(e, n, t, o, d, u, r) {
1118
+ if (!(t.width <= 0 || t.height <= 0))
1119
+ for (const i of n) {
1120
+ const h = (i.x - t.x) / t.width, s = (i.y - t.y) / t.height, l = i.width / t.width, y = i.height / t.height;
1121
+ if (h + l < 0 || h > 1 || s + y < 0 || s > 1) continue;
1122
+ const c = o + h * u, p = d + s * r, w = l * u, M = y * r;
1123
+ if (e.save(), e.globalAlpha = i.opacity, e.translate(c + w / 2, p + M / 2), e.rotate(i.rotation), e.scale(i.flipX ? -1 : 1, i.flipY ? -1 : 1), !i.src.startsWith("http") && !i.src.startsWith("data:") && !i.src.startsWith("blob:") && !i.src.startsWith("/") && !i.src.startsWith(".")) {
1124
+ const v = Math.min(w, M) * 0.8;
1125
+ e.font = `${v}px sans-serif`, e.textAlign = "center", e.textBaseline = "middle", e.fillText(i.src, 0, 0);
1126
+ } else {
1127
+ let v = this.stickerImageCache.get(i.src);
1128
+ if (!v) {
1129
+ if (this.stickerImageCache.size >= 50) {
1130
+ const f = this.stickerImageCache.keys().next().value;
1131
+ this.stickerImageCache.delete(f);
1132
+ }
1133
+ v = new Image(), v.crossOrigin = "anonymous", v.src = i.src, this.stickerImageCache.set(i.src, v), v.onload = () => {
1134
+ this.requestRender();
1135
+ }, v.onerror = () => {
1136
+ this.stickerImageCache.delete(i.src);
1137
+ };
1138
+ }
1139
+ v.complete && v.naturalWidth > 0 && e.drawImage(v, -w / 2, -M / 2, w, M);
1140
+ }
1141
+ e.restore();
1142
+ }
1143
+ }
1144
+ destroy() {
1145
+ this.stopRenderLoop(), this.sourceImage = null, this.previewCanvas = null, this.previewCtx = null, this.stickerImageCache.clear();
1146
+ }
1147
+ }
1148
+ const xt = {
1149
+ key: 0,
1150
+ class: "vie-canvas-overlay vie-canvas-overlay--interactive"
1151
+ }, Ct = {
1152
+ key: 1,
1153
+ class: "vie-canvas-loading"
1154
+ }, Mt = {
1155
+ key: 2,
1156
+ class: "vie-canvas-loading",
1157
+ style: { color: "var(--vie-danger)" }
1158
+ }, Re = /* @__PURE__ */ Y({
1159
+ __name: "EditorCanvas",
1160
+ setup(a, { expose: e }) {
1161
+ const n = Q(ee, (R) => R), t = G(), o = F(null), d = F(null), u = F({ x: 0, y: 0, width: 0, height: 0 }), r = F({ width: 0, height: 0 });
1162
+ let i = null, h = null, s = null, l = null;
1163
+ function y() {
1164
+ i && (u.value = i.getImageRect());
1165
+ }
1166
+ ce(() => {
1167
+ if (!d.value || !o.value) return;
1168
+ i = new _t(d.value), h = new ResizeObserver((x) => {
1169
+ for (const E of x) {
1170
+ const { width: L, height: B } = E.contentRect;
1171
+ L > 0 && B > 0 && (r.value = { width: L, height: B }, i == null || i.resize(L, B), i == null || i.requestRender(), requestAnimationFrame(y));
1172
+ }
1173
+ }), h.observe(o.value);
1174
+ function R() {
1175
+ s == null || s.removeEventListener("change", l);
1176
+ const x = window.devicePixelRatio || 1;
1177
+ s = window.matchMedia(`(resolution: ${x}dppx)`), l = () => {
1178
+ const { width: E, height: L } = r.value;
1179
+ E > 0 && L > 0 && (i == null || i.resize(E, L), i == null || i.requestRender()), R();
1180
+ }, s.addEventListener("change", l);
1181
+ }
1182
+ R();
1183
+ const z = o.value.getBoundingClientRect();
1184
+ r.value = { width: z.width, height: z.height }, i.resize(z.width, z.height), i.startRenderLoop(() => t.state), i.afterRender = (x, E, L) => {
1185
+ const B = t.activePlugin.value;
1186
+ B != null && B.onRender && B.onRender({ ctx: x, state: E, imageRect: L });
1187
+ }, t.onRender.value = () => {
1188
+ i == null || i.requestRender(), requestAnimationFrame(y);
1189
+ }, i.activePluginId = t.activePluginId.value, c = t.zoom.value, p = t.zoom.value, M = 0, k = 0, v = 0, f = 0, t.options.src && t.load(t.options.src);
1190
+ }), ne(() => t.sourceImage.value, (R) => {
1191
+ i && R && (i.setSource(R), i.requestRender(), requestAnimationFrame(() => requestAnimationFrame(y)));
1192
+ }), ne(() => t.zoom.value, (R) => {
1193
+ i && (i.viewport.zoom = R, i.requestRender(), requestAnimationFrame(y)), w || (c = R, p = R, R <= 1.005 && (M = 0, k = 0, v = 0, f = 0, g()));
1194
+ }), ne(() => t.activePluginId.value, (R) => {
1195
+ i && (i.activePluginId = R, i.requestRender(), requestAnimationFrame(y));
1196
+ }), ne(() => t.cropDragPan.value, (R) => {
1197
+ i && (i.viewport.panX = v + R.x, i.viewport.panY = f + R.y, i.requestRender());
1198
+ }, { deep: !0 });
1199
+ let c = 1, p = 1, w = !1, M = 0, k = 0, v = 0, f = 0;
1200
+ function g() {
1201
+ i && (i.viewport.panX = v, i.viewport.panY = f, i.requestRender(), requestAnimationFrame(y));
1202
+ }
1203
+ function b(R) {
1204
+ const z = R.deltaY > 0 ? 0.95 : 1.05, x = Math.max(0.1, Math.min(10, c * z)), E = o.value.getBoundingClientRect(), L = R.clientX - E.left - E.width / 2, B = R.clientY - E.top - E.height / 2, oe = x / c;
1205
+ M = L - (L - M) * oe, k = B - (B - k) * oe, c = x, c <= 1.005 && (M = 0, k = 0), w || (w = !0, I());
1206
+ }
1207
+ function I() {
1208
+ const R = c - p, z = M - v, x = k - f;
1209
+ if (Math.abs(R) < 1e-3 && Math.abs(z) < 0.5 && Math.abs(x) < 0.5) {
1210
+ p = c, v = M, f = k, t.setZoom(p), g(), w = !1;
1211
+ return;
1212
+ }
1213
+ const L = 0.15;
1214
+ p += R * L, v += z * L, f += x * L, t.setZoom(p), g(), requestAnimationFrame(I);
1215
+ }
1216
+ const H = F(!1), T = V(() => t.zoom.value > 1.005 && t.activePluginId.value !== "crop");
1217
+ function K(R) {
1218
+ if (R.button !== 0 || !T.value || R.target !== o.value && R.target !== d.value) return;
1219
+ R.preventDefault(), H.value = !0;
1220
+ const z = R.clientX, x = R.clientY, E = M, L = k, B = (Me) => {
1221
+ M = E + (Me.clientX - z), k = L + (Me.clientY - x), v = M, f = k, g();
1222
+ }, oe = () => {
1223
+ H.value = !1, window.removeEventListener("mousemove", B), window.removeEventListener("mouseup", oe);
1224
+ };
1225
+ window.addEventListener("mousemove", B), window.addEventListener("mouseup", oe);
1226
+ }
1227
+ let D = 0, W = 1;
1228
+ function P(R, z) {
1229
+ const x = R.clientX - z.clientX, E = R.clientY - z.clientY;
1230
+ return Math.sqrt(x * x + E * E);
1231
+ }
1232
+ function j(R) {
1233
+ R.touches.length === 2 && (D = P(R.touches[0], R.touches[1]), W = t.zoom.value);
1234
+ }
1235
+ function _(R) {
1236
+ if (R.touches.length === 2) {
1237
+ const z = P(R.touches[0], R.touches[1]);
1238
+ if (D > 0) {
1239
+ const x = z / D;
1240
+ t.setZoom(W * x);
1241
+ }
1242
+ }
1243
+ }
1244
+ function A(R) {
1245
+ D = 0;
1246
+ }
1247
+ return ue(() => {
1248
+ h == null || h.disconnect(), s == null || s.removeEventListener("change", l), s = null, i == null || i.destroy(), i = null, t.onRender.value = null;
1249
+ }), e({
1250
+ getRenderer: () => i
1251
+ }), (R, z) => {
1252
+ var x;
1253
+ return C(), $("div", {
1254
+ class: U(["vie-canvas-wrapper", { "vie-canvas-wrapper--grab": T.value, "vie-canvas-wrapper--grabbing": H.value }]),
1255
+ ref_key: "wrapperRef",
1256
+ ref: o,
1257
+ onWheel: le(b, ["prevent"]),
1258
+ onMousedown: K,
1259
+ onTouchstartPassive: j,
1260
+ onTouchmove: le(_, ["prevent"]),
1261
+ onTouchendPassive: A
1262
+ }, [
1263
+ m("canvas", {
1264
+ ref_key: "canvasRef",
1265
+ ref: d,
1266
+ class: "vie-canvas"
1267
+ }, null, 512),
1268
+ (x = S(t).activePlugin.value) != null && x.overlay ? (C(), $("div", xt, [
1269
+ (C(), re(be(S(t).activePlugin.value.overlay), {
1270
+ "canvas-rect": u.value,
1271
+ "wrapper-size": r.value
1272
+ }, null, 8, ["canvas-rect", "wrapper-size"]))
1273
+ ])) : Z("", !0),
1274
+ S(t).loading.value ? (C(), $("div", Ct, [
1275
+ z[0] || (z[0] = m("span", { class: "vie-spinner" }, null, -1)),
1276
+ m("span", null, q(S(n)("loading")), 1)
1277
+ ])) : Z("", !0),
1278
+ S(t).error.value ? (C(), $("div", Mt, q(S(n)("loadError")), 1)) : Z("", !0)
1279
+ ], 34);
1280
+ };
1281
+ }
1282
+ }), St = {
1283
+ class: "vie-tab-bar",
1284
+ role: "tablist"
1285
+ }, $t = ["aria-selected", "onClick"], Rt = { class: "vie-tab__label" }, Ie = /* @__PURE__ */ Y({
1286
+ __name: "EditorTabs",
1287
+ setup(a) {
1288
+ const e = Q(ee, (i) => i), n = G(), t = F([]), o = /* @__PURE__ */ new Set([
1289
+ "svg",
1290
+ "path",
1291
+ "circle",
1292
+ "rect",
1293
+ "line",
1294
+ "polyline",
1295
+ "polygon",
1296
+ "ellipse",
1297
+ "g",
1298
+ "defs",
1299
+ "clippath",
1300
+ "mask",
1301
+ "use",
1302
+ "text",
1303
+ "tspan"
1304
+ ]), d = /* @__PURE__ */ new Set([
1305
+ "viewbox",
1306
+ "width",
1307
+ "height",
1308
+ "fill",
1309
+ "stroke",
1310
+ "stroke-width",
1311
+ "stroke-linecap",
1312
+ "stroke-linejoin",
1313
+ "d",
1314
+ "cx",
1315
+ "cy",
1316
+ "r",
1317
+ "rx",
1318
+ "ry",
1319
+ "x",
1320
+ "y",
1321
+ "x1",
1322
+ "y1",
1323
+ "x2",
1324
+ "y2",
1325
+ "points",
1326
+ "transform",
1327
+ "opacity",
1328
+ "class",
1329
+ "id",
1330
+ "clip-path",
1331
+ "clip-rule",
1332
+ "fill-rule",
1333
+ "fill-opacity",
1334
+ "stroke-opacity",
1335
+ "stroke-dasharray",
1336
+ "stroke-dashoffset"
1337
+ ]);
1338
+ function u(i) {
1339
+ const l = new DOMParser().parseFromString(i, "image/svg+xml").documentElement;
1340
+ function y(c) {
1341
+ const p = Array.from(c.children);
1342
+ for (const w of p)
1343
+ if (!o.has(w.tagName.toLowerCase()))
1344
+ w.remove();
1345
+ else {
1346
+ for (const M of Array.from(w.attributes))
1347
+ d.has(M.name.toLowerCase()) || w.removeAttribute(M.name);
1348
+ y(w);
1349
+ }
1350
+ }
1351
+ return y(l), l.outerHTML;
1352
+ }
1353
+ function r() {
1354
+ const i = n.plugins.value.filter((h) => typeof h.icon == "string");
1355
+ t.value.forEach((h, s) => {
1356
+ h && i[s] && (h.innerHTML = u(i[s].icon));
1357
+ });
1358
+ }
1359
+ return ce(r), Ne(r), (i, h) => (C(), $("div", St, [
1360
+ (C(!0), $(X, null, N(S(n).plugins.value, (s) => (C(), $("button", {
1361
+ key: s.id,
1362
+ role: "tab",
1363
+ "aria-selected": s.id === S(n).activePluginId.value,
1364
+ class: U([
1365
+ "vie-tab",
1366
+ { "vie-tab--active": s.id === S(n).activePluginId.value }
1367
+ ]),
1368
+ onClick: (l) => S(n).setActivePlugin(s.id)
1369
+ }, [
1370
+ typeof s.icon == "string" ? (C(), $("span", {
1371
+ key: 0,
1372
+ class: "vie-tab__icon",
1373
+ ref_for: !0,
1374
+ ref_key: "iconRefs",
1375
+ ref: t
1376
+ }, null, 512)) : (C(), re(be(s.icon), {
1377
+ key: 1,
1378
+ class: "vie-tab__icon"
1379
+ })),
1380
+ m("span", Rt, q(S(e)(s.labelKey)), 1)
1381
+ ], 10, $t))), 128))
1382
+ ]));
1383
+ }
1384
+ }), It = {
1385
+ key: 0,
1386
+ class: "vie-control-panel"
1387
+ }, ze = /* @__PURE__ */ Y({
1388
+ __name: "EditorControlPanel",
1389
+ setup(a) {
1390
+ const e = G();
1391
+ return (n, t) => {
1392
+ var o;
1393
+ return (o = S(e).activePlugin.value) != null && o.controls ? (C(), $("div", It, [
1394
+ O(_e, {
1395
+ name: "vie-panel",
1396
+ mode: "out-in"
1397
+ }, {
1398
+ default: J(() => [
1399
+ (C(), re(be(S(e).activePlugin.value.controls), {
1400
+ key: S(e).activePluginId.value
1401
+ }))
1402
+ ]),
1403
+ _: 1
1404
+ })
1405
+ ])) : Z("", !0);
1406
+ };
1407
+ }
1408
+ }), zt = ["aria-valuemin", "aria-valuemax", "aria-valuenow", "aria-labelledby"], Pt = { class: "vie-slider__track" }, Et = {
1409
+ key: 0,
1410
+ class: "vie-slider__tooltip"
1411
+ }, Tt = { class: "vie-slider__value" }, ve = /* @__PURE__ */ Y({
1412
+ __name: "Slider",
1413
+ props: {
1414
+ modelValue: {},
1415
+ min: { default: 0 },
1416
+ max: { default: 1 },
1417
+ step: { default: 0.01 },
1418
+ base: { default: 0 },
1419
+ label: {},
1420
+ format: { default: "percent" },
1421
+ ticks: {}
1422
+ },
1423
+ emits: ["update:modelValue"],
1424
+ setup(a, { emit: e }) {
1425
+ const n = `vie-slider-${Math.random().toString(36).slice(2, 9)}`, t = a, o = e, d = F(null), u = F(!1), r = V(() => (t.modelValue - t.min) / (t.max - t.min)), i = V(() => (t.base - t.min) / (t.max - t.min)), h = V(() => t.ticks ? t.ticks.map((k) => (k - t.min) / (t.max - t.min)) : []), s = V(() => r.value * 100), l = V(() => {
1426
+ const k = Math.min(i.value, r.value), v = Math.max(i.value, r.value);
1427
+ return {
1428
+ left: k * 100 + "%",
1429
+ width: (v - k) * 100 + "%"
1430
+ };
1431
+ }), y = V(() => t.format === "percent" ? Math.round(t.modelValue * 100) + "%" : t.modelValue.toFixed(2));
1432
+ function c(k) {
1433
+ if (!d.value) return t.modelValue;
1434
+ const v = d.value.getBoundingClientRect(), f = getComputedStyle(d.value).direction === "rtl";
1435
+ let g;
1436
+ f ? g = (v.right - k.clientX) / v.width : g = (k.clientX - v.left) / v.width, g = Math.max(0, Math.min(1, g));
1437
+ let b = t.min + g * (t.max - t.min);
1438
+ return b = Math.round(b / t.step) * t.step, Math.max(t.min, Math.min(t.max, b));
1439
+ }
1440
+ function p(k) {
1441
+ if (k.button !== 0) return;
1442
+ u.value = !0, o("update:modelValue", c(k));
1443
+ const v = (g) => {
1444
+ o("update:modelValue", c(g));
1445
+ }, f = () => {
1446
+ u.value = !1, window.removeEventListener("pointermove", v), window.removeEventListener("pointerup", f);
1447
+ };
1448
+ window.addEventListener("pointermove", v), window.addEventListener("pointerup", f);
1449
+ }
1450
+ function w() {
1451
+ o("update:modelValue", t.base);
1452
+ }
1453
+ function M(k) {
1454
+ let v = t.modelValue;
1455
+ switch (k.key) {
1456
+ case "ArrowRight":
1457
+ case "ArrowUp":
1458
+ v = Math.min(t.max, t.modelValue + t.step);
1459
+ break;
1460
+ case "ArrowLeft":
1461
+ case "ArrowDown":
1462
+ v = Math.max(t.min, t.modelValue - t.step);
1463
+ break;
1464
+ case "Home":
1465
+ v = t.min;
1466
+ break;
1467
+ case "End":
1468
+ v = t.max;
1469
+ break;
1470
+ default:
1471
+ return;
1472
+ }
1473
+ k.preventDefault(), o("update:modelValue", Math.round(v / t.step) * t.step);
1474
+ }
1475
+ return (k, v) => (C(), $("div", {
1476
+ class: U(["vie-slider", { "vie-slider--dragging": u.value }])
1477
+ }, [
1478
+ a.label ? (C(), $("span", {
1479
+ key: 0,
1480
+ class: "vie-slider__label",
1481
+ id: n
1482
+ }, q(a.label), 1)) : Z("", !0),
1483
+ m("div", {
1484
+ ref_key: "trackRef",
1485
+ ref: d,
1486
+ class: "vie-slider__track-wrapper",
1487
+ role: "slider",
1488
+ tabindex: "0",
1489
+ "aria-valuemin": a.min,
1490
+ "aria-valuemax": a.max,
1491
+ "aria-valuenow": a.modelValue,
1492
+ "aria-labelledby": a.label ? n : void 0,
1493
+ onPointerdown: p,
1494
+ onDblclick: w,
1495
+ onKeydown: M
1496
+ }, [
1497
+ m("div", Pt, [
1498
+ m("div", {
1499
+ class: "vie-slider__base-mark",
1500
+ style: se({ left: i.value * 100 + "%" })
1501
+ }, null, 4),
1502
+ (C(!0), $(X, null, N(h.value, (f, g) => (C(), $("div", {
1503
+ key: g,
1504
+ class: "vie-slider__tick",
1505
+ style: se({ left: f * 100 + "%" })
1506
+ }, null, 4))), 128)),
1507
+ m("div", {
1508
+ class: "vie-slider__fill",
1509
+ style: se(l.value)
1510
+ }, null, 4),
1511
+ m("div", {
1512
+ class: "vie-slider__thumb",
1513
+ style: se({ left: s.value + "%" })
1514
+ }, [
1515
+ v[0] || (v[0] = m("span", { class: "vie-slider__thumb-dot" }, null, -1)),
1516
+ u.value ? (C(), $("span", Et, q(y.value), 1)) : Z("", !0)
1517
+ ], 4)
1518
+ ])
1519
+ ], 40, zt),
1520
+ m("span", Tt, q(y.value), 1)
1521
+ ], 2));
1522
+ }
1523
+ }), Wt = ["aria-expanded"], Kt = {
1524
+ key: 0,
1525
+ class: "vie-dropdown__menu",
1526
+ role: "listbox"
1527
+ }, Dt = ["aria-selected", "onClick"], At = /* @__PURE__ */ Y({
1528
+ __name: "Dropdown",
1529
+ props: {
1530
+ modelValue: {},
1531
+ options: {}
1532
+ },
1533
+ emits: ["update:modelValue"],
1534
+ setup(a, { emit: e }) {
1535
+ const n = a, t = e, o = F(!1), d = F(null), u = V(() => {
1536
+ const h = n.options.find((s) => s.value === n.modelValue);
1537
+ return h ? h.label : "";
1538
+ });
1539
+ function r(h) {
1540
+ t("update:modelValue", h), o.value = !1;
1541
+ }
1542
+ function i(h) {
1543
+ d.value && !d.value.contains(h.target) && (o.value = !1);
1544
+ }
1545
+ return ne(o, (h) => {
1546
+ h ? document.addEventListener("click", i) : document.removeEventListener("click", i);
1547
+ }), ue(() => {
1548
+ document.removeEventListener("click", i);
1549
+ }), (h, s) => (C(), $("div", {
1550
+ class: "vie-dropdown",
1551
+ ref_key: "dropdownRef",
1552
+ ref: d
1553
+ }, [
1554
+ m("button", {
1555
+ class: "vie-dropdown__trigger",
1556
+ role: "combobox",
1557
+ "aria-expanded": o.value,
1558
+ "aria-haspopup": "listbox",
1559
+ onClick: s[0] || (s[0] = (l) => o.value = !o.value)
1560
+ }, [
1561
+ m("span", null, q(u.value), 1),
1562
+ s[1] || (s[1] = m("svg", {
1563
+ class: "vie-dropdown__chevron",
1564
+ viewBox: "0 0 24 24",
1565
+ fill: "none",
1566
+ stroke: "currentColor",
1567
+ "stroke-width": "2"
1568
+ }, [
1569
+ m("path", { d: "M6 9l6 6 6-6" })
1570
+ ], -1))
1571
+ ], 8, Wt),
1572
+ O(_e, { name: "vie-dropdown" }, {
1573
+ default: J(() => [
1574
+ o.value ? (C(), $("div", Kt, [
1575
+ (C(!0), $(X, null, N(a.options, (l) => (C(), $("button", {
1576
+ key: l.value,
1577
+ role: "option",
1578
+ "aria-selected": l.value === a.modelValue,
1579
+ class: U([
1580
+ "vie-dropdown__item",
1581
+ { "vie-dropdown__item--active": l.value === a.modelValue }
1582
+ ]),
1583
+ onClick: (y) => r(l.value)
1584
+ }, q(l.label), 11, Dt))), 128))
1585
+ ])) : Z("", !0)
1586
+ ]),
1587
+ _: 1
1588
+ })
1589
+ ], 512));
1590
+ }
1591
+ }), Lt = [
1592
+ { labelKey: "custom", value: null },
1593
+ { labelKey: "square", value: 1 },
1594
+ { labelKey: "landscape", value: 4 / 3 },
1595
+ { labelKey: "landscape", value: 16 / 9 },
1596
+ { labelKey: "portrait", value: 3 / 4 },
1597
+ { labelKey: "portrait", value: 9 / 16 }
1598
+ ];
1599
+ function Ft(a, e) {
1600
+ if (a.value === null) return e("custom");
1601
+ if (a.value === 1) return e("square") + " 1:1";
1602
+ const t = {
1603
+ [4 / 3]: "4:3",
1604
+ [16 / 9]: "16:9",
1605
+ [3 / 4]: "3:4",
1606
+ [9 / 16]: "9:16"
1607
+ }[a.value] || `${a.value.toFixed(2)}`, o = a.value > 1 ? "landscape" : "portrait";
1608
+ return `${e(o)} ${t}`;
1609
+ }
1610
+ const Ht = { class: "vie-crop-controls" }, Vt = { class: "vie-crop-controls__section" }, jt = { class: "vie-crop-controls__section" }, Ot = { class: "vie-crop-controls__section" }, Bt = { class: "vie-crop-controls__rotation" }, qt = /* @__PURE__ */ Y({
1611
+ __name: "CropControls",
1612
+ setup(a) {
1613
+ const e = Q(ee, (c) => c), n = G();
1614
+ let t = !1;
1615
+ ne(() => n.sourceImage.value, (c) => {
1616
+ if (!c || t) return;
1617
+ const p = n.state.crop;
1618
+ if (!(p.x === 0 && p.y === 0 && p.width === 1 && p.height === 1 && p.aspectRatio === null && p.rotation === 0 && !p.flipX && !p.flipY)) return;
1619
+ t = !0;
1620
+ const M = c.naturalWidth / c.naturalHeight;
1621
+ if (M >= 1) {
1622
+ const k = 1 / M;
1623
+ n.updateState((v) => {
1624
+ v.crop.x = (1 - k) / 2, v.crop.y = 0, v.crop.width = k, v.crop.height = 1, v.crop.aspectRatio = 1;
1625
+ });
1626
+ } else {
1627
+ const k = M;
1628
+ n.updateState((v) => {
1629
+ v.crop.x = 0, v.crop.y = (1 - k) / 2, v.crop.width = 1, v.crop.height = k, v.crop.aspectRatio = 1;
1630
+ });
1631
+ }
1632
+ }, { immediate: !0 });
1633
+ const o = V(
1634
+ () => Lt.map((c) => ({
1635
+ label: Ft(c, e),
1636
+ value: c.value == null ? "custom" : c.value
1637
+ }))
1638
+ ), d = V(() => {
1639
+ const c = n.state.crop.aspectRatio;
1640
+ return c === null ? "custom" : c;
1641
+ });
1642
+ function u(c) {
1643
+ const p = c === "custom" ? null : Number(c);
1644
+ n.updateState((w) => {
1645
+ if (w.crop.aspectRatio = p, p !== null) {
1646
+ const M = w.crop.width, k = w.crop.height;
1647
+ if (M / k > p) {
1648
+ const f = k * p;
1649
+ w.crop.x += (M - f) / 2, w.crop.width = f;
1650
+ } else {
1651
+ const f = M / p;
1652
+ w.crop.y += (k - f) / 2, w.crop.height = f;
1653
+ }
1654
+ }
1655
+ });
1656
+ }
1657
+ const r = V(() => n.state.crop.rotation * 180 / Math.PI);
1658
+ function i(c) {
1659
+ n.updateState((p) => {
1660
+ p.crop.rotation = c * Math.PI / 180;
1661
+ });
1662
+ }
1663
+ function h() {
1664
+ n.updateState((c) => {
1665
+ c.crop.rotation -= Math.PI / 2;
1666
+ });
1667
+ }
1668
+ function s() {
1669
+ n.updateState((c) => {
1670
+ c.crop.rotation += Math.PI / 2;
1671
+ });
1672
+ }
1673
+ function l() {
1674
+ n.updateState((c) => {
1675
+ c.crop.flipX = !c.crop.flipX;
1676
+ });
1677
+ }
1678
+ function y() {
1679
+ n.updateState((c) => {
1680
+ c.crop.flipY = !c.crop.flipY;
1681
+ });
1682
+ }
1683
+ return (c, p) => (C(), $("div", Ht, [
1684
+ m("div", Vt, [
1685
+ O(At, {
1686
+ "model-value": d.value,
1687
+ options: o.value,
1688
+ "onUpdate:modelValue": u
1689
+ }, null, 8, ["model-value", "options"])
1690
+ ]),
1691
+ p[4] || (p[4] = m("div", { class: "vie-crop-controls__divider" }, null, -1)),
1692
+ m("div", jt, [
1693
+ O(te, {
1694
+ title: S(e)("rotateLeft"),
1695
+ onClick: h
1696
+ }, {
1697
+ default: J(() => [...p[0] || (p[0] = [
1698
+ m("svg", {
1699
+ viewBox: "0 0 24 24",
1700
+ fill: "none",
1701
+ stroke: "currentColor",
1702
+ "stroke-width": "2",
1703
+ "stroke-linecap": "round",
1704
+ "stroke-linejoin": "round"
1705
+ }, [
1706
+ m("path", { d: "M2.5 2v6h6" }),
1707
+ m("path", { d: "M2.5 8C5 4 9 2 13 2a9 9 0 1 1-6 15.7" })
1708
+ ], -1)
1709
+ ])]),
1710
+ _: 1
1711
+ }, 8, ["title"]),
1712
+ O(te, {
1713
+ title: S(e)("rotateRight"),
1714
+ onClick: s
1715
+ }, {
1716
+ default: J(() => [...p[1] || (p[1] = [
1717
+ m("svg", {
1718
+ viewBox: "0 0 24 24",
1719
+ fill: "none",
1720
+ stroke: "currentColor",
1721
+ "stroke-width": "2",
1722
+ "stroke-linecap": "round",
1723
+ "stroke-linejoin": "round"
1724
+ }, [
1725
+ m("path", { d: "M21.5 2v6h-6" }),
1726
+ m("path", { d: "M21.5 8C19 4 15 2 11 2a9 9 0 1 0 6 15.7" })
1727
+ ], -1)
1728
+ ])]),
1729
+ _: 1
1730
+ }, 8, ["title"])
1731
+ ]),
1732
+ p[5] || (p[5] = m("div", { class: "vie-crop-controls__divider" }, null, -1)),
1733
+ m("div", Ot, [
1734
+ O(te, {
1735
+ title: S(e)("flipHorizontal"),
1736
+ onClick: l
1737
+ }, {
1738
+ default: J(() => [...p[2] || (p[2] = [
1739
+ m("svg", {
1740
+ viewBox: "0 0 24 24",
1741
+ fill: "none",
1742
+ stroke: "currentColor",
1743
+ "stroke-width": "2",
1744
+ "stroke-linecap": "round"
1745
+ }, [
1746
+ m("path", { d: "M12 3v18" }),
1747
+ m("path", { d: "M16 7l4 5-4 5" }),
1748
+ m("path", { d: "M8 7L4 12l4 5" })
1749
+ ], -1)
1750
+ ])]),
1751
+ _: 1
1752
+ }, 8, ["title"]),
1753
+ O(te, {
1754
+ title: S(e)("flipVertical"),
1755
+ onClick: y
1756
+ }, {
1757
+ default: J(() => [...p[3] || (p[3] = [
1758
+ m("svg", {
1759
+ viewBox: "0 0 24 24",
1760
+ fill: "none",
1761
+ stroke: "currentColor",
1762
+ "stroke-width": "2",
1763
+ "stroke-linecap": "round"
1764
+ }, [
1765
+ m("path", { d: "M3 12h18" }),
1766
+ m("path", { d: "M7 8L12 4l5 4" }),
1767
+ m("path", { d: "M7 16l5 4 5-4" })
1768
+ ], -1)
1769
+ ])]),
1770
+ _: 1
1771
+ }, 8, ["title"])
1772
+ ]),
1773
+ p[6] || (p[6] = m("div", { class: "vie-crop-controls__divider" }, null, -1)),
1774
+ m("div", Bt, [
1775
+ O(ve, {
1776
+ label: S(e)("rotation"),
1777
+ "model-value": r.value,
1778
+ min: -45,
1779
+ max: 45,
1780
+ step: 0.5,
1781
+ base: 0,
1782
+ format: "number",
1783
+ ticks: [-45, -30, -15, 0, 15, 30, 45],
1784
+ "onUpdate:modelValue": i
1785
+ }, null, 8, ["label", "model-value"])
1786
+ ])
1787
+ ]));
1788
+ }
1789
+ }), Xt = ["viewBox", "width", "height"], Yt = ["width", "height"], Ut = ["x", "y", "width", "height"], Nt = ["width", "height", "mask"], Zt = ["x", "y", "width", "height"], Jt = {
1790
+ key: 0,
1791
+ class: "vie-crop-grid"
1792
+ }, Gt = ["x1", "y1", "x2", "y2"], Qt = ["x1", "y1", "x2", "y2"], en = ["x", "y", "width", "height"], tn = ["x", "y", "data-handle"], nn = ["x", "y", "width", "height", "data-handle"], on = ["x", "y"], an = {
1793
+ xmlns: "http://www.w3.org/1999/xhtml",
1794
+ style: { display: "flex", "justify-content": "center", "pointer-events": "none" }
1795
+ }, ae = 12, sn = 8, rn = 32, ln = /* @__PURE__ */ Y({
1796
+ __name: "CropOverlay",
1797
+ props: {
1798
+ canvasRect: {},
1799
+ wrapperSize: {}
1800
+ },
1801
+ setup(a) {
1802
+ const e = `vie-crop-mask-${Math.random().toString(36).slice(2, 9)}`, n = a, t = G(), o = Q(ee, (f) => f), d = V(() => n.wrapperSize.width || 800), u = V(() => n.wrapperSize.height || 600), r = V(() => {
1803
+ const f = n.canvasRect, g = t.state.crop;
1804
+ return {
1805
+ x: f.x + g.x * f.width,
1806
+ y: f.y + g.y * f.height,
1807
+ width: g.width * f.width,
1808
+ height: g.height * f.height
1809
+ };
1810
+ }), i = V(() => {
1811
+ const f = r.value, b = ae / 2;
1812
+ return [
1813
+ { id: "nw", x: f.x - b, y: f.y - b },
1814
+ { id: "ne", x: f.x + f.width - b, y: f.y - b },
1815
+ { id: "sw", x: f.x - b, y: f.y + f.height - b },
1816
+ { id: "se", x: f.x + f.width - b, y: f.y + f.height - b }
1817
+ ];
1818
+ }), h = V(() => {
1819
+ const f = r.value, g = Math.min(rn, f.width * 0.3, f.height * 0.3), b = sn;
1820
+ return [
1821
+ { id: "n", x: f.x + (f.width - g) / 2, y: f.y - b / 2, w: g, h: b },
1822
+ { id: "s", x: f.x + (f.width - g) / 2, y: f.y + f.height - b / 2, w: g, h: b },
1823
+ { id: "w", x: f.x - b / 2, y: f.y + (f.height - g) / 2, w: b, h: g },
1824
+ { id: "e", x: f.x + f.width - b / 2, y: f.y + (f.height - g) / 2, w: b, h: g }
1825
+ ];
1826
+ }), s = F(null), l = F({ x: 0, y: 0 }), y = F({ x: 0, y: 0, width: 0, height: 0 }), c = F(!1);
1827
+ let p = null;
1828
+ function w(f) {
1829
+ const g = f.target, b = g.getAttribute("data-handle");
1830
+ if (!b) return;
1831
+ f.preventDefault();
1832
+ const I = g.ownerSVGElement || g;
1833
+ I.setPointerCapture(f.pointerId), s.value = b, l.value = { x: f.clientX, y: f.clientY }, y.value = { ...t.state.crop };
1834
+ const H = (D) => {
1835
+ if (!s.value) return;
1836
+ const W = n.canvasRect;
1837
+ if (W.width === 0 || W.height === 0) return;
1838
+ const P = (D.clientX - l.value.x) / W.width, j = (D.clientY - l.value.y) / W.height, _ = y.value, A = t.state.crop, R = A.aspectRatio;
1839
+ switch (s.value) {
1840
+ case "move": {
1841
+ const z = D.clientX - l.value.x, x = D.clientY - l.value.y, E = v(_.x - z / W.width, 0, 1 - A.width), L = v(_.y - x / W.height, 0, 1 - A.height), B = (_.x - E) * W.width, oe = (_.y - L) * W.height;
1842
+ t.cropDragPan.value = { x: B, y: oe };
1843
+ break;
1844
+ }
1845
+ case "nw": {
1846
+ let z = v(_.x + P), x = v(_.y + j), E = _.x + _.width - z, L = _.y + _.height - x;
1847
+ R && (L = E / R, x = _.y + _.height - L, x < 0 && (x = 0, L = _.y + _.height, E = L * R, z = _.x + _.width - E)), E > 0.02 && L > 0.02 && z >= 0 && x >= 0 && (A.x = z, A.y = x, A.width = E, A.height = L);
1848
+ break;
1849
+ }
1850
+ case "ne": {
1851
+ let z = v(_.width + P, 0.02, 1 - _.x), x = _.y + j, E = _.y + _.height - x;
1852
+ R && (E = z / R, x = _.y + _.height - E, x < 0 && (x = 0, E = _.y + _.height, z = E * R)), z > 0.02 && E > 0.02 && x >= 0 && _.x + z <= 1 && (A.y = x, A.width = z, A.height = E);
1853
+ break;
1854
+ }
1855
+ case "sw": {
1856
+ let z = v(_.x + P), x = _.x + _.width - z, E = v(_.height + j, 0.02, 1 - _.y);
1857
+ R && (x = E * R, z = _.x + _.width - x, z < 0 && (z = 0, x = _.x + _.width, E = x / R)), x > 0.02 && E > 0.02 && z >= 0 && _.y + E <= 1 && (A.x = z, A.width = x, A.height = E);
1858
+ break;
1859
+ }
1860
+ case "se": {
1861
+ let z = v(_.width + P, 0.02, 1 - _.x), x = v(_.height + j, 0.02, 1 - _.y);
1862
+ R && (x = z / R, _.y + x > 1 && (x = 1 - _.y, z = x * R)), z > 0.02 && x > 0.02 && _.x + z <= 1 && _.y + x <= 1 && (A.width = z, A.height = x);
1863
+ break;
1864
+ }
1865
+ case "n": {
1866
+ let z = v(_.y + j), x = _.y + _.height - z;
1867
+ if (R) {
1868
+ const E = x * R, L = E - _.width, B = v(_.x - L / 2, 0, 1 - E);
1869
+ E > 0.02 && B >= 0 && B + E <= 1 && (A.x = B, A.width = E);
1870
+ }
1871
+ x > 0.02 && z >= 0 && (A.y = z, A.height = x);
1872
+ break;
1873
+ }
1874
+ case "s": {
1875
+ let z = v(_.height + j, 0.02, 1 - _.y);
1876
+ if (R) {
1877
+ const x = z * R, E = x - _.width, L = v(_.x - E / 2, 0, 1 - x);
1878
+ x > 0.02 && L >= 0 && L + x <= 1 && (A.x = L, A.width = x);
1879
+ }
1880
+ z > 0.02 && _.y + z <= 1 && (A.height = z);
1881
+ break;
1882
+ }
1883
+ case "w": {
1884
+ let z = v(_.x + P), x = _.x + _.width - z;
1885
+ if (R) {
1886
+ const E = x / R, L = E - _.height, B = v(_.y - L / 2, 0, 1 - E);
1887
+ E > 0.02 && B >= 0 && B + E <= 1 && (A.y = B, A.height = E);
1888
+ }
1889
+ x > 0.02 && z >= 0 && (A.x = z, A.width = x);
1890
+ break;
1891
+ }
1892
+ case "e": {
1893
+ let z = v(_.width + P, 0.02, 1 - _.x);
1894
+ if (R) {
1895
+ const x = z / R, E = x - _.height, L = v(_.y - E / 2, 0, 1 - x);
1896
+ x > 0.02 && L >= 0 && L + x <= 1 && (A.y = L, A.height = x);
1897
+ }
1898
+ z > 0.02 && _.x + z <= 1 && (A.width = z);
1899
+ break;
1900
+ }
1901
+ }
1902
+ t.requestRender();
1903
+ }, T = () => {
1904
+ window.removeEventListener("pointermove", H), window.removeEventListener("pointerup", K), p = null;
1905
+ }, K = (D) => {
1906
+ if (s.value === "move") {
1907
+ const W = D.clientX - l.value.x, P = D.clientY - l.value.y, j = n.canvasRect, _ = y.value, A = t.state.crop;
1908
+ A.x = v(_.x - W / j.width, 0, 1 - A.width), A.y = v(_.y - P / j.height, 0, 1 - A.height), t.cropDragPan.value = { x: 0, y: 0 };
1909
+ }
1910
+ s.value && (s.value !== "move" && (c.value = !0), t.updateState(() => {
1911
+ })), s.value = null;
1912
+ try {
1913
+ I.releasePointerCapture(D.pointerId);
1914
+ } catch {
1915
+ }
1916
+ T();
1917
+ };
1918
+ window.addEventListener("pointermove", H), window.addEventListener("pointerup", K), p = T;
1919
+ }
1920
+ ue(() => {
1921
+ p == null || p(), t.cropDragPan.value = { x: 0, y: 0 };
1922
+ });
1923
+ const M = V(() => {
1924
+ const f = t.state.crop;
1925
+ return c.value && !s.value && r.value.width > 60 && r.value.height > 60 && (f.x > 1e-3 || f.y > 1e-3 || f.width < 0.999 || f.height < 0.999);
1926
+ });
1927
+ ne(() => t.state.crop.aspectRatio, () => {
1928
+ c.value = !1;
1929
+ });
1930
+ function k() {
1931
+ const f = t.plugins.value, g = f.findIndex((b) => b.id === t.activePluginId.value);
1932
+ g >= 0 && g < f.length - 1 && t.setActivePlugin(f[g + 1].id);
1933
+ }
1934
+ function v(f, g = 0, b = 1) {
1935
+ return Math.max(g, Math.min(b, f));
1936
+ }
1937
+ return (f, g) => (C(), $("svg", {
1938
+ class: U(["vie-crop-overlay", { "vie-crop-overlay--dragging": s.value }]),
1939
+ role: "application",
1940
+ "aria-label": "Crop region",
1941
+ viewBox: `0 0 ${d.value} ${u.value}`,
1942
+ width: d.value,
1943
+ height: u.value,
1944
+ style: { "touch-action": "none" },
1945
+ onPointerdown: w
1946
+ }, [
1947
+ m("defs", null, [
1948
+ m("mask", { id: e }, [
1949
+ m("rect", {
1950
+ x: "0",
1951
+ y: "0",
1952
+ width: d.value,
1953
+ height: u.value,
1954
+ fill: "white"
1955
+ }, null, 8, Yt),
1956
+ m("rect", {
1957
+ x: r.value.x,
1958
+ y: r.value.y,
1959
+ width: Math.max(0, r.value.width),
1960
+ height: Math.max(0, r.value.height),
1961
+ fill: "black"
1962
+ }, null, 8, Ut)
1963
+ ])
1964
+ ]),
1965
+ m("rect", {
1966
+ x: "0",
1967
+ y: "0",
1968
+ width: d.value,
1969
+ height: u.value,
1970
+ class: "vie-crop-mask",
1971
+ mask: `url(#${e})`
1972
+ }, null, 8, Nt),
1973
+ m("rect", {
1974
+ x: r.value.x,
1975
+ y: r.value.y,
1976
+ width: Math.max(0, r.value.width),
1977
+ height: Math.max(0, r.value.height),
1978
+ class: "vie-crop-border"
1979
+ }, null, 8, Zt),
1980
+ r.value.width > 10 && r.value.height > 10 ? (C(), $("g", Jt, [
1981
+ (C(), $(X, null, N(2, (b) => m("line", {
1982
+ key: "h" + b,
1983
+ x1: r.value.x,
1984
+ y1: r.value.y + r.value.height * (b / 3),
1985
+ x2: r.value.x + r.value.width,
1986
+ y2: r.value.y + r.value.height * (b / 3)
1987
+ }, null, 8, Gt)), 64)),
1988
+ (C(), $(X, null, N(2, (b) => m("line", {
1989
+ key: "v" + b,
1990
+ x1: r.value.x + r.value.width * (b / 3),
1991
+ y1: r.value.y,
1992
+ x2: r.value.x + r.value.width * (b / 3),
1993
+ y2: r.value.y + r.value.height
1994
+ }, null, 8, Qt)), 64))
1995
+ ])) : Z("", !0),
1996
+ m("rect", {
1997
+ x: r.value.x + ae,
1998
+ y: r.value.y + ae,
1999
+ width: Math.max(0, r.value.width - ae * 2),
2000
+ height: Math.max(0, r.value.height - ae * 2),
2001
+ class: "vie-crop-move",
2002
+ "data-handle": "move"
2003
+ }, null, 8, en),
2004
+ (C(!0), $(X, null, N(i.value, (b) => (C(), $("rect", {
2005
+ key: b.id,
2006
+ x: b.x,
2007
+ y: b.y,
2008
+ width: ae,
2009
+ height: ae,
2010
+ class: U(["vie-crop-handle", `vie-crop-handle--${b.id}`]),
2011
+ "data-handle": b.id,
2012
+ rx: "2"
2013
+ }, null, 10, tn))), 128)),
2014
+ (C(!0), $(X, null, N(h.value, (b) => (C(), $("rect", {
2015
+ key: b.id,
2016
+ x: b.x,
2017
+ y: b.y,
2018
+ width: b.w,
2019
+ height: b.h,
2020
+ class: U(["vie-crop-handle", `vie-crop-handle--${b.id}`]),
2021
+ "data-handle": b.id,
2022
+ rx: "2"
2023
+ }, null, 10, nn))), 128)),
2024
+ M.value ? (C(), $("foreignObject", {
2025
+ key: 1,
2026
+ x: r.value.x + (r.value.width - 100) / 2,
2027
+ y: r.value.y + r.value.height - 14,
2028
+ width: "100",
2029
+ height: "36",
2030
+ style: { "pointer-events": "none", overflow: "visible" }
2031
+ }, [
2032
+ m("div", an, [
2033
+ m("button", {
2034
+ class: "vie-crop-confirm-pill",
2035
+ onPointerdown: g[0] || (g[0] = le(() => {
2036
+ }, ["stop"])),
2037
+ onClick: le(k, ["stop"])
2038
+ }, [
2039
+ g[1] || (g[1] = m("svg", {
2040
+ viewBox: "0 0 24 24",
2041
+ width: "14",
2042
+ height: "14",
2043
+ fill: "none",
2044
+ stroke: "currentColor",
2045
+ "stroke-width": "3",
2046
+ "stroke-linecap": "round",
2047
+ "stroke-linejoin": "round"
2048
+ }, [
2049
+ m("polyline", { points: "20 6 9 17 4 12" })
2050
+ ], -1)),
2051
+ m("span", null, q(S(o)("cropApply")), 1)
2052
+ ], 32)
2053
+ ])
2054
+ ], 8, on)) : Z("", !0)
2055
+ ], 42, Xt));
2056
+ }
2057
+ }), cn = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2058
+ <path d="M6 2v4" />
2059
+ <path d="M6 6h12a2 2 0 0 1 2 2v8" />
2060
+ <path d="M18 22v-4" />
2061
+ <path d="M18 18H6a2 2 0 0 1-2-2V8" />
2062
+ </svg>`;
2063
+ function un() {
2064
+ return {
2065
+ id: "crop",
2066
+ icon: cn,
2067
+ labelKey: "crop",
2068
+ controls: qt,
2069
+ overlay: ln
2070
+ };
2071
+ }
2072
+ const dn = [
2073
+ { key: "brightness", labelKey: "brightness", min: -0.25, max: 0.25, base: 0, step: 0.01 },
2074
+ { key: "contrast", labelKey: "contrast", min: -0.25, max: 0.25, base: 0, step: 0.01 },
2075
+ { key: "saturation", labelKey: "saturation", min: -0.25, max: 0.25, base: 0, step: 0.01 },
2076
+ { key: "exposure", labelKey: "exposure", min: -0.25, max: 0.25, base: 0, step: 0.01 },
2077
+ { key: "temperature", labelKey: "temperature", min: -0.25, max: 0.25, base: 0, step: 0.01 },
2078
+ { key: "gamma", labelKey: "gamma", min: 0.2, max: 5, base: 1, step: 0.05 },
2079
+ { key: "clarity", labelKey: "clarity", min: -0.25, max: 0.25, base: 0, step: 0.01 },
2080
+ { key: "vignette", labelKey: "vignette", min: -1, max: 1, base: 0, step: 0.05 }
2081
+ ], hn = { class: "vie-finetune-controls" }, vn = /* @__PURE__ */ Y({
2082
+ __name: "FinetuneControls",
2083
+ setup(a) {
2084
+ const e = G(), n = Q(ee, (o) => o);
2085
+ function t(o, d) {
2086
+ e.updateState((u) => {
2087
+ u.finetune[o] = d;
2088
+ });
2089
+ }
2090
+ return (o, d) => (C(), $("div", hn, [
2091
+ (C(!0), $(X, null, N(S(dn), (u) => (C(), re(ve, {
2092
+ key: u.key,
2093
+ modelValue: S(e).state.finetune[u.key],
2094
+ min: u.min,
2095
+ max: u.max,
2096
+ step: u.step,
2097
+ base: u.base,
2098
+ label: S(n)(u.labelKey),
2099
+ format: u.key === "gamma" ? "number" : "percent",
2100
+ "onUpdate:modelValue": (r) => t(u.key, r)
2101
+ }, null, 8, ["modelValue", "min", "max", "step", "base", "label", "format", "onUpdate:modelValue"]))), 128))
2102
+ ]));
2103
+ }
2104
+ }), pn = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2105
+ <line x1="4" y1="21" x2="4" y2="14" />
2106
+ <line x1="4" y1="10" x2="4" y2="3" />
2107
+ <line x1="12" y1="21" x2="12" y2="12" />
2108
+ <line x1="12" y1="8" x2="12" y2="3" />
2109
+ <line x1="20" y1="21" x2="20" y2="16" />
2110
+ <line x1="20" y1="12" x2="20" y2="3" />
2111
+ <line x1="1" y1="14" x2="7" y2="14" />
2112
+ <line x1="9" y1="8" x2="15" y2="8" />
2113
+ <line x1="17" y1="16" x2="23" y2="16" />
2114
+ </svg>`;
2115
+ function fn() {
2116
+ return {
2117
+ id: "finetune",
2118
+ icon: pn,
2119
+ labelKey: "finetune",
2120
+ controls: vn
2121
+ };
2122
+ }
2123
+ const pe = [
2124
+ {
2125
+ id: "chrome",
2126
+ labelKey: "chrome",
2127
+ matrix: [
2128
+ 1.2,
2129
+ 0.1,
2130
+ 0.1,
2131
+ 0,
2132
+ -0.05,
2133
+ 0.05,
2134
+ 1.1,
2135
+ 0.05,
2136
+ 0,
2137
+ -0.02,
2138
+ 0.05,
2139
+ 0.1,
2140
+ 1.2,
2141
+ 0,
2142
+ -0.05,
2143
+ 0,
2144
+ 0,
2145
+ 0,
2146
+ 1,
2147
+ 0
2148
+ ]
2149
+ },
2150
+ {
2151
+ id: "fade",
2152
+ labelKey: "fade",
2153
+ matrix: [
2154
+ 1,
2155
+ 0.02,
2156
+ 0.04,
2157
+ 0,
2158
+ 0.06,
2159
+ 0.02,
2160
+ 0.96,
2161
+ 0.04,
2162
+ 0,
2163
+ 0.06,
2164
+ 0.04,
2165
+ 0.04,
2166
+ 0.92,
2167
+ 0,
2168
+ 0.08,
2169
+ 0,
2170
+ 0,
2171
+ 0,
2172
+ 1,
2173
+ 0
2174
+ ]
2175
+ },
2176
+ {
2177
+ id: "pastel",
2178
+ labelKey: "pastel",
2179
+ matrix: [
2180
+ 0.9,
2181
+ 0.1,
2182
+ 0.05,
2183
+ 0,
2184
+ 0.08,
2185
+ 0.05,
2186
+ 0.9,
2187
+ 0.1,
2188
+ 0,
2189
+ 0.08,
2190
+ 0.1,
2191
+ 0.05,
2192
+ 0.85,
2193
+ 0,
2194
+ 0.1,
2195
+ 0,
2196
+ 0,
2197
+ 0,
2198
+ 1,
2199
+ 0
2200
+ ]
2201
+ },
2202
+ {
2203
+ id: "cold",
2204
+ labelKey: "cold",
2205
+ matrix: [
2206
+ 0.9,
2207
+ 0,
2208
+ 0.1,
2209
+ 0,
2210
+ -0.02,
2211
+ 0,
2212
+ 0.95,
2213
+ 0.1,
2214
+ 0,
2215
+ 0,
2216
+ 0,
2217
+ 0.1,
2218
+ 1.1,
2219
+ 0,
2220
+ 0.03,
2221
+ 0,
2222
+ 0,
2223
+ 0,
2224
+ 1,
2225
+ 0
2226
+ ]
2227
+ },
2228
+ {
2229
+ id: "warm",
2230
+ labelKey: "warm",
2231
+ matrix: [
2232
+ 1.1,
2233
+ 0.1,
2234
+ 0,
2235
+ 0,
2236
+ 0.03,
2237
+ 0,
2238
+ 1,
2239
+ 0.05,
2240
+ 0,
2241
+ 0.01,
2242
+ 0,
2243
+ 0,
2244
+ 0.9,
2245
+ 0,
2246
+ -0.02,
2247
+ 0,
2248
+ 0,
2249
+ 0,
2250
+ 1,
2251
+ 0
2252
+ ]
2253
+ },
2254
+ {
2255
+ id: "monoDefault",
2256
+ labelKey: "mono",
2257
+ matrix: [
2258
+ 0.2126,
2259
+ 0.7152,
2260
+ 0.0722,
2261
+ 0,
2262
+ 0,
2263
+ 0.2126,
2264
+ 0.7152,
2265
+ 0.0722,
2266
+ 0,
2267
+ 0,
2268
+ 0.2126,
2269
+ 0.7152,
2270
+ 0.0722,
2271
+ 0,
2272
+ 0,
2273
+ 0,
2274
+ 0,
2275
+ 0,
2276
+ 1,
2277
+ 0
2278
+ ]
2279
+ },
2280
+ {
2281
+ id: "monoNoir",
2282
+ labelKey: "noir",
2283
+ matrix: [
2284
+ 0.3,
2285
+ 0.8,
2286
+ 0.1,
2287
+ 0,
2288
+ -0.08,
2289
+ 0.3,
2290
+ 0.8,
2291
+ 0.1,
2292
+ 0,
2293
+ -0.08,
2294
+ 0.3,
2295
+ 0.8,
2296
+ 0.1,
2297
+ 0,
2298
+ -0.08,
2299
+ 0,
2300
+ 0,
2301
+ 0,
2302
+ 1,
2303
+ 0
2304
+ ]
2305
+ },
2306
+ {
2307
+ id: "monoWash",
2308
+ labelKey: "wash",
2309
+ matrix: [
2310
+ 0.2126,
2311
+ 0.7152,
2312
+ 0.0722,
2313
+ 0,
2314
+ 0.06,
2315
+ 0.2126,
2316
+ 0.7152,
2317
+ 0.0722,
2318
+ 0,
2319
+ 0.06,
2320
+ 0.2126,
2321
+ 0.7152,
2322
+ 0.0722,
2323
+ 0,
2324
+ 0.06,
2325
+ 0,
2326
+ 0,
2327
+ 0,
2328
+ 1,
2329
+ 0
2330
+ ]
2331
+ },
2332
+ {
2333
+ id: "monoStark",
2334
+ labelKey: "stark",
2335
+ matrix: [
2336
+ 0.35,
2337
+ 1,
2338
+ 0.15,
2339
+ 0,
2340
+ -0.15,
2341
+ 0.35,
2342
+ 1,
2343
+ 0.15,
2344
+ 0,
2345
+ -0.15,
2346
+ 0.35,
2347
+ 1,
2348
+ 0.15,
2349
+ 0,
2350
+ -0.15,
2351
+ 0,
2352
+ 0,
2353
+ 0,
2354
+ 1,
2355
+ 0
2356
+ ]
2357
+ },
2358
+ {
2359
+ id: "sepiaDefault",
2360
+ labelKey: "sepia",
2361
+ matrix: [
2362
+ 0.393,
2363
+ 0.769,
2364
+ 0.189,
2365
+ 0,
2366
+ 0,
2367
+ 0.349,
2368
+ 0.686,
2369
+ 0.168,
2370
+ 0,
2371
+ 0,
2372
+ 0.272,
2373
+ 0.534,
2374
+ 0.131,
2375
+ 0,
2376
+ 0,
2377
+ 0,
2378
+ 0,
2379
+ 0,
2380
+ 1,
2381
+ 0
2382
+ ]
2383
+ },
2384
+ {
2385
+ id: "sepiaRust",
2386
+ labelKey: "rust",
2387
+ matrix: [
2388
+ 0.45,
2389
+ 0.75,
2390
+ 0.15,
2391
+ 0,
2392
+ 0.04,
2393
+ 0.3,
2394
+ 0.6,
2395
+ 0.15,
2396
+ 0,
2397
+ -0.01,
2398
+ 0.2,
2399
+ 0.4,
2400
+ 0.15,
2401
+ 0,
2402
+ -0.04,
2403
+ 0,
2404
+ 0,
2405
+ 0,
2406
+ 1,
2407
+ 0
2408
+ ]
2409
+ },
2410
+ {
2411
+ id: "sepiaBlues",
2412
+ labelKey: "blues",
2413
+ matrix: [
2414
+ 0.2126,
2415
+ 0.7152,
2416
+ 0.0722,
2417
+ 0,
2418
+ -0.04,
2419
+ 0.2126,
2420
+ 0.7152,
2421
+ 0.0722,
2422
+ 0,
2423
+ 0,
2424
+ 0.2126,
2425
+ 0.7152,
2426
+ 0.0722,
2427
+ 0,
2428
+ 0.08,
2429
+ 0,
2430
+ 0,
2431
+ 0,
2432
+ 1,
2433
+ 0
2434
+ ]
2435
+ },
2436
+ {
2437
+ id: "sepiaColor",
2438
+ labelKey: "color",
2439
+ matrix: [
2440
+ 0.4,
2441
+ 0.6,
2442
+ 0.1,
2443
+ 0,
2444
+ 0.02,
2445
+ 0.25,
2446
+ 0.7,
2447
+ 0.15,
2448
+ 0,
2449
+ 0.01,
2450
+ 0.2,
2451
+ 0.5,
2452
+ 0.4,
2453
+ 0,
2454
+ 0.01,
2455
+ 0,
2456
+ 0,
2457
+ 0,
2458
+ 1,
2459
+ 0
2460
+ ]
2461
+ }
2462
+ ], mn = { class: "vie-filter-controls" }, gn = { class: "vie-filter-strip" }, yn = { class: "vie-filter-thumb__label" }, wn = ["onClick"], kn = { class: "vie-filter-thumb__label" }, bn = /* @__PURE__ */ Y({
2463
+ __name: "FilterControls",
2464
+ setup(a) {
2465
+ const e = G(), n = Q(ee, (p) => p), t = F(null), o = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Set();
2466
+ let u = null;
2467
+ function r(p, w) {
2468
+ w && (o.set(p, w), u == null || u.observe(w));
2469
+ }
2470
+ function i(p) {
2471
+ e.updateState((w) => {
2472
+ p ? (w.filter.id = p.id, w.filter.matrix = [...p.matrix]) : (w.filter.id = null, w.filter.matrix = void 0);
2473
+ });
2474
+ }
2475
+ function h(p) {
2476
+ e.updateState((w) => {
2477
+ w.filter.intensity = p;
2478
+ });
2479
+ }
2480
+ function s(p, w) {
2481
+ const M = e.sourceImage.value;
2482
+ if (!M) return;
2483
+ const k = 96, v = p.getContext("2d");
2484
+ v.drawImage(M, 0, 0, k, k);
2485
+ const f = v.getImageData(0, 0, k, k);
2486
+ Ce(f, w.matrix), v.putImageData(f, 0, 0), d.add(w.id);
2487
+ }
2488
+ function l() {
2489
+ const p = e.sourceImage.value;
2490
+ if (!p || !t.value) return;
2491
+ t.value.getContext("2d").drawImage(p, 0, 0, 96, 96);
2492
+ }
2493
+ function y() {
2494
+ u = new IntersectionObserver((p) => {
2495
+ for (const w of p) {
2496
+ if (!w.isIntersecting) continue;
2497
+ const M = w.target, k = pe.find((v) => o.get(v.id) === M);
2498
+ k && !d.has(k.id) && s(M, k);
2499
+ }
2500
+ }, { threshold: 0.1 });
2501
+ for (const p of o.values())
2502
+ u.observe(p);
2503
+ }
2504
+ function c() {
2505
+ d.clear(), l();
2506
+ for (const p of pe) {
2507
+ const w = o.get(p.id);
2508
+ w && (u == null || u.unobserve(w));
2509
+ }
2510
+ for (const p of o.values())
2511
+ u == null || u.observe(p);
2512
+ }
2513
+ return ne(() => e.sourceImage.value, () => {
2514
+ setTimeout(c, 50);
2515
+ }), ce(() => {
2516
+ y(), setTimeout(() => {
2517
+ l();
2518
+ }, 50);
2519
+ }), Ze(() => {
2520
+ u == null || u.disconnect(), u = null;
2521
+ }), (p, w) => (C(), $("div", mn, [
2522
+ m("div", gn, [
2523
+ m("button", {
2524
+ class: U(["vie-filter-thumb", { "vie-filter-thumb--active": !S(e).state.filter.id }]),
2525
+ onClick: w[0] || (w[0] = (M) => i(null))
2526
+ }, [
2527
+ m("canvas", {
2528
+ ref_key: "originalThumbRef",
2529
+ ref: t,
2530
+ width: "96",
2531
+ height: "96",
2532
+ class: "vie-filter-thumb__canvas"
2533
+ }, null, 512),
2534
+ m("span", yn, q(S(n)("original")), 1)
2535
+ ], 2),
2536
+ (C(!0), $(X, null, N(S(pe), (M) => (C(), $("button", {
2537
+ key: M.id,
2538
+ class: U(["vie-filter-thumb", { "vie-filter-thumb--active": S(e).state.filter.id === M.id }]),
2539
+ onClick: (k) => i(M)
2540
+ }, [
2541
+ m("canvas", {
2542
+ ref_for: !0,
2543
+ ref: (k) => r(M.id, k),
2544
+ width: "96",
2545
+ height: "96",
2546
+ class: "vie-filter-thumb__canvas"
2547
+ }, null, 512),
2548
+ m("span", kn, q(S(n)(M.labelKey) || M.labelKey), 1)
2549
+ ], 10, wn))), 128))
2550
+ ]),
2551
+ S(e).state.filter.id ? (C(), re(ve, {
2552
+ key: 0,
2553
+ modelValue: S(e).state.filter.intensity,
2554
+ min: 0,
2555
+ max: 1,
2556
+ step: 0.01,
2557
+ base: 1,
2558
+ label: S(n)("intensity"),
2559
+ format: "percent",
2560
+ "onUpdate:modelValue": h
2561
+ }, null, 8, ["modelValue", "label"])) : Z("", !0)
2562
+ ]));
2563
+ }
2564
+ }), _n = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2565
+ <path d="M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" />
2566
+ <path d="M12 20a8 8 0 1 0 0-16" fill="currentColor" opacity="0.3" />
2567
+ <path d="M12 4v16" />
2568
+ </svg>`;
2569
+ function xn() {
2570
+ return {
2571
+ id: "filter",
2572
+ icon: _n,
2573
+ labelKey: "filter",
2574
+ controls: bn
2575
+ };
2576
+ }
2577
+ const fe = [
2578
+ {
2579
+ id: "emoji",
2580
+ labelKey: "emoji",
2581
+ stickers: [
2582
+ "😀",
2583
+ "😂",
2584
+ "❤️",
2585
+ "🎉",
2586
+ "👍",
2587
+ "⭐",
2588
+ "🔥",
2589
+ "💯",
2590
+ "🎨",
2591
+ "📸",
2592
+ "🎵",
2593
+ "🌟",
2594
+ "✅",
2595
+ "❌",
2596
+ "⚡",
2597
+ "🎯",
2598
+ "💡",
2599
+ "🏆",
2600
+ "🎲",
2601
+ "🎪",
2602
+ "🌈",
2603
+ "🦋",
2604
+ "🍀",
2605
+ "💎"
2606
+ ]
2607
+ },
2608
+ {
2609
+ id: "shapes",
2610
+ labelKey: "shapes",
2611
+ stickers: [
2612
+ "⬛",
2613
+ "⬜",
2614
+ "🔴",
2615
+ "🔵",
2616
+ "🟢",
2617
+ "🟡",
2618
+ "🟠",
2619
+ "🟣",
2620
+ "▶️",
2621
+ "◀️",
2622
+ "🔺",
2623
+ "🔻",
2624
+ "💠",
2625
+ "🔶",
2626
+ "🔷",
2627
+ "♦️"
2628
+ ]
2629
+ }
2630
+ ], Pe = /* @__PURE__ */ new WeakMap();
2631
+ function je(a) {
2632
+ let e = Pe.get(a);
2633
+ return e || (e = F(null), Pe.set(a, e)), e;
2634
+ }
2635
+ const Cn = { class: "vie-sticker-controls" }, Mn = { class: "vie-sticker-tabs" }, Sn = ["onClick"], $n = { class: "vie-sticker-grid" }, Rn = ["onClick"], In = /* @__PURE__ */ Y({
2636
+ __name: "StickerControls",
2637
+ setup(a) {
2638
+ var i;
2639
+ const e = G(), n = Q(ee, (h) => h), t = je(e.state), o = F(((i = fe[0]) == null ? void 0 : i.id) || "emoji"), d = V(() => {
2640
+ const h = fe.find((s) => s.id === o.value);
2641
+ return (h == null ? void 0 : h.stickers) || [];
2642
+ });
2643
+ function u(h) {
2644
+ const s = `sticker-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, l = e.state.stickers.length % 5 * 0.03;
2645
+ e.updateState((y) => {
2646
+ y.stickers.push({
2647
+ id: s,
2648
+ src: h,
2649
+ x: 0.35 + l,
2650
+ y: 0.35 + l,
2651
+ width: 0.15,
2652
+ height: 0.15,
2653
+ rotation: 0,
2654
+ flipX: !1,
2655
+ flipY: !1,
2656
+ opacity: 1
2657
+ });
2658
+ }), t.value = s;
2659
+ }
2660
+ function r() {
2661
+ if (!t.value) return;
2662
+ const h = t.value;
2663
+ e.updateState((s) => {
2664
+ const l = s.stickers.findIndex((y) => y.id === h);
2665
+ l >= 0 && s.stickers.splice(l, 1);
2666
+ }), t.value = null;
2667
+ }
2668
+ return (h, s) => (C(), $("div", Cn, [
2669
+ m("div", Mn, [
2670
+ (C(!0), $(X, null, N(S(fe), (l) => (C(), $("button", {
2671
+ key: l.id,
2672
+ class: U(["vie-sticker-tab", { "vie-sticker-tab--active": o.value === l.id }]),
2673
+ onClick: (y) => o.value = l.id
2674
+ }, q(S(n)(l.labelKey) || l.labelKey), 11, Sn))), 128)),
2675
+ S(t) ? (C(), $("button", {
2676
+ key: 0,
2677
+ class: "vie-sticker-tab vie-sticker-tab--delete",
2678
+ onClick: r
2679
+ }, q(S(n)("delete") || "Delete"), 1)) : Z("", !0)
2680
+ ]),
2681
+ m("div", $n, [
2682
+ (C(!0), $(X, null, N(d.value, (l) => (C(), $("button", {
2683
+ key: l,
2684
+ class: "vie-sticker-item",
2685
+ onClick: (y) => u(l)
2686
+ }, q(l), 9, Rn))), 128))
2687
+ ])
2688
+ ]));
2689
+ }
2690
+ }), zn = ["viewBox", "width", "height"], Pn = ["x", "y", "width", "height", "data-sticker-id"], En = ["x", "y", "width", "height"], Tn = ["x", "y", "data-handle"], Wn = ["x1", "y1", "x2", "y2"], Kn = ["cx", "cy"], me = 10, Ee = 20, Te = 6, Dn = /* @__PURE__ */ Y({
2691
+ __name: "StickerOverlay",
2692
+ props: {
2693
+ canvasRect: {},
2694
+ wrapperSize: {}
2695
+ },
2696
+ setup(a) {
2697
+ const e = a, n = G(), t = F(null), o = je(n.state), d = V(() => {
2698
+ const v = e.canvasRect;
2699
+ return n.state.stickers.map((f) => ({
2700
+ id: f.id,
2701
+ x: v.x + f.x * v.width,
2702
+ y: v.y + f.y * v.height,
2703
+ w: f.width * v.width,
2704
+ h: f.height * v.height
2705
+ }));
2706
+ }), u = V(() => o.value && d.value.find((v) => v.id === o.value) || null), r = V(() => {
2707
+ if (!u.value) return [];
2708
+ const v = u.value, g = me / 2;
2709
+ return [
2710
+ { id: "nw", x: v.x - g, y: v.y - g },
2711
+ { id: "ne", x: v.x + v.w - g, y: v.y - g },
2712
+ { id: "sw", x: v.x - g, y: v.y + v.h - g },
2713
+ { id: "se", x: v.x + v.w - g, y: v.y + v.h - g }
2714
+ ];
2715
+ }), i = F(null), h = F(null), s = F({ x: 0, y: 0 }), l = F({ x: 0, y: 0, width: 0, height: 0, rotation: 0 });
2716
+ function y(v) {
2717
+ var I;
2718
+ const f = v.target, g = f.getAttribute("data-handle");
2719
+ if (g === "rotate" && o.value) {
2720
+ v.preventDefault(), c(v, "rotate", g);
2721
+ return;
2722
+ }
2723
+ if (g && ["nw", "ne", "sw", "se"].includes(g) && o.value) {
2724
+ v.preventDefault(), c(v, "resize", g);
2725
+ return;
2726
+ }
2727
+ const b = f.getAttribute("data-sticker-id");
2728
+ if (b) {
2729
+ v.preventDefault(), o.value = b, c(v, "move", null), (I = t.value) == null || I.focus();
2730
+ return;
2731
+ }
2732
+ o.value = null;
2733
+ }
2734
+ function c(v, f, g) {
2735
+ i.value = f, h.value = g, s.value = { x: v.clientX, y: v.clientY };
2736
+ const b = n.state.stickers.find((I) => I.id === o.value);
2737
+ b && (l.value = {
2738
+ x: b.x,
2739
+ y: b.y,
2740
+ width: b.width,
2741
+ height: b.height,
2742
+ rotation: b.rotation
2743
+ }), window.addEventListener("pointermove", p), window.addEventListener("pointerup", w);
2744
+ }
2745
+ function p(v) {
2746
+ if (!i.value || !o.value) return;
2747
+ const f = e.canvasRect;
2748
+ if (f.width === 0 || f.height === 0) return;
2749
+ const g = (v.clientX - s.value.x) / f.width, b = (v.clientY - s.value.y) / f.height, I = l.value, H = n.state.stickers.find((T) => T.id === o.value);
2750
+ if (H) {
2751
+ switch (i.value) {
2752
+ case "move": {
2753
+ H.x = k(I.x + g, 0, 1 - H.width), H.y = k(I.y + b, 0, 1 - H.height);
2754
+ break;
2755
+ }
2756
+ case "resize": {
2757
+ switch (h.value) {
2758
+ case "se": {
2759
+ H.width = k(I.width + g, 0.03, 1 - I.x), H.height = k(I.height + b, 0.03, 1 - I.y);
2760
+ break;
2761
+ }
2762
+ case "ne": {
2763
+ const K = k(I.width + g, 0.03, 1 - I.x), D = k(I.height - b, 0.03, I.y + I.height), W = I.y + I.height - D;
2764
+ H.width = K, H.height = D, H.y = W;
2765
+ break;
2766
+ }
2767
+ case "sw": {
2768
+ const K = k(I.width - g, 0.03, I.x + I.width), D = k(I.height + b, 0.03, 1 - I.y), W = I.x + I.width - K;
2769
+ H.width = K, H.height = D, H.x = W;
2770
+ break;
2771
+ }
2772
+ case "nw": {
2773
+ const K = k(I.width - g, 0.03, I.x + I.width), D = k(I.height - b, 0.03, I.y + I.height), W = I.x + I.width - K, P = I.y + I.height - D;
2774
+ H.width = K, H.height = D, H.x = W, H.y = P;
2775
+ break;
2776
+ }
2777
+ }
2778
+ break;
2779
+ }
2780
+ case "rotate": {
2781
+ const T = f.x + H.x * f.width + H.width * f.width / 2, K = f.y + H.y * f.height + H.height * f.height / 2, D = Math.atan2(v.clientX - T, -(v.clientY - K));
2782
+ H.rotation = D;
2783
+ break;
2784
+ }
2785
+ }
2786
+ n.requestRender();
2787
+ }
2788
+ }
2789
+ function w() {
2790
+ i.value && n.updateState(() => {
2791
+ }), i.value = null, h.value = null, window.removeEventListener("pointermove", p), window.removeEventListener("pointerup", w);
2792
+ }
2793
+ function M(v) {
2794
+ if ((v.key === "Delete" || v.key === "Backspace") && o.value) {
2795
+ v.preventDefault();
2796
+ const f = o.value;
2797
+ n.updateState((g) => {
2798
+ const b = g.stickers.findIndex((I) => I.id === f);
2799
+ b >= 0 && g.stickers.splice(b, 1);
2800
+ }), o.value = null;
2801
+ }
2802
+ }
2803
+ function k(v, f, g) {
2804
+ return Math.max(f, Math.min(g, v));
2805
+ }
2806
+ return (v, f) => (C(), $("svg", {
2807
+ ref_key: "svgRef",
2808
+ ref: t,
2809
+ class: "vie-sticker-overlay",
2810
+ viewBox: `0 0 ${a.wrapperSize.width} ${a.wrapperSize.height}`,
2811
+ width: a.wrapperSize.width,
2812
+ height: a.wrapperSize.height,
2813
+ onPointerdown: y,
2814
+ onKeydown: M,
2815
+ tabindex: "0"
2816
+ }, [
2817
+ (C(!0), $(X, null, N(d.value, (g) => (C(), $("rect", {
2818
+ key: g.id,
2819
+ x: g.x,
2820
+ y: g.y,
2821
+ width: g.w,
2822
+ height: g.h,
2823
+ fill: "transparent",
2824
+ class: "vie-sticker-hitarea",
2825
+ "data-sticker-id": g.id
2826
+ }, null, 8, Pn))), 128)),
2827
+ u.value ? (C(), $(X, { key: 0 }, [
2828
+ m("rect", {
2829
+ x: u.value.x,
2830
+ y: u.value.y,
2831
+ width: u.value.w,
2832
+ height: u.value.h,
2833
+ class: "vie-sticker-selection"
2834
+ }, null, 8, En),
2835
+ (C(!0), $(X, null, N(r.value, (g) => (C(), $("rect", {
2836
+ key: g.id,
2837
+ x: g.x,
2838
+ y: g.y,
2839
+ width: me,
2840
+ height: me,
2841
+ class: "vie-sticker-handle",
2842
+ "data-handle": g.id
2843
+ }, null, 8, Tn))), 128)),
2844
+ m("line", {
2845
+ x1: u.value.x + u.value.w / 2,
2846
+ y1: u.value.y - Ee,
2847
+ x2: u.value.x + u.value.w / 2,
2848
+ y2: u.value.y,
2849
+ class: "vie-sticker-rotate-line"
2850
+ }, null, 8, Wn),
2851
+ m("circle", {
2852
+ cx: u.value.x + u.value.w / 2,
2853
+ cy: u.value.y - Ee - Te,
2854
+ r: Te,
2855
+ class: "vie-sticker-rotate-handle",
2856
+ "data-handle": "rotate"
2857
+ }, null, 8, Kn)
2858
+ ], 64)) : Z("", !0)
2859
+ ], 40, zn));
2860
+ }
2861
+ }), An = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2862
+ <circle cx="12" cy="12" r="10" />
2863
+ <path d="M8 14s1.5 2 4 2 4-2 4-2" />
2864
+ <line x1="9" y1="9" x2="9.01" y2="9" />
2865
+ <line x1="15" y1="9" x2="15.01" y2="9" />
2866
+ </svg>`;
2867
+ function Ln() {
2868
+ return {
2869
+ id: "sticker",
2870
+ icon: An,
2871
+ labelKey: "sticker",
2872
+ controls: In,
2873
+ overlay: Dn
2874
+ };
2875
+ }
2876
+ const Fn = [
2877
+ { id: "solidSharp", labelKey: "solidSharp" },
2878
+ { id: "solidRound", labelKey: "solidRound" },
2879
+ { id: "lineSingle", labelKey: "lineSingle" },
2880
+ { id: "lineMultiple", labelKey: "lineMultiple" },
2881
+ { id: "hook", labelKey: "hook" },
2882
+ { id: "polaroid", labelKey: "polaroid" },
2883
+ { id: "edgeSeparate", labelKey: "edgeSeparate" },
2884
+ { id: "edgeCross", labelKey: "edgeCross" },
2885
+ { id: "edgeOverlap", labelKey: "edgeOverlap" }
2886
+ ], Hn = [
2887
+ [1, 1, 1, 1],
2888
+ // White
2889
+ [0, 0, 0, 1],
2890
+ // Black
2891
+ [0.85, 0.75, 0.6, 1],
2892
+ // Cream
2893
+ [0.6, 0.4, 0.2, 1],
2894
+ // Brown
2895
+ [0.2, 0.4, 0.6, 1],
2896
+ // Navy
2897
+ [0.8, 0.2, 0.2, 1]
2898
+ // Red
2899
+ ], Vn = { class: "vie-frame-controls" }, jn = { class: "vie-frame-strip" }, On = { class: "vie-frame-style__label" }, Bn = ["onClick"], qn = { class: "vie-frame-style__label" }, Xn = { class: "vie-frame-colors" }, Yn = { class: "vie-frame-colors__label" }, Un = { class: "vie-frame-colors__swatches" }, Nn = ["onClick"], Zn = /* @__PURE__ */ Y({
2900
+ __name: "FrameControls",
2901
+ setup(a) {
2902
+ const e = G(), n = Q(ee, (i) => i);
2903
+ function t(i) {
2904
+ e.updateState((h) => {
2905
+ h.frame.style = i;
2906
+ });
2907
+ }
2908
+ function o(i) {
2909
+ e.updateState((h) => {
2910
+ h.frame.size = i;
2911
+ });
2912
+ }
2913
+ function d(i) {
2914
+ e.updateState((h) => {
2915
+ h.frame.color = [...i];
2916
+ });
2917
+ }
2918
+ function u(i) {
2919
+ const h = e.state.frame.color;
2920
+ return h[0] === i[0] && h[1] === i[1] && h[2] === i[2] && h[3] === i[3];
2921
+ }
2922
+ function r(i) {
2923
+ return `rgba(${Math.round(i[0] * 255)}, ${Math.round(i[1] * 255)}, ${Math.round(i[2] * 255)}, ${i[3]})`;
2924
+ }
2925
+ return (i, h) => (C(), $("div", Vn, [
2926
+ m("div", jn, [
2927
+ m("button", {
2928
+ class: U(["vie-frame-style", { "vie-frame-style--active": !S(e).state.frame.style }]),
2929
+ onClick: h[0] || (h[0] = (s) => t(null))
2930
+ }, [
2931
+ m("span", On, q(S(n)("none")), 1)
2932
+ ], 2),
2933
+ (C(!0), $(X, null, N(S(Fn), (s) => (C(), $("button", {
2934
+ key: s.id,
2935
+ class: U(["vie-frame-style", { "vie-frame-style--active": S(e).state.frame.style === s.id }]),
2936
+ onClick: (l) => t(s.id)
2937
+ }, [
2938
+ m("span", qn, q(S(n)(s.labelKey)), 1)
2939
+ ], 10, Bn))), 128))
2940
+ ]),
2941
+ S(e).state.frame.style ? (C(), $(X, { key: 0 }, [
2942
+ O(ve, {
2943
+ modelValue: S(e).state.frame.size,
2944
+ min: 5e-3,
2945
+ max: 0.15,
2946
+ step: 5e-3,
2947
+ base: 0.025,
2948
+ label: S(n)("frameSize"),
2949
+ format: "percent",
2950
+ "onUpdate:modelValue": o
2951
+ }, null, 8, ["modelValue", "label"]),
2952
+ m("div", Xn, [
2953
+ m("span", Yn, q(S(n)("frameColor")), 1),
2954
+ m("div", Un, [
2955
+ (C(!0), $(X, null, N(S(Hn), (s, l) => (C(), $("button", {
2956
+ key: l,
2957
+ class: U(["vie-frame-color-swatch", { "vie-frame-color-swatch--active": u(s) }]),
2958
+ style: se({ backgroundColor: r(s) }),
2959
+ onClick: (y) => d(s)
2960
+ }, null, 14, Nn))), 128))
2961
+ ])
2962
+ ])
2963
+ ], 64)) : Z("", !0)
2964
+ ]));
2965
+ }
2966
+ }), Jn = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2967
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
2968
+ <rect x="7" y="7" width="10" height="10" />
2969
+ </svg>`;
2970
+ function Gn() {
2971
+ return {
2972
+ id: "frame",
2973
+ icon: Jn,
2974
+ labelKey: "frame",
2975
+ controls: Zn
2976
+ };
2977
+ }
2978
+ const Qn = { class: "vie-fill-controls" }, ei = { class: "vie-fill-strip" }, ti = ["title", "onClick"], ni = /* @__PURE__ */ Y({
2979
+ __name: "FillControls",
2980
+ setup(a) {
2981
+ const e = G(), n = Q(ee, (r) => r), t = [
2982
+ [0, 0, 0, 0],
2983
+ // Transparent
2984
+ [1, 1, 1, 1],
2985
+ // White
2986
+ [0.8, 0.8, 0.8, 1],
2987
+ // Light gray
2988
+ [0.2, 0.2, 0.2, 1],
2989
+ // Dark gray
2990
+ [0, 0, 0, 1],
2991
+ // Black
2992
+ [0.1, 0.14, 0.49, 1],
2993
+ // Dark navy
2994
+ [0.13, 0.59, 0.95, 1],
2995
+ // Blue
2996
+ [0, 0.74, 0.83, 1],
2997
+ // Cyan
2998
+ [0, 0.59, 0.53, 1],
2999
+ // Teal
3000
+ [0.3, 0.69, 0.31, 1],
3001
+ // Green
3002
+ [0.55, 0.76, 0.29, 1],
3003
+ // Light green
3004
+ [1, 0.92, 0.23, 1],
3005
+ // Yellow
3006
+ [1, 0.6, 0, 1],
3007
+ // Orange
3008
+ [1, 0.34, 0.13, 1],
3009
+ // Deep orange
3010
+ [0.96, 0.26, 0.21, 1],
3011
+ // Red
3012
+ [0.91, 0.12, 0.39, 1],
3013
+ // Pink
3014
+ [0.61, 0.15, 0.69, 1]
3015
+ // Purple
3016
+ ];
3017
+ function o(r) {
3018
+ e.updateState((i) => {
3019
+ i.backgroundColor = [...r];
3020
+ });
3021
+ }
3022
+ function d(r) {
3023
+ const i = e.state.backgroundColor;
3024
+ return i[0] === r[0] && i[1] === r[1] && i[2] === r[2] && i[3] === r[3];
3025
+ }
3026
+ function u(r) {
3027
+ return `rgba(${Math.round(r[0] * 255)}, ${Math.round(r[1] * 255)}, ${Math.round(r[2] * 255)}, ${r[3]})`;
3028
+ }
3029
+ return (r, i) => (C(), $("div", Qn, [
3030
+ m("div", ei, [
3031
+ (C(), $(X, null, N(t, (h, s) => m("button", {
3032
+ key: s,
3033
+ class: U(["vie-fill-swatch", {
3034
+ "vie-fill-swatch--active": d(h),
3035
+ "vie-fill-swatch--transparent": h[3] === 0
3036
+ }]),
3037
+ style: se(h[3] > 0 ? { backgroundColor: u(h) } : void 0),
3038
+ title: s === 0 ? S(n)("transparent") : void 0,
3039
+ onClick: (l) => o(h)
3040
+ }, null, 14, ti)), 64))
3041
+ ])
3042
+ ]));
3043
+ }
3044
+ }), ii = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3045
+ <path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z" />
3046
+ </svg>`;
3047
+ function oi() {
3048
+ return {
3049
+ id: "fill",
3050
+ icon: ii,
3051
+ labelKey: "fill",
3052
+ controls: ni
3053
+ };
3054
+ }
3055
+ const ai = { class: "vie-resize-controls" }, si = { class: "vie-resize-dimensions" }, ri = { class: "vie-resize-input" }, li = { class: "vie-resize-input__label" }, ci = { class: "vie-resize-input__field-wrapper" }, ui = ["value"], di = ["title"], hi = {
3056
+ viewBox: "0 0 24 24",
3057
+ width: "16",
3058
+ height: "16",
3059
+ fill: "none",
3060
+ stroke: "currentColor",
3061
+ "stroke-width": "2"
3062
+ }, vi = {
3063
+ key: 0,
3064
+ d: "M7 11V7a5 5 0 0 1 10 0v4"
3065
+ }, pi = {
3066
+ key: 1,
3067
+ d: "M7 11V7a5 5 0 0 1 9.9-1"
3068
+ }, fi = { class: "vie-resize-input" }, mi = { class: "vie-resize-input__label" }, gi = { class: "vie-resize-input__field-wrapper" }, yi = ["value"], wi = /* @__PURE__ */ Y({
3069
+ __name: "ResizeControls",
3070
+ setup(a) {
3071
+ const e = G(), n = Q(ee, (h) => h), t = F(!0), o = V(() => {
3072
+ const h = e.sourceImage.value;
3073
+ if (!h) return 1;
3074
+ const s = e.state.crop;
3075
+ return h.naturalWidth * s.width / (h.naturalHeight * s.height);
3076
+ }), d = V(() => {
3077
+ if (e.state.resize.width) return e.state.resize.width;
3078
+ const h = e.sourceImage.value;
3079
+ return h ? Math.round(h.naturalWidth * e.state.crop.width) : 0;
3080
+ }), u = V(() => {
3081
+ if (e.state.resize.height) return e.state.resize.height;
3082
+ const h = e.sourceImage.value;
3083
+ return h ? Math.round(h.naturalHeight * e.state.crop.height) : 0;
3084
+ });
3085
+ function r(h) {
3086
+ const s = parseInt(h, 10);
3087
+ !s || s < 1 || e.updateState((l) => {
3088
+ l.resize.width = s, t.value && (l.resize.height = Math.round(s / o.value));
3089
+ });
3090
+ }
3091
+ function i(h) {
3092
+ const s = parseInt(h, 10);
3093
+ !s || s < 1 || e.updateState((l) => {
3094
+ l.resize.height = s, t.value && (l.resize.width = Math.round(s * o.value));
3095
+ });
3096
+ }
3097
+ return (h, s) => (C(), $("div", ai, [
3098
+ m("div", si, [
3099
+ m("div", ri, [
3100
+ m("label", li, q(S(n)("width")), 1),
3101
+ m("div", ci, [
3102
+ m("input", {
3103
+ type: "number",
3104
+ class: "vie-resize-input__field",
3105
+ value: d.value,
3106
+ min: "1",
3107
+ onInput: s[0] || (s[0] = (l) => r(l.target.value))
3108
+ }, null, 40, ui),
3109
+ s[3] || (s[3] = m("span", { class: "vie-resize-input__unit" }, "px", -1))
3110
+ ])
3111
+ ]),
3112
+ m("button", {
3113
+ class: U(["vie-resize-lock", { "vie-resize-lock--active": t.value }]),
3114
+ onClick: s[1] || (s[1] = (l) => t.value = !t.value),
3115
+ title: S(n)("lockAspectRatio")
3116
+ }, [
3117
+ (C(), $("svg", hi, [
3118
+ s[4] || (s[4] = m("rect", {
3119
+ x: "3",
3120
+ y: "11",
3121
+ width: "18",
3122
+ height: "11",
3123
+ rx: "2",
3124
+ ry: "2"
3125
+ }, null, -1)),
3126
+ t.value ? (C(), $("path", vi)) : (C(), $("path", pi))
3127
+ ]))
3128
+ ], 10, di),
3129
+ m("div", fi, [
3130
+ m("label", mi, q(S(n)("height")), 1),
3131
+ m("div", gi, [
3132
+ m("input", {
3133
+ type: "number",
3134
+ class: "vie-resize-input__field",
3135
+ value: u.value,
3136
+ min: "1",
3137
+ onInput: s[2] || (s[2] = (l) => i(l.target.value))
3138
+ }, null, 40, yi),
3139
+ s[5] || (s[5] = m("span", { class: "vie-resize-input__unit" }, "px", -1))
3140
+ ])
3141
+ ])
3142
+ ])
3143
+ ]));
3144
+ }
3145
+ }), ki = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3146
+ <polyline points="15 3 21 3 21 9" />
3147
+ <polyline points="9 21 3 21 3 15" />
3148
+ <line x1="21" y1="3" x2="14" y2="10" />
3149
+ <line x1="3" y1="21" x2="10" y2="14" />
3150
+ </svg>`;
3151
+ function bi() {
3152
+ return {
3153
+ id: "resize",
3154
+ icon: ki,
3155
+ labelKey: "resize",
3156
+ controls: wi
3157
+ };
3158
+ }
3159
+ const _i = ["dir"], xi = { class: "vie-main" }, Ci = /* @__PURE__ */ Y({
3160
+ __name: "EditorShell",
3161
+ props: {
3162
+ options: {}
3163
+ },
3164
+ emits: ["process", "close"],
3165
+ setup(a, { emit: e }) {
3166
+ const n = a, t = e, o = nt(n.options);
3167
+ it(o);
3168
+ const d = { en: ut, ar: dt }, u = V(() => {
3169
+ const w = n.options.locale || "en";
3170
+ return (M) => {
3171
+ var k;
3172
+ return ((k = d[w]) == null ? void 0 : k[M]) || d.en[M] || M;
3173
+ };
3174
+ });
3175
+ We(ee, (w) => u.value(w));
3176
+ const r = {
3177
+ crop: () => o.registerPlugin(un()),
3178
+ finetune: () => o.registerPlugin(fn()),
3179
+ filter: () => o.registerPlugin(xn()),
3180
+ sticker: () => o.registerPlugin(Ln()),
3181
+ frame: () => o.registerPlugin(Gn()),
3182
+ fill: () => o.registerPlugin(oi()),
3183
+ resize: () => o.registerPlugin(bi())
3184
+ }, i = n.options.plugins || ["crop", "finetune", "filter", "sticker", "frame", "resize"];
3185
+ for (const w of i)
3186
+ r[w] && r[w]();
3187
+ if (n.options.customPlugins)
3188
+ for (const w of n.options.customPlugins)
3189
+ o.registerPlugin(w);
3190
+ const h = F(null), s = F(!1);
3191
+ let l = null;
3192
+ ce(() => {
3193
+ h.value && (l = new ResizeObserver((w) => {
3194
+ for (const M of w) {
3195
+ const { width: k, height: v } = M.contentRect;
3196
+ s.value = k > v && k > 700;
3197
+ }
3198
+ }), l.observe(h.value), h.value.focus());
3199
+ }), ue(() => {
3200
+ l == null || l.disconnect();
3201
+ });
3202
+ function y(w) {
3203
+ w.ctrlKey || w.metaKey ? w.key === "z" && !w.shiftKey ? (w.preventDefault(), o.undo()) : (w.key === "z" && w.shiftKey || w.key === "y") && (w.preventDefault(), o.redo()) : w.key === "Escape" && t("close");
3204
+ }
3205
+ const c = F(!1);
3206
+ async function p() {
3207
+ if (!(!o.sourceImage.value || c.value)) {
3208
+ c.value = !0;
3209
+ try {
3210
+ const M = await new st().process(
3211
+ o.sourceImage.value,
3212
+ o.state,
3213
+ {
3214
+ mimeType: n.options.outputMimeType || "image/jpeg",
3215
+ quality: n.options.outputQuality ?? 0.92,
3216
+ maxCanvasPixels: n.options.maxCanvasPixels
3217
+ }
3218
+ );
3219
+ t("process", M);
3220
+ } finally {
3221
+ c.value = !1;
3222
+ }
3223
+ }
3224
+ }
3225
+ return (w, M) => (C(), $("div", {
3226
+ ref_key: "shellRef",
3227
+ ref: h,
3228
+ class: U([
3229
+ "vie-editor",
3230
+ "vie-shell",
3231
+ s.value ? "vie-shell--horizontal" : "",
3232
+ a.options.theme === "dark" ? "vie-theme-dark" : ""
3233
+ ]),
3234
+ dir: a.options.dir || "ltr",
3235
+ onKeydown: y,
3236
+ tabindex: "0"
3237
+ }, [
3238
+ s.value ? (C(), $(X, { key: 0 }, [
3239
+ O(Ie),
3240
+ m("div", xi, [
3241
+ O($e, {
3242
+ onDone: p,
3243
+ processing: c.value
3244
+ }, null, 8, ["processing"]),
3245
+ O(Re),
3246
+ O(ze)
3247
+ ])
3248
+ ], 64)) : (C(), $(X, { key: 1 }, [
3249
+ O($e, {
3250
+ onDone: p,
3251
+ processing: c.value
3252
+ }, null, 8, ["processing"]),
3253
+ O(Re),
3254
+ O(ze),
3255
+ O(Ie)
3256
+ ], 64))
3257
+ ], 42, _i));
3258
+ }
3259
+ }), Mi = { class: "vie-modal-container" }, Si = /* @__PURE__ */ Y({
3260
+ __name: "EditorModal",
3261
+ props: {
3262
+ src: {},
3263
+ plugins: { default: () => ["crop", "finetune", "filter", "sticker", "frame", "resize"] },
3264
+ locale: { default: "en" },
3265
+ dir: { default: "ltr" },
3266
+ theme: { default: "light" },
3267
+ outputMimeType: {},
3268
+ outputQuality: { default: 0.92 },
3269
+ maxCanvasPixels: {},
3270
+ initialState: {}
3271
+ },
3272
+ emits: ["process", "close"],
3273
+ setup(a, { emit: e }) {
3274
+ const n = a, t = e, o = F(null), d = V(() => ({
3275
+ src: n.src,
3276
+ plugins: n.plugins,
3277
+ locale: n.locale,
3278
+ dir: n.dir,
3279
+ theme: n.theme,
3280
+ outputMimeType: n.outputMimeType,
3281
+ outputQuality: n.outputQuality,
3282
+ maxCanvasPixels: n.maxCanvasPixels,
3283
+ initialState: n.initialState
3284
+ }));
3285
+ function u() {
3286
+ t("close");
3287
+ }
3288
+ function r() {
3289
+ window.confirm("Close editor? Unsaved changes will be lost.") && u();
3290
+ }
3291
+ function i(s) {
3292
+ const l = o.value;
3293
+ if (!l) return;
3294
+ const y = l.querySelectorAll(
3295
+ 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
3296
+ );
3297
+ if (y.length === 0) return;
3298
+ const c = y[0], p = y[y.length - 1];
3299
+ s.shiftKey ? document.activeElement === c && (s.preventDefault(), p.focus()) : document.activeElement === p && (s.preventDefault(), c.focus());
3300
+ }
3301
+ let h = "";
3302
+ return ce(async () => {
3303
+ var s, l;
3304
+ h = document.body.style.overflow, document.body.style.overflow = "hidden", await Je(), (l = (s = o.value) == null ? void 0 : s.querySelector('[tabindex="0"]')) == null || l.focus();
3305
+ }), ue(() => {
3306
+ document.body.style.overflow = h;
3307
+ }), (s, l) => (C(), re(Ge, { to: "body" }, [
3308
+ O(_e, { name: "vie-modal" }, {
3309
+ default: J(() => [
3310
+ m("div", {
3311
+ class: "vie-modal-backdrop",
3312
+ role: "dialog",
3313
+ "aria-modal": "true",
3314
+ onClick: le(r, ["self"]),
3315
+ onKeydown: [
3316
+ Se(u, ["esc"]),
3317
+ Se(i, ["tab"])
3318
+ ],
3319
+ ref_key: "backdropRef",
3320
+ ref: o
3321
+ }, [
3322
+ m("div", Mi, [
3323
+ O(Ci, {
3324
+ options: d.value,
3325
+ onProcess: l[0] || (l[0] = (y) => s.$emit("process", y)),
3326
+ onClose: u
3327
+ }, null, 8, ["options"])
3328
+ ])
3329
+ ], 544)
3330
+ ]),
3331
+ _: 1
3332
+ })
3333
+ ]));
3334
+ }
3335
+ });
3336
+ function Ii(a) {
3337
+ return JSON.stringify(a);
3338
+ }
3339
+ function zi(a) {
3340
+ const e = JSON.parse(a);
3341
+ if (typeof e != "object" || e === null || Array.isArray(e))
3342
+ throw new Error("Invalid state: expected an object");
3343
+ if (Array.isArray(e.stickers)) {
3344
+ for (const n of e.stickers)
3345
+ if (typeof n.src == "string") {
3346
+ const t = n.src.toLowerCase().trim();
3347
+ (t.startsWith("javascript:") || t.startsWith("vbscript:")) && (n.src = "");
3348
+ }
3349
+ }
3350
+ return e;
3351
+ }
3352
+ function Pi(a) {
3353
+ const e = ge();
3354
+ return {
3355
+ ...e,
3356
+ ...a,
3357
+ crop: { ...e.crop, ...a.crop || {} },
3358
+ finetune: { ...e.finetune, ...a.finetune || {} },
3359
+ filter: { ...e.filter, ...a.filter || {} },
3360
+ frame: { ...e.frame, ...a.frame || {} },
3361
+ resize: { ...e.resize, ...a.resize || {} },
3362
+ stickers: a.stickers || e.stickers,
3363
+ backgroundColor: a.backgroundColor || e.backgroundColor
3364
+ };
3365
+ }
3366
+ function $i(a) {
3367
+ a.component("ImageEditorModal", Si);
3368
+ }
3369
+ const Ei = { install: $i };
3370
+ export {
3371
+ _t as CanvasRenderer,
3372
+ un as CropPlugin,
3373
+ oi as FillPlugin,
3374
+ xn as FilterPlugin,
3375
+ fn as FinetunePlugin,
3376
+ Gn as FramePlugin,
3377
+ Qe as History,
3378
+ xe as IDENTITY_MATRIX,
3379
+ Si as ImageEditorModal,
3380
+ Ci as ImageEditorShell,
3381
+ st as ImageProcessor,
3382
+ ee as LOCALE_KEY,
3383
+ bi as ResizePlugin,
3384
+ Ln as StickerPlugin,
3385
+ ke as applyClarity,
3386
+ Ce as applyColorMatrix,
3387
+ ye as applyGamma,
3388
+ we as applyVignette,
3389
+ dt as ar,
3390
+ Ae as brightnessMatrix,
3391
+ De as composeMatrices,
3392
+ Le as contrastMatrix,
3393
+ ge as createDefaultImageState,
3394
+ nt as createEditorEngine,
3395
+ Ei as default,
3396
+ fe as defaultStickerCategories,
3397
+ zi as deserializeState,
3398
+ ut as en,
3399
+ He as exposureMatrix,
3400
+ pe as filterPresets,
3401
+ dn as finetuneEffects,
3402
+ Fn as frameStyles,
3403
+ $i as install,
3404
+ et as loadImage,
3405
+ Pi as mergeWithDefaults,
3406
+ ot as multiplyMatrices,
3407
+ Fe as saturationMatrix,
3408
+ Ii as serializeState,
3409
+ Ve as temperatureMatrix,
3410
+ G as useEditor
3411
+ };
3412
+ //# sourceMappingURL=vuedit-image-editor.es.js.map