@michaelyagi/kiri 0.1.0-alpha.2 → 0.1.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/batch.d.ts +2 -0
- package/dist/export.d.ts +12 -1
- package/dist/gestures.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/kiri.css +7 -0
- package/dist/kiri.d.ts +22 -1
- package/dist/kiri.js +200 -31
- package/dist/kiri.js.map +1 -1
- package/dist/kiri.min.css +1 -1
- package/dist/kiri.min.js +1 -1
- package/dist/kiri.min.js.map +1 -1
- package/dist/kiri.mjs +340 -222
- package/dist/kiri.mjs.map +1 -1
- package/dist/types.d.ts +24 -1
- package/package.json +1 -1
package/dist/kiri.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
const
|
|
1
|
+
var K = Object.defineProperty;
|
|
2
|
+
var X = (i, t, e) => t in i ? K(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
|
|
3
|
+
var d = (i, t, e) => X(i, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
const A = {
|
|
5
5
|
brightness: 1,
|
|
6
6
|
contrast: 1,
|
|
7
7
|
saturation: 1,
|
|
8
8
|
grayscale: !1,
|
|
9
9
|
sepia: !1
|
|
10
10
|
};
|
|
11
|
-
function
|
|
11
|
+
function I(i, t) {
|
|
12
12
|
return {
|
|
13
13
|
brightness: Math.max(0, t.brightness ?? i.brightness),
|
|
14
14
|
contrast: Math.max(0, t.contrast ?? i.contrast),
|
|
@@ -17,7 +17,7 @@ function M(i, t) {
|
|
|
17
17
|
sepia: t.sepia ?? i.sepia
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function $(i) {
|
|
21
21
|
const t = [
|
|
22
22
|
`brightness(${i.brightness})`,
|
|
23
23
|
`contrast(${i.contrast})`,
|
|
@@ -25,148 +25,180 @@ function C(i) {
|
|
|
25
25
|
];
|
|
26
26
|
return i.grayscale && t.push("grayscale(1)"), i.sepia && t.push("sepia(1)"), t.join(" ");
|
|
27
27
|
}
|
|
28
|
-
function
|
|
28
|
+
function j(i, t, e, o, s) {
|
|
29
29
|
i.innerHTML = "";
|
|
30
30
|
const n = document.createElement("div");
|
|
31
|
-
n.className = "kiri-stage"
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
n.className = "kiri-stage", n.tabIndex = 0, n.setAttribute("role", "application"), n.setAttribute(
|
|
32
|
+
"aria-label",
|
|
33
|
+
"Image cropper. Drag to pan. Arrow keys to pan, plus/minus to zoom, 0 to reset."
|
|
34
|
+
);
|
|
35
|
+
const l = document.createElement("div");
|
|
36
|
+
l.className = "kiri-image-layer";
|
|
34
37
|
const c = document.createElement("img");
|
|
35
|
-
c.draggable = !1,
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
+
c.draggable = !1, l.appendChild(c);
|
|
39
|
+
const m = document.createElement("div");
|
|
40
|
+
m.className = t === "circle" ? "kiri-frame kiri-frame--circle" : "kiri-frame", k(m, e, o), n.appendChild(l), n.appendChild(m);
|
|
38
41
|
let h = null;
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
+
if (s.show) {
|
|
43
|
+
const f = document.createElement("div");
|
|
44
|
+
f.className = `kiri-root kiri-root--${s.position}`, h = document.createElement("input"), h.type = "range", h.className = "kiri-zoomer", h.min = String(s.min), h.max = String(s.max), h.step = "0.01", h.value = String(s.value), f.appendChild(n), f.appendChild(h), i.appendChild(f);
|
|
42
45
|
} else
|
|
43
46
|
i.appendChild(n);
|
|
44
|
-
return { stageEl: n, frameEl:
|
|
47
|
+
return { stageEl: n, frameEl: m, imageLayerEl: l, imgEl: c, zoomerEl: h };
|
|
45
48
|
}
|
|
46
|
-
function
|
|
49
|
+
function k(i, t, e) {
|
|
47
50
|
i.style.width = `${t}px`, i.style.height = `${e}px`;
|
|
48
51
|
}
|
|
49
|
-
const
|
|
50
|
-
function
|
|
52
|
+
const C = 20;
|
|
53
|
+
function V(i, t, e) {
|
|
51
54
|
i.style.width = `${t}px`, i.style.height = `${e}px`;
|
|
52
55
|
}
|
|
53
|
-
function
|
|
54
|
-
const
|
|
55
|
-
i.style.transform = `translate(-50%, -50%) translate(${t.offset.x}px, ${t.offset.y}px) rotate(${t.rotation}deg) scale(${
|
|
56
|
+
function W(i, t, e) {
|
|
57
|
+
const o = e * (t.flip.horizontal ? -1 : 1), s = e * (t.flip.vertical ? -1 : 1);
|
|
58
|
+
i.style.transform = `translate(-50%, -50%) translate(${t.offset.x}px, ${t.offset.y}px) rotate(${t.rotation}deg) scale(${o}, ${s})`;
|
|
56
59
|
}
|
|
57
|
-
function
|
|
58
|
-
i.style.filter =
|
|
60
|
+
function R(i, t) {
|
|
61
|
+
i.style.filter = $(t);
|
|
59
62
|
}
|
|
60
|
-
function
|
|
63
|
+
function N(i, t) {
|
|
61
64
|
return (t / 90 % 2 + 2) % 2 === 1 ? { width: i.height, height: i.width } : { width: i.width, height: i.height };
|
|
62
65
|
}
|
|
63
|
-
function
|
|
64
|
-
const
|
|
65
|
-
return
|
|
66
|
+
function O(i, t, e) {
|
|
67
|
+
const o = N(i, e);
|
|
68
|
+
return o.width <= 0 || o.height <= 0 ? 1 : Math.max(t.width / o.width, t.height / o.height);
|
|
66
69
|
}
|
|
67
|
-
function
|
|
68
|
-
const
|
|
69
|
-
return { width:
|
|
70
|
+
function S(i, t, e, o) {
|
|
71
|
+
const s = N(i, e), n = O(i, t, e) * o;
|
|
72
|
+
return { width: s.width * n, height: s.height * n };
|
|
70
73
|
}
|
|
71
|
-
function
|
|
74
|
+
function P(i, t, e) {
|
|
72
75
|
return Math.min(Math.max(i, t), e);
|
|
73
76
|
}
|
|
74
|
-
function
|
|
75
|
-
const
|
|
77
|
+
function x(i, t, e) {
|
|
78
|
+
const o = Math.max(0, (t.width - e.width) / 2), s = Math.max(0, (t.height - e.height) / 2);
|
|
76
79
|
return {
|
|
77
|
-
x: Math.min(Math.max(i.x, -
|
|
78
|
-
y: Math.min(Math.max(i.y, -
|
|
80
|
+
x: Math.min(Math.max(i.x, -o), o) || 0,
|
|
81
|
+
y: Math.min(Math.max(i.y, -s), s) || 0
|
|
79
82
|
};
|
|
80
83
|
}
|
|
81
|
-
function
|
|
84
|
+
function b(i) {
|
|
82
85
|
return (i % 360 + 360) % 360;
|
|
83
86
|
}
|
|
84
|
-
|
|
87
|
+
const F = 15, T = 0.1;
|
|
88
|
+
function H(i, t) {
|
|
85
89
|
return Math.hypot(i.clientX - t.clientX, i.clientY - t.clientY);
|
|
86
90
|
}
|
|
87
|
-
function
|
|
88
|
-
const
|
|
89
|
-
let
|
|
90
|
-
function c(
|
|
91
|
-
const { min:
|
|
91
|
+
function B(i, t, e) {
|
|
92
|
+
const o = /* @__PURE__ */ new Map();
|
|
93
|
+
let s = null, n = 0, l = 1;
|
|
94
|
+
function c(r) {
|
|
95
|
+
const { min: a, max: g } = t.getMinMaxZoom(), w = P(r.zoom, a, g), z = S(
|
|
92
96
|
t.getNaturalSize(),
|
|
93
97
|
t.getFrameSize(),
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
),
|
|
98
|
+
r.rotation,
|
|
99
|
+
w
|
|
100
|
+
), y = x(r.offset, z, t.getFrameSize());
|
|
97
101
|
t.setState({
|
|
98
|
-
zoom:
|
|
99
|
-
offset:
|
|
100
|
-
rotation:
|
|
101
|
-
flip:
|
|
102
|
-
filters:
|
|
102
|
+
zoom: w,
|
|
103
|
+
offset: y,
|
|
104
|
+
rotation: b(r.rotation),
|
|
105
|
+
flip: r.flip,
|
|
106
|
+
filters: r.filters
|
|
103
107
|
});
|
|
104
108
|
}
|
|
105
|
-
function
|
|
106
|
-
if (i.setPointerCapture(
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
} else if (
|
|
110
|
-
|
|
111
|
-
const [
|
|
112
|
-
n =
|
|
109
|
+
function m(r) {
|
|
110
|
+
if (i.setPointerCapture(r.pointerId), o.set(r.pointerId, r), o.size === 1) {
|
|
111
|
+
const a = t.getState();
|
|
112
|
+
s = { x: r.clientX, y: r.clientY, offset: a.offset }, i.classList.add("kiri-dragging");
|
|
113
|
+
} else if (o.size === 2) {
|
|
114
|
+
s = null;
|
|
115
|
+
const [a, g] = [...o.values()];
|
|
116
|
+
n = H(a, g), l = t.getState().zoom;
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
|
-
function h(
|
|
116
|
-
if (
|
|
117
|
-
if (
|
|
118
|
-
const [
|
|
119
|
+
function h(r) {
|
|
120
|
+
if (o.has(r.pointerId)) {
|
|
121
|
+
if (o.set(r.pointerId, r), o.size === 2) {
|
|
122
|
+
const [a, g] = [...o.values()], w = H(a, g);
|
|
119
123
|
if (n > 0) {
|
|
120
|
-
const
|
|
121
|
-
c({ ...
|
|
124
|
+
const z = w / n, y = t.getState();
|
|
125
|
+
c({ ...y, zoom: l * z });
|
|
122
126
|
}
|
|
123
127
|
return;
|
|
124
128
|
}
|
|
125
|
-
if (
|
|
126
|
-
const
|
|
129
|
+
if (s) {
|
|
130
|
+
const a = r.clientX - s.x, g = r.clientY - s.y, w = t.getState();
|
|
127
131
|
c({
|
|
128
|
-
...
|
|
129
|
-
offset: { x:
|
|
132
|
+
...w,
|
|
133
|
+
offset: { x: s.offset.x + a, y: s.offset.y + g }
|
|
130
134
|
});
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
}
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
function u(
|
|
138
|
-
if (!e.mouseWheelZoom || e.mouseWheelZoom === "ctrl" && !
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
c({ ...
|
|
138
|
+
function f(r) {
|
|
139
|
+
o.delete(r.pointerId), o.size < 2 && (n = 0), o.size === 0 && (s = null, i.classList.remove("kiri-dragging"));
|
|
140
|
+
}
|
|
141
|
+
function u(r) {
|
|
142
|
+
if (!e.mouseWheelZoom || e.mouseWheelZoom === "ctrl" && !r.ctrlKey) return;
|
|
143
|
+
r.preventDefault();
|
|
144
|
+
const a = t.getState(), g = -r.deltaY * 15e-4;
|
|
145
|
+
c({ ...a, zoom: a.zoom * (1 + g) });
|
|
146
|
+
}
|
|
147
|
+
function p(r) {
|
|
148
|
+
const a = t.getState();
|
|
149
|
+
switch (r.key) {
|
|
150
|
+
case "ArrowLeft":
|
|
151
|
+
r.preventDefault(), c({ ...a, offset: { ...a.offset, x: a.offset.x + F } });
|
|
152
|
+
break;
|
|
153
|
+
case "ArrowRight":
|
|
154
|
+
r.preventDefault(), c({ ...a, offset: { ...a.offset, x: a.offset.x - F } });
|
|
155
|
+
break;
|
|
156
|
+
case "ArrowUp":
|
|
157
|
+
r.preventDefault(), c({ ...a, offset: { ...a.offset, y: a.offset.y + F } });
|
|
158
|
+
break;
|
|
159
|
+
case "ArrowDown":
|
|
160
|
+
r.preventDefault(), c({ ...a, offset: { ...a.offset, y: a.offset.y - F } });
|
|
161
|
+
break;
|
|
162
|
+
case "+":
|
|
163
|
+
case "=":
|
|
164
|
+
r.preventDefault(), c({ ...a, zoom: a.zoom + T });
|
|
165
|
+
break;
|
|
166
|
+
case "-":
|
|
167
|
+
case "_":
|
|
168
|
+
r.preventDefault(), c({ ...a, zoom: a.zoom - T });
|
|
169
|
+
break;
|
|
170
|
+
case "0":
|
|
171
|
+
r.preventDefault(), t.reset();
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
142
174
|
}
|
|
143
|
-
return i.addEventListener("pointerdown",
|
|
175
|
+
return i.addEventListener("pointerdown", m), i.addEventListener("pointermove", h), i.addEventListener("pointerup", f), i.addEventListener("pointercancel", f), i.addEventListener("wheel", u, { passive: !1 }), i.addEventListener("keydown", p), {
|
|
144
176
|
destroy() {
|
|
145
|
-
i.removeEventListener("pointerdown",
|
|
177
|
+
i.removeEventListener("pointerdown", m), i.removeEventListener("pointermove", h), i.removeEventListener("pointerup", f), i.removeEventListener("pointercancel", f), i.removeEventListener("wheel", u), i.removeEventListener("keydown", p);
|
|
146
178
|
}
|
|
147
179
|
};
|
|
148
180
|
}
|
|
149
|
-
function
|
|
181
|
+
function G(i) {
|
|
150
182
|
const t = new DataView(i);
|
|
151
183
|
if (t.byteLength < 4 || t.getUint16(0, !1) !== 65496) return 1;
|
|
152
184
|
let e = 2;
|
|
153
185
|
for (; e + 4 <= t.byteLength; ) {
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
186
|
+
const o = t.getUint16(e, !1), s = t.getUint16(e + 2, !1);
|
|
187
|
+
if (o === 65505) {
|
|
156
188
|
const n = e + 4;
|
|
157
|
-
return t.getUint32(n, !1) !== 1165519206 ? 1 :
|
|
189
|
+
return t.getUint32(n, !1) !== 1165519206 ? 1 : q(t, n + 6);
|
|
158
190
|
}
|
|
159
|
-
if ((
|
|
160
|
-
e += 2 +
|
|
191
|
+
if ((o & 65280) !== 65280) break;
|
|
192
|
+
e += 2 + s;
|
|
161
193
|
}
|
|
162
194
|
return 1;
|
|
163
195
|
}
|
|
164
|
-
function
|
|
165
|
-
const e = i.getUint16(t, !1) === 18761,
|
|
166
|
-
if (
|
|
167
|
-
const n = i.getUint16(
|
|
168
|
-
for (let
|
|
169
|
-
const c =
|
|
196
|
+
function q(i, t) {
|
|
197
|
+
const e = i.getUint16(t, !1) === 18761, o = i.getUint32(t + 4, e), s = t + o;
|
|
198
|
+
if (s + 2 > i.byteLength) return 1;
|
|
199
|
+
const n = i.getUint16(s, e);
|
|
200
|
+
for (let l = 0; l < n; l++) {
|
|
201
|
+
const c = s + 2 + l * 12;
|
|
170
202
|
if (c + 12 > i.byteLength) break;
|
|
171
203
|
if (i.getUint16(c, e) === 274) {
|
|
172
204
|
const h = i.getUint16(c + 8, e);
|
|
@@ -175,7 +207,7 @@ function K(i, t) {
|
|
|
175
207
|
}
|
|
176
208
|
return 1;
|
|
177
209
|
}
|
|
178
|
-
function
|
|
210
|
+
function J(i) {
|
|
179
211
|
switch (i) {
|
|
180
212
|
case 2:
|
|
181
213
|
return { rotation: 0, flipHorizontal: !0 };
|
|
@@ -195,78 +227,101 @@ function j(i) {
|
|
|
195
227
|
return { rotation: 0, flipHorizontal: !1 };
|
|
196
228
|
}
|
|
197
229
|
}
|
|
198
|
-
function
|
|
230
|
+
function D(i, t, e, o) {
|
|
199
231
|
return i === void 0 ? e : t.includes(i) ? i : (console.warn(
|
|
200
|
-
`Kiri: invalid ${
|
|
232
|
+
`Kiri: invalid ${o} "${i}" — defaulting to "${e}". Valid values: ${t.join(", ")}.`
|
|
201
233
|
), e);
|
|
202
234
|
}
|
|
203
|
-
|
|
204
|
-
|
|
235
|
+
function Z(i, t, e) {
|
|
236
|
+
return Math.min(Math.max(i, t), e);
|
|
237
|
+
}
|
|
238
|
+
const Q = ["base64", "blob", "canvas"], tt = ["image/jpeg", "image/png", "image/webp"];
|
|
239
|
+
function Y(i, t, e) {
|
|
205
240
|
return {
|
|
206
241
|
left: i.width / 2 - t.x - e.width / 2,
|
|
207
242
|
top: i.height / 2 - t.y - e.height / 2
|
|
208
243
|
};
|
|
209
244
|
}
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
245
|
+
function et(i, t, e) {
|
|
246
|
+
const o = O(i, t, e.rotation) * e.zoom, s = S(i, t, e.rotation, e.zoom), { left: n, top: l } = Y(s, e.offset, t), c = { x: s.width / 2, y: s.height / 2 }, m = { x: i.width / 2, y: i.height / 2 }, h = b(e.rotation), f = [
|
|
247
|
+
{ x: n, y: l },
|
|
248
|
+
{ x: n + t.width, y: l },
|
|
249
|
+
{ x: n, y: l + t.height },
|
|
250
|
+
{ x: n + t.width, y: l + t.height }
|
|
251
|
+
].map(({ x: z, y }) => {
|
|
252
|
+
const M = (z - c.x) / o, L = (y - c.y) / o;
|
|
253
|
+
let v, E;
|
|
254
|
+
return h === 90 ? (v = L, E = -M) : h === 180 ? (v = -M, E = -L) : h === 270 ? (v = -L, E = M) : (v = M, E = L), { x: v + m.x, y: E + m.y };
|
|
255
|
+
}), u = f.map((z) => z.x), p = f.map((z) => z.y), r = Z(Math.min(...u), 0, i.width), a = Z(Math.min(...p), 0, i.height), g = Z(Math.max(...u), 0, i.width), w = Z(Math.max(...p), 0, i.height);
|
|
256
|
+
return {
|
|
257
|
+
x: Math.round(r),
|
|
258
|
+
y: Math.round(a),
|
|
259
|
+
width: Math.round(g - r),
|
|
260
|
+
height: Math.round(w - a),
|
|
261
|
+
rotation: h,
|
|
262
|
+
flip: { ...e.flip }
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function it(i, t, e, o, s, n) {
|
|
266
|
+
const l = { width: i.naturalWidth, height: i.naturalHeight }, c = O(l, e, t.rotation) * t.zoom, m = S(l, e, t.rotation, t.zoom), h = document.createElement("canvas");
|
|
267
|
+
h.width = Math.max(1, Math.round(m.width)), h.height = Math.max(1, Math.round(m.height));
|
|
268
|
+
const f = h.getContext("2d");
|
|
269
|
+
if (!f) throw new Error("Kiri: unable to get 2D canvas context");
|
|
270
|
+
f.translate(h.width / 2, h.height / 2), f.rotate(t.rotation * Math.PI / 180), f.scale(c * (t.flip.horizontal ? -1 : 1), c * (t.flip.vertical ? -1 : 1)), f.filter = $(t.filters), f.drawImage(i, -l.width / 2, -l.height / 2, l.width, l.height);
|
|
271
|
+
const { left: u, top: p } = Y(
|
|
272
|
+
m,
|
|
218
273
|
t.offset,
|
|
219
274
|
e
|
|
220
|
-
),
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
if (!
|
|
224
|
-
return n === "circle" && (
|
|
225
|
-
s / 2,
|
|
275
|
+
), r = document.createElement("canvas");
|
|
276
|
+
r.width = o, r.height = s;
|
|
277
|
+
const a = r.getContext("2d");
|
|
278
|
+
if (!a) throw new Error("Kiri: unable to get 2D canvas context");
|
|
279
|
+
return n === "circle" && (a.save(), a.beginPath(), a.ellipse(
|
|
226
280
|
o / 2,
|
|
227
281
|
s / 2,
|
|
228
282
|
o / 2,
|
|
283
|
+
s / 2,
|
|
229
284
|
0,
|
|
230
285
|
0,
|
|
231
286
|
Math.PI * 2
|
|
232
|
-
),
|
|
287
|
+
), a.clip()), a.drawImage(
|
|
233
288
|
h,
|
|
234
289
|
u,
|
|
235
|
-
|
|
290
|
+
p,
|
|
236
291
|
e.width,
|
|
237
292
|
e.height,
|
|
238
293
|
0,
|
|
239
294
|
0,
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
), n === "circle" &&
|
|
295
|
+
o,
|
|
296
|
+
s
|
|
297
|
+
), n === "circle" && a.restore(), r;
|
|
243
298
|
}
|
|
244
|
-
async function
|
|
245
|
-
const n =
|
|
246
|
-
|
|
299
|
+
async function ot(i, t, e, o, s) {
|
|
300
|
+
const n = D(s.type, Q, "base64", "export type"), l = D(s.format, tt, "image/png", "export format"), c = s.quality, m = s.width ?? e.width, h = s.height ?? e.height;
|
|
301
|
+
o === "circle" && l === "image/jpeg" && console.warn(
|
|
247
302
|
"Kiri: exporting a circle-shaped frame as image/jpeg — JPEG has no alpha channel, so the area outside the circle will render as solid black instead of transparent. Use image/png or image/webp instead."
|
|
248
303
|
);
|
|
249
|
-
const
|
|
250
|
-
return n === "canvas" ?
|
|
251
|
-
|
|
252
|
-
(
|
|
253
|
-
|
|
304
|
+
const f = it(i, t, e, m, h, o);
|
|
305
|
+
return n === "canvas" ? f : n === "base64" ? f.toDataURL(l, c) : new Promise((u, p) => {
|
|
306
|
+
f.toBlob(
|
|
307
|
+
(r) => r ? u(r) : p(new Error("Kiri: canvas.toBlob failed")),
|
|
308
|
+
l,
|
|
254
309
|
c
|
|
255
310
|
);
|
|
256
311
|
});
|
|
257
312
|
}
|
|
258
|
-
async function
|
|
259
|
-
const e = t.fieldName ?? "file",
|
|
260
|
-
|
|
261
|
-
for (const [n,
|
|
262
|
-
|
|
313
|
+
async function st(i, t) {
|
|
314
|
+
const e = t.fieldName ?? "file", o = t.fileName ?? `crop.${nt(t.format ?? "image/png")}`, s = new FormData();
|
|
315
|
+
s.append(e, i, o);
|
|
316
|
+
for (const [n, l] of Object.entries(t.extraFields ?? {}))
|
|
317
|
+
s.append(n, l);
|
|
263
318
|
return fetch(t.url, {
|
|
264
319
|
...t.fetchOptions,
|
|
265
320
|
method: "POST",
|
|
266
|
-
body:
|
|
321
|
+
body: s
|
|
267
322
|
});
|
|
268
323
|
}
|
|
269
|
-
function
|
|
324
|
+
function nt(i) {
|
|
270
325
|
switch (i) {
|
|
271
326
|
case "image/jpeg":
|
|
272
327
|
return "jpg";
|
|
@@ -276,67 +331,70 @@ function G(i) {
|
|
|
276
331
|
return "png";
|
|
277
332
|
}
|
|
278
333
|
}
|
|
279
|
-
const
|
|
280
|
-
function
|
|
334
|
+
const U = 200, _ = 20, rt = ["rectangle", "circle"], at = ["top", "bottom", "left", "right"];
|
|
335
|
+
function ht(i) {
|
|
281
336
|
return i === void 0 ? !0 : typeof i == "boolean" || i === "ctrl" ? i : (console.warn(
|
|
282
337
|
`Kiri: invalid mouseWheelZoom "${String(i)}" — defaulting to true. Valid values: true, false, "ctrl".`
|
|
283
338
|
), !0);
|
|
284
339
|
}
|
|
285
|
-
class
|
|
340
|
+
class lt {
|
|
286
341
|
/**
|
|
287
342
|
* @param container An element already present in the DOM. Passing
|
|
288
343
|
* `null`/`undefined`, or an element that isn't in the DOM yet, throws.
|
|
289
344
|
* @param options See the {@link KiriOptions} fields for defaults.
|
|
290
345
|
*/
|
|
291
346
|
constructor(t, e = {}) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
347
|
+
d(this, "container");
|
|
348
|
+
d(this, "opts");
|
|
349
|
+
d(this, "stage");
|
|
350
|
+
d(this, "gestureHandle");
|
|
351
|
+
d(this, "resizeHandle", null);
|
|
352
|
+
d(this, "zoomerHandle", null);
|
|
353
|
+
d(this, "naturalSize", { width: 0, height: 0 });
|
|
354
|
+
d(this, "state", {
|
|
300
355
|
zoom: 1,
|
|
301
356
|
offset: { x: 0, y: 0 },
|
|
302
357
|
rotation: 0,
|
|
303
358
|
flip: { horizontal: !1, vertical: !1 },
|
|
304
|
-
filters:
|
|
359
|
+
filters: A
|
|
305
360
|
});
|
|
306
|
-
|
|
307
|
-
|
|
361
|
+
/** Snapshot taken right after `load()` resolves, so `reset()` has something to revert to. */
|
|
362
|
+
d(this, "initialState", null);
|
|
363
|
+
d(this, "listeners", { change: [] });
|
|
364
|
+
var o, s, n;
|
|
308
365
|
if (!t || typeof t.appendChild != "function")
|
|
309
366
|
throw new Error(
|
|
310
367
|
"Kiri: container element is null/undefined or not a DOM element. This usually means the element wasn't in the DOM yet when `new Kiri(...)` ran — e.g. document.getElementById() was called before the element existed. Place the <script> after the element, or construct inside a DOMContentLoaded listener."
|
|
311
368
|
);
|
|
312
369
|
this.container = t, this.opts = {
|
|
313
370
|
frame: {
|
|
314
|
-
shape:
|
|
315
|
-
(
|
|
316
|
-
|
|
371
|
+
shape: D(
|
|
372
|
+
(o = e.frame) == null ? void 0 : o.shape,
|
|
373
|
+
rt,
|
|
317
374
|
"rectangle",
|
|
318
375
|
"frame.shape"
|
|
319
376
|
),
|
|
320
|
-
width: ((
|
|
321
|
-
height: ((n = e.frame) == null ? void 0 : n.height) ??
|
|
377
|
+
width: ((s = e.frame) == null ? void 0 : s.width) ?? U,
|
|
378
|
+
height: ((n = e.frame) == null ? void 0 : n.height) ?? U
|
|
322
379
|
},
|
|
323
380
|
minZoom: e.minZoom ?? 1,
|
|
324
381
|
maxZoom: e.maxZoom ?? 4,
|
|
325
382
|
rotatable: e.rotatable ?? !0,
|
|
326
383
|
flippable: e.flippable ?? !0,
|
|
327
384
|
resizableFrame: e.resizableFrame ?? !1,
|
|
328
|
-
|
|
385
|
+
lockAspectRatio: e.lockAspectRatio ?? !1,
|
|
386
|
+
mouseWheelZoom: ht(e.mouseWheelZoom),
|
|
329
387
|
useExifOrientation: e.useExifOrientation ?? !0,
|
|
330
388
|
uploader: e.uploader,
|
|
331
389
|
autoSizeStage: e.autoSizeStage ?? !0,
|
|
332
390
|
showZoomer: e.showZoomer ?? !1,
|
|
333
|
-
zoomerPosition:
|
|
391
|
+
zoomerPosition: D(
|
|
334
392
|
e.zoomerPosition,
|
|
335
|
-
|
|
393
|
+
at,
|
|
336
394
|
"bottom",
|
|
337
395
|
"zoomerPosition"
|
|
338
396
|
)
|
|
339
|
-
}, this.state.filters =
|
|
397
|
+
}, this.state.filters = I(A, e.filters ?? {}), this.stage = j(
|
|
340
398
|
this.container,
|
|
341
399
|
this.opts.frame.shape,
|
|
342
400
|
this.opts.frame.width,
|
|
@@ -348,14 +406,15 @@ class tt {
|
|
|
348
406
|
max: this.opts.maxZoom,
|
|
349
407
|
value: this.state.zoom
|
|
350
408
|
}
|
|
351
|
-
), this.opts.autoSizeStage && this.syncStageSize(),
|
|
409
|
+
), this.opts.autoSizeStage && this.syncStageSize(), R(this.stage.imgEl, this.state.filters), this.stage.zoomerEl && this.enableZoomer(this.stage.zoomerEl), this.gestureHandle = B(
|
|
352
410
|
this.stage.stageEl,
|
|
353
411
|
{
|
|
354
412
|
getNaturalSize: () => this.naturalSize,
|
|
355
413
|
getFrameSize: () => this.getFrameSize(),
|
|
356
414
|
getState: () => this.state,
|
|
357
415
|
getMinMaxZoom: () => ({ min: this.opts.minZoom, max: this.opts.maxZoom }),
|
|
358
|
-
setState: (
|
|
416
|
+
setState: (l) => this.commitState(l),
|
|
417
|
+
reset: () => this.reset()
|
|
359
418
|
},
|
|
360
419
|
{ mouseWheelZoom: this.opts.mouseWheelZoom }
|
|
361
420
|
), this.opts.resizableFrame && this.enableFrameResize();
|
|
@@ -370,37 +429,37 @@ class tt {
|
|
|
370
429
|
* @param loadOptions Initial `zoom`/`offset`/`rotation`/`flip`.
|
|
371
430
|
*/
|
|
372
431
|
async load(t, e = {}) {
|
|
373
|
-
var u,
|
|
374
|
-
let
|
|
375
|
-
const n = ((
|
|
376
|
-
let
|
|
432
|
+
var u, p;
|
|
433
|
+
let o = b(e.rotation ?? 0), s = ((u = e.flip) == null ? void 0 : u.horizontal) ?? !1;
|
|
434
|
+
const n = ((p = e.flip) == null ? void 0 : p.vertical) ?? !1;
|
|
435
|
+
let l = null, c;
|
|
377
436
|
if (typeof t == "string")
|
|
378
437
|
c = t;
|
|
379
438
|
else {
|
|
380
439
|
if (this.opts.useExifOrientation) {
|
|
381
|
-
const
|
|
382
|
-
|
|
440
|
+
const r = await t.arrayBuffer(), a = G(r), g = J(a);
|
|
441
|
+
o = b(o + g.rotation), s = s !== g.flipHorizontal;
|
|
383
442
|
}
|
|
384
|
-
|
|
443
|
+
l = URL.createObjectURL(t), c = l;
|
|
385
444
|
}
|
|
386
|
-
await new Promise((
|
|
387
|
-
this.stage.imgEl.onload = () =>
|
|
388
|
-
}),
|
|
445
|
+
await new Promise((r, a) => {
|
|
446
|
+
this.stage.imgEl.onload = () => r(), this.stage.imgEl.onerror = () => a(new Error("Kiri: failed to load image")), this.stage.imgEl.src = c;
|
|
447
|
+
}), l && URL.revokeObjectURL(l), this.naturalSize = {
|
|
389
448
|
width: this.stage.imgEl.naturalWidth,
|
|
390
449
|
height: this.stage.imgEl.naturalHeight
|
|
391
450
|
};
|
|
392
|
-
const
|
|
451
|
+
const m = P(
|
|
393
452
|
e.zoom ?? this.opts.minZoom,
|
|
394
453
|
this.opts.minZoom,
|
|
395
454
|
this.opts.maxZoom
|
|
396
|
-
), h =
|
|
455
|
+
), h = S(this.naturalSize, this.getFrameSize(), o, m), f = x(e.offset ?? { x: 0, y: 0 }, h, this.getFrameSize());
|
|
397
456
|
this.commitState({
|
|
398
|
-
zoom:
|
|
399
|
-
offset:
|
|
400
|
-
rotation:
|
|
401
|
-
flip: { horizontal:
|
|
457
|
+
zoom: m,
|
|
458
|
+
offset: f,
|
|
459
|
+
rotation: o,
|
|
460
|
+
flip: { horizontal: s, vertical: n },
|
|
402
461
|
filters: this.state.filters
|
|
403
|
-
});
|
|
462
|
+
}), this.initialState = this.getState();
|
|
404
463
|
}
|
|
405
464
|
/** A snapshot of the current state — mutating the returned object has no effect. */
|
|
406
465
|
getState() {
|
|
@@ -414,13 +473,41 @@ class tt {
|
|
|
414
473
|
}
|
|
415
474
|
/** Sets the zoom to an absolute value, clamped to `[minZoom, maxZoom]`. */
|
|
416
475
|
setZoom(t) {
|
|
417
|
-
const e =
|
|
476
|
+
const e = P(t, this.opts.minZoom, this.opts.maxZoom), o = S(
|
|
418
477
|
this.naturalSize,
|
|
419
478
|
this.getFrameSize(),
|
|
420
479
|
this.state.rotation,
|
|
421
480
|
e
|
|
422
|
-
),
|
|
423
|
-
this.commitState({ ...this.state, zoom: e, offset:
|
|
481
|
+
), s = x(this.state.offset, o, this.getFrameSize());
|
|
482
|
+
this.commitState({ ...this.state, zoom: e, offset: s });
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Sets the pan offset to an absolute value (image-center offset from the
|
|
486
|
+
* frame center, in stage pixels), clamped so the frame stays fully covered
|
|
487
|
+
* by the rendered image.
|
|
488
|
+
*/
|
|
489
|
+
setOffset(t) {
|
|
490
|
+
const e = S(
|
|
491
|
+
this.naturalSize,
|
|
492
|
+
this.getFrameSize(),
|
|
493
|
+
this.state.rotation,
|
|
494
|
+
this.state.zoom
|
|
495
|
+
), o = x(t, e, this.getFrameSize());
|
|
496
|
+
this.commitState({ ...this.state, offset: o });
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Reverts zoom/offset/rotation/flip/filters to what they were right after
|
|
500
|
+
* `load()` resolved (including any `loadOptions` passed to it). No-op if
|
|
501
|
+
* nothing has been loaded yet.
|
|
502
|
+
*/
|
|
503
|
+
reset() {
|
|
504
|
+
this.initialState && this.commitState({
|
|
505
|
+
zoom: this.initialState.zoom,
|
|
506
|
+
offset: { ...this.initialState.offset },
|
|
507
|
+
rotation: this.initialState.rotation,
|
|
508
|
+
flip: { ...this.initialState.flip },
|
|
509
|
+
filters: { ...this.initialState.filters }
|
|
510
|
+
});
|
|
424
511
|
}
|
|
425
512
|
/**
|
|
426
513
|
* Rotates relative to the current rotation, snapped to the nearest 90°.
|
|
@@ -428,13 +515,13 @@ class tt {
|
|
|
428
515
|
*/
|
|
429
516
|
rotate(t) {
|
|
430
517
|
if (!this.opts.rotatable) return;
|
|
431
|
-
const e = Math.round(t / 90) * 90,
|
|
518
|
+
const e = Math.round(t / 90) * 90, o = b(this.state.rotation + e), s = S(
|
|
432
519
|
this.naturalSize,
|
|
433
520
|
this.getFrameSize(),
|
|
434
|
-
|
|
521
|
+
o,
|
|
435
522
|
this.state.zoom
|
|
436
|
-
), n =
|
|
437
|
-
this.commitState({ ...this.state, rotation:
|
|
523
|
+
), n = x(this.state.offset, s, this.getFrameSize());
|
|
524
|
+
this.commitState({ ...this.state, rotation: o, offset: n });
|
|
438
525
|
}
|
|
439
526
|
/** Toggles horizontal flip, independent of rotation. No-op if `flippable: false`. */
|
|
440
527
|
flipHorizontal() {
|
|
@@ -454,21 +541,21 @@ class tt {
|
|
|
454
541
|
* minimum.
|
|
455
542
|
*/
|
|
456
543
|
setFrameSize(t, e) {
|
|
457
|
-
this.opts.frame.width = Math.max(
|
|
458
|
-
const
|
|
544
|
+
this.opts.frame.width = Math.max(_, t), this.opts.frame.height = Math.max(_, e), k(this.stage.frameEl, this.opts.frame.width, this.opts.frame.height), this.opts.autoSizeStage && this.syncStageSize();
|
|
545
|
+
const o = S(
|
|
459
546
|
this.naturalSize,
|
|
460
547
|
this.getFrameSize(),
|
|
461
548
|
this.state.rotation,
|
|
462
549
|
this.state.zoom
|
|
463
|
-
),
|
|
464
|
-
this.commitState({ ...this.state, offset:
|
|
550
|
+
), s = x(this.state.offset, o, this.getFrameSize());
|
|
551
|
+
this.commitState({ ...this.state, offset: s });
|
|
465
552
|
}
|
|
466
553
|
/**
|
|
467
554
|
* Merges a partial update into the current filters (omitted fields are
|
|
468
555
|
* left as they are). Numeric values are clamped to `>= 0`.
|
|
469
556
|
*/
|
|
470
557
|
setFilters(t) {
|
|
471
|
-
this.commitState({ ...this.state, filters:
|
|
558
|
+
this.commitState({ ...this.state, filters: I(this.state.filters, t) });
|
|
472
559
|
}
|
|
473
560
|
/**
|
|
474
561
|
* Renders the current crop. A circle frame is a real clip in the output
|
|
@@ -477,7 +564,7 @@ class tt {
|
|
|
477
564
|
* @returns A data URL string (`type: "base64"`, the default), a `Blob`, or an `HTMLCanvasElement`.
|
|
478
565
|
*/
|
|
479
566
|
async export(t = {}) {
|
|
480
|
-
return
|
|
567
|
+
return ot(
|
|
481
568
|
this.stage.imgEl,
|
|
482
569
|
this.state,
|
|
483
570
|
this.getFrameSize(),
|
|
@@ -485,14 +572,23 @@ class tt {
|
|
|
485
572
|
t
|
|
486
573
|
);
|
|
487
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* The current crop selection as a rectangle in the original, unrotated,
|
|
577
|
+
* unflipped source image's own pixel coordinates — for sending to a server
|
|
578
|
+
* that will crop the full-resolution original itself instead of uploading
|
|
579
|
+
* a client-re-encoded image. See {@link CropRegion}.
|
|
580
|
+
*/
|
|
581
|
+
getCropRegion() {
|
|
582
|
+
return et(this.naturalSize, this.getFrameSize(), this.state);
|
|
583
|
+
}
|
|
488
584
|
/**
|
|
489
585
|
* Exports the current crop as a blob, then uploads it — a default
|
|
490
586
|
* FormData/`fetch` POST, or a custom `uploader` (per-call `options.uploader`
|
|
491
587
|
* wins over the constructor's, which wins over the built-in default).
|
|
492
588
|
*/
|
|
493
589
|
async upload(t, e = {}) {
|
|
494
|
-
const
|
|
495
|
-
return (e.uploader ?? this.opts.uploader ??
|
|
590
|
+
const o = await this.export({ ...e, type: "blob" });
|
|
591
|
+
return (e.uploader ?? this.opts.uploader ?? st)(o, { ...e, url: t });
|
|
496
592
|
}
|
|
497
593
|
/** Subscribes to `"change"` — fires on every state update (drag/zoom/rotate/flip/filters), and once after `load()` resolves. */
|
|
498
594
|
on(t, e) {
|
|
@@ -500,7 +596,7 @@ class tt {
|
|
|
500
596
|
}
|
|
501
597
|
/** Unsubscribes a callback previously passed to {@link on}. */
|
|
502
598
|
off(t, e) {
|
|
503
|
-
this.listeners[t] = this.listeners[t].filter((
|
|
599
|
+
this.listeners[t] = this.listeners[t].filter((o) => o !== e);
|
|
504
600
|
}
|
|
505
601
|
/**
|
|
506
602
|
* Tears the instance down: removes all pointer/wheel event listeners
|
|
@@ -518,17 +614,17 @@ class tt {
|
|
|
518
614
|
return { width: this.opts.frame.width, height: this.opts.frame.height };
|
|
519
615
|
}
|
|
520
616
|
syncStageSize() {
|
|
521
|
-
|
|
617
|
+
V(
|
|
522
618
|
this.stage.stageEl,
|
|
523
|
-
this.opts.frame.width +
|
|
524
|
-
this.opts.frame.height +
|
|
619
|
+
this.opts.frame.width + C * 2,
|
|
620
|
+
this.opts.frame.height + C * 2
|
|
525
621
|
);
|
|
526
622
|
}
|
|
527
623
|
commitState(t) {
|
|
528
624
|
this.state = t;
|
|
529
|
-
const e =
|
|
530
|
-
|
|
531
|
-
for (const
|
|
625
|
+
const e = O(this.naturalSize, this.getFrameSize(), t.rotation) * t.zoom;
|
|
626
|
+
W(this.stage.imageLayerEl, t, e), R(this.stage.imgEl, t.filters), this.stage.zoomerEl && (this.stage.zoomerEl.value = String(t.zoom));
|
|
627
|
+
for (const o of this.listeners.change) o(this.getState());
|
|
532
628
|
}
|
|
533
629
|
enableZoomer(t) {
|
|
534
630
|
const e = () => this.setZoom(Number(t.value));
|
|
@@ -539,39 +635,54 @@ class tt {
|
|
|
539
635
|
};
|
|
540
636
|
}
|
|
541
637
|
enableFrameResize() {
|
|
542
|
-
const t =
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
638
|
+
const t = [
|
|
639
|
+
{ name: "top-left", edge: { left: "-5px", top: "-5px" }, signX: -1, signY: -1 },
|
|
640
|
+
{ name: "top-right", edge: { right: "-5px", top: "-5px" }, signX: 1, signY: -1 },
|
|
641
|
+
{ name: "bottom-left", edge: { left: "-5px", bottom: "-5px" }, signX: -1, signY: 1 },
|
|
642
|
+
{ name: "bottom-right", edge: { right: "-5px", bottom: "-5px" }, signX: 1, signY: 1 }
|
|
643
|
+
], e = [];
|
|
644
|
+
for (const o of t) {
|
|
645
|
+
const s = document.createElement("div");
|
|
646
|
+
s.className = `kiri-frame-handle kiri-frame-handle--${o.name}`, Object.assign(s.style, o.edge), this.stage.frameEl.appendChild(s);
|
|
647
|
+
let n = null;
|
|
648
|
+
const l = (h) => {
|
|
649
|
+
h.stopPropagation(), s.setPointerCapture(h.pointerId), n = {
|
|
650
|
+
x: h.clientX,
|
|
651
|
+
y: h.clientY,
|
|
652
|
+
width: this.opts.frame.width,
|
|
653
|
+
height: this.opts.frame.height
|
|
654
|
+
};
|
|
655
|
+
}, c = (h) => {
|
|
656
|
+
if (!n) return;
|
|
657
|
+
const f = (h.clientX - n.x) * 2 * o.signX, u = (h.clientY - n.y) * 2 * o.signY, p = n.width + f, r = n.height + u;
|
|
658
|
+
if (this.opts.lockAspectRatio) {
|
|
659
|
+
const a = n.width / n.height;
|
|
660
|
+
Math.abs(p - n.width) >= Math.abs(r - n.height) * a ? this.setFrameSize(p, p / a) : this.setFrameSize(r * a, r);
|
|
661
|
+
} else
|
|
662
|
+
this.setFrameSize(p, r);
|
|
663
|
+
}, m = () => {
|
|
664
|
+
n = null;
|
|
551
665
|
};
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
e = null;
|
|
558
|
-
};
|
|
559
|
-
t.addEventListener("pointerdown", s), t.addEventListener("pointermove", o), t.addEventListener("pointerup", n), t.addEventListener("pointercancel", n), this.resizeHandle = {
|
|
666
|
+
s.addEventListener("pointerdown", l), s.addEventListener("pointermove", c), s.addEventListener("pointerup", m), s.addEventListener("pointercancel", m), e.push(() => {
|
|
667
|
+
s.removeEventListener("pointerdown", l), s.removeEventListener("pointermove", c), s.removeEventListener("pointerup", m), s.removeEventListener("pointercancel", m), s.remove();
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
this.resizeHandle = {
|
|
560
671
|
destroy() {
|
|
561
|
-
|
|
672
|
+
for (const o of e) o();
|
|
562
673
|
}
|
|
563
674
|
};
|
|
564
675
|
}
|
|
565
676
|
}
|
|
566
|
-
class
|
|
677
|
+
class ft {
|
|
567
678
|
/** @param items An initial queue; more can be added later via `add()`. */
|
|
568
|
-
constructor(t, e = {},
|
|
679
|
+
constructor(t, e = {}, o = []) {
|
|
569
680
|
/** The shared `Kiri` instance. Use its normal methods (drag/zoom/rotate/filters/etc.) to adjust the currently-loaded item. */
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
this.cropper = new
|
|
681
|
+
d(this, "cropper");
|
|
682
|
+
d(this, "items");
|
|
683
|
+
d(this, "index", -1);
|
|
684
|
+
d(this, "captures", []);
|
|
685
|
+
this.cropper = new lt(t, e), this.items = [...o];
|
|
575
686
|
}
|
|
576
687
|
/** Appends an item to the queue. */
|
|
577
688
|
add(t) {
|
|
@@ -588,6 +699,13 @@ class it {
|
|
|
588
699
|
const t = this.items[this.index];
|
|
589
700
|
return await this.cropper.load(t.source, t.loadOptions), !0;
|
|
590
701
|
}
|
|
702
|
+
/** Loads the previous queued image into `cropper`. Returns false when already at the first item (or nothing loaded yet). */
|
|
703
|
+
async previous() {
|
|
704
|
+
if (this.index <= 0) return !1;
|
|
705
|
+
this.index -= 1;
|
|
706
|
+
const t = this.items[this.index];
|
|
707
|
+
return await this.cropper.load(t.source, t.loadOptions), !0;
|
|
708
|
+
}
|
|
591
709
|
/** Metadata for the currently loaded item, or null before the first next() / after exhaustion. */
|
|
592
710
|
current() {
|
|
593
711
|
return this.items[this.index] ?? null;
|
|
@@ -607,7 +725,7 @@ class it {
|
|
|
607
725
|
}
|
|
608
726
|
}
|
|
609
727
|
export {
|
|
610
|
-
|
|
611
|
-
|
|
728
|
+
lt as Kiri,
|
|
729
|
+
ft as KiriBatch
|
|
612
730
|
};
|
|
613
731
|
//# sourceMappingURL=kiri.mjs.map
|