@anu3ev/fabric-image-editor 0.1.59 → 0.1.60

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.
Files changed (2) hide show
  1. package/dist/main.js +76 -45
  2. package/package.json +9 -2
package/dist/main.js CHANGED
@@ -2,7 +2,7 @@ var fe = Object.defineProperty, je = Object.defineProperties;
2
2
  var be = Object.getOwnPropertyDescriptors;
3
3
  var H = Object.getOwnPropertySymbols;
4
4
  var ce = Object.prototype.hasOwnProperty, de = Object.prototype.propertyIsEnumerable;
5
- var re = (c, e, t) => e in c ? fe(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t, p = (c, e) => {
5
+ var re = (c, e, t) => e in c ? fe(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t, y = (c, e) => {
6
6
  for (var t in e || (e = {}))
7
7
  ce.call(e, t) && re(c, t, e[t]);
8
8
  if (H)
@@ -35,7 +35,7 @@ var I = (c, e, t) => new Promise((s, n) => {
35
35
  }, o = (d) => d.done ? s(d.value) : Promise.resolve(d.value).then(i, a);
36
36
  o((t = t.apply(c, e)).next());
37
37
  });
38
- import { ActiveSelection as v, util as R, controlsUtils as pe, InteractiveFabricObject as ye, loadSVGFromURL as Ie, FabricImage as Z, Point as _, Rect as ve, Circle as Ae, Triangle as Se, Group as X, Canvas as Ce, Pattern as Ne } from "fabric";
38
+ import { ActiveSelection as v, util as R, controlsUtils as ye, InteractiveFabricObject as pe, loadSVGFromURL as Ie, FabricImage as Z, Point as _, Rect as ve, Circle as Ae, Triangle as Se, Group as X, Canvas as Ce, Pattern as Ne } from "fabric";
39
39
  import { create as De } from "jsondiffpatch";
40
40
  import Le from "diff-match-patch";
41
41
  var we = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict", L = function() {
@@ -143,7 +143,7 @@ class z {
143
143
  */
144
144
  handleCopyEvent(e) {
145
145
  const { ctrlKey: t, metaKey: s, code: n } = e;
146
- !t && !s || n !== "KeyC" || (e.preventDefault(), this.editor.clipboardManager.copy());
146
+ this._shouldIgnoreKeyboardEvent(e) || !t && !s || n !== "KeyC" || (e.preventDefault(), this.editor.clipboardManager.copy());
147
147
  }
148
148
  /**
149
149
  * Обработчик вставки объекта или изображения из буфера обмена.
@@ -162,7 +162,7 @@ class z {
162
162
  handleUndoRedoEvent(e) {
163
163
  return I(this, null, function* () {
164
164
  const { ctrlKey: t, metaKey: s, code: n, repeat: i } = e;
165
- !t && !s || i || !/Mac/i.test(navigator.userAgent) && this.isUndoRedoKeyPressed || (n === "KeyZ" ? (e.preventDefault(), this.isUndoRedoKeyPressed = !0, yield this.editor.historyManager.undo()) : n === "KeyY" && (e.preventDefault(), this.isUndoRedoKeyPressed = !0, yield this.editor.historyManager.redo()));
165
+ this._shouldIgnoreKeyboardEvent(e) || !t && !s || i || !/Mac/i.test(navigator.userAgent) && this.isUndoRedoKeyPressed || (n === "KeyZ" ? (e.preventDefault(), this.isUndoRedoKeyPressed = !0, yield this.editor.historyManager.undo()) : n === "KeyY" && (e.preventDefault(), this.isUndoRedoKeyPressed = !0, yield this.editor.historyManager.redo()));
166
166
  });
167
167
  }
168
168
  /**
@@ -170,8 +170,8 @@ class z {
170
170
  * @param event — объект события
171
171
  * @param event.code — код клавиши
172
172
  */
173
- handleUndoRedoKeyUp({ code: e }) {
174
- ["KeyZ", "KeyY"].includes(e) && (this.isUndoRedoKeyPressed = !1);
173
+ handleUndoRedoKeyUp(e) {
174
+ this._shouldIgnoreKeyboardEvent(e) || ["KeyZ", "KeyY"].includes(e.code) && (this.isUndoRedoKeyPressed = !1);
175
175
  }
176
176
  /**
177
177
  * Обработчик для выделения всех объектов (Ctrl+A).
@@ -181,16 +181,17 @@ class z {
181
181
  * @param event.code — код клавиши
182
182
  */
183
183
  handleSelectAllEvent(e) {
184
+ if (this._shouldIgnoreKeyboardEvent(e)) return;
184
185
  const { ctrlKey: t, metaKey: s, code: n } = e;
185
186
  !t && !s || n !== "KeyA" || (e.preventDefault(), this.editor.selectionManager.selectAll());
186
187
  }
187
188
  /**
188
- * Обработчик для удаления объектов (Delete).
189
+ * Обработчик для удаления объектов (Delete или Backspace).
189
190
  * @param event — объект события
190
191
  * @param event.code — код клавиши
191
192
  */
192
193
  handleDeleteObjectsEvent(e) {
193
- e.code === "Delete" && (e.preventDefault(), this.editor.deletionManager.deleteSelectedObjects());
194
+ this._shouldIgnoreKeyboardEvent(e) || e.code !== "Delete" && e.code !== "Backspace" || (e.preventDefault(), this.editor.deletionManager.deleteSelectedObjects());
194
195
  }
195
196
  /**
196
197
  * Обработчик для нажатия пробела.
@@ -199,7 +200,7 @@ class z {
199
200
  * @param event.code — код клавиши
200
201
  */
201
202
  handleSpaceKeyDown(e) {
202
- if (e.code !== "Space") return;
203
+ if (e.code !== "Space" || this._shouldIgnoreKeyboardEvent(e)) return;
203
204
  const { canvas: t, editor: s, isSpacePressed: n, isDragging: i } = this;
204
205
  n || i || (this.isSpacePressed = !0, e.preventDefault(), t.set({
205
206
  selection: !1,
@@ -219,7 +220,7 @@ class z {
219
220
  * @param event.code — код клавиши
220
221
  */
221
222
  handleSpaceKeyUp(e) {
222
- e.code === "Space" && (this.isSpacePressed = !1, this.isDragging && this.handleCanvasDragEnd(), this.canvas.set({
223
+ e.code !== "Space" || this._shouldIgnoreKeyboardEvent(e) || (this.isSpacePressed = !1, this.isDragging && this.handleCanvasDragEnd(), this.canvas.set({
223
224
  defaultCursor: "default",
224
225
  selection: !0
225
226
  }), this.canvas.setCursor("default"), this.editor.canvasManager.getObjects().forEach((t) => {
@@ -285,6 +286,35 @@ class z {
285
286
  const t = e == null ? void 0 : e.target;
286
287
  t && this.editor.transformManager.resetObject(t);
287
288
  }
289
+ /**
290
+ * Проверяет, должно ли событие клавиатуры быть проигнорировано
291
+ * Возвращает true если фокус находится в поле ввода или элементе из списка игнорируемых селекторов
292
+ * @param event - Событие клавиатуры
293
+ * @returns true если событие должно быть проигнорировано
294
+ */
295
+ _shouldIgnoreKeyboardEvent(e) {
296
+ const t = e.target;
297
+ if (!t) return !1;
298
+ const s = ["input", "textarea", "select"], n = t.tagName.toLowerCase();
299
+ if (s.includes(n) || t.contentEditable === "true") return !0;
300
+ const { keyboardIgnoreSelectors: i } = this.options;
301
+ if (i != null && i.length)
302
+ for (const a of i)
303
+ try {
304
+ if (t.matches && t.matches(a) || t.closest && t.closest(a))
305
+ return !0;
306
+ } catch (o) {
307
+ this.editor.errorManager.emitWarning({
308
+ origin: "Listeners",
309
+ method: "_shouldIgnoreKeyboardEvent",
310
+ code: "INVALID_SELECTOR",
311
+ // eslint-disable-next-line max-len
312
+ message: `Invalid keyboard ignore selector: "${a}". Error: ${o.message}`,
313
+ data: o
314
+ });
315
+ }
316
+ return !1;
317
+ }
288
318
  /**
289
319
  * Метод для удаления всех слушателей
290
320
  */
@@ -378,17 +408,17 @@ class Te {
378
408
  this.worker.terminate();
379
409
  }
380
410
  }
381
- const N = 12, ke = 2, Q = 8, J = 20, xe = 100, $ = 20, K = 8, Be = 100, q = 32, ee = 1, Ze = "#2B2D33", te = "#3D8BF4", se = "#FFFFFF";
411
+ const N = 12, ke = 2, Q = 8, $ = 20, xe = 100, J = 20, K = 8, Be = 100, q = 32, ee = 1, Ze = "#2B2D33", te = "#3D8BF4", se = "#FFFFFF";
382
412
  function W(c, e, t, s, n) {
383
413
  const i = N, a = ke;
384
414
  c.save(), c.translate(e, t), c.rotate(R.degreesToRadians(n.angle)), c.fillStyle = se, c.strokeStyle = te, c.lineWidth = ee, c.beginPath(), c.roundRect(-12 / 2, -12 / 2, i, i, a), c.fill(), c.stroke(), c.restore();
385
415
  }
386
416
  function he(c, e, t, s, n) {
387
- const i = Q, a = J, o = xe;
417
+ const i = Q, a = $, o = xe;
388
418
  c.save(), c.translate(e, t), c.rotate(R.degreesToRadians(n.angle)), c.fillStyle = se, c.strokeStyle = te, c.lineWidth = ee, c.beginPath(), c.roundRect(-8 / 2, -20 / 2, i, a, o), c.fill(), c.stroke(), c.restore();
389
419
  }
390
420
  function ge(c, e, t, s, n) {
391
- const i = $, a = K, o = Be;
421
+ const i = J, a = K, o = Be;
392
422
  c.save(), c.translate(e, t), c.rotate(R.degreesToRadians(n.angle)), c.fillStyle = se, c.strokeStyle = te, c.lineWidth = ee, c.beginPath(), c.roundRect(-20 / 2, -8 / 2, i, a, o), c.fill(), c.stroke(), c.restore();
393
423
  }
394
424
  const Ue = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE4Ljc1IDQuMzc1djMuNzVhLjYyNS42MjUgMCAwIDEtLjYyNS42MjVoLTMuNzVhLjYyNS42MjUgMCAwIDEgMC0xLjI1aDIuMTRsLTIuMDc3LTEuOTAzLS4wMi0uMDE5YTYuMjUgNi4yNSAwIDEgMC0uMTMgOC45NjcuNjI2LjYyNiAwIDAgMSAuODYuOTA5QTcuNDU2IDcuNDU2IDAgMCAxIDEwIDE3LjVoLS4xMDNhNy41IDcuNSAwIDEgMSA1LjM5Ni0xMi44MTJMMTcuNSA2LjcwM1Y0LjM3NWEuNjI1LjYyNSAwIDAgMSAxLjI1IDBaIi8+PC9zdmc+", ue = new Image();
@@ -431,28 +461,28 @@ const Re = {
431
461
  ml: {
432
462
  render: he,
433
463
  sizeX: Q,
434
- sizeY: J,
464
+ sizeY: $,
435
465
  offsetX: 0,
436
466
  offsetY: 0
437
467
  },
438
468
  mr: {
439
469
  render: he,
440
470
  sizeX: Q,
441
- sizeY: J,
471
+ sizeY: $,
442
472
  offsetX: 0,
443
473
  offsetY: 0
444
474
  },
445
475
  // Середина горизонталей
446
476
  mt: {
447
477
  render: ge,
448
- sizeX: $,
478
+ sizeX: J,
449
479
  sizeY: K,
450
480
  offsetX: 0,
451
481
  offsetY: 0
452
482
  },
453
483
  mb: {
454
484
  render: ge,
455
- sizeX: $,
485
+ sizeX: J,
456
486
  sizeY: K,
457
487
  offsetX: 0,
458
488
  offsetY: 0
@@ -468,7 +498,7 @@ const Re = {
468
498
  };
469
499
  class He {
470
500
  static apply() {
471
- const e = pe.createObjectDefaultControls();
501
+ const e = ye.createObjectDefaultControls();
472
502
  Object.entries(Re).forEach(([t, s]) => {
473
503
  Object.assign(e[t], {
474
504
  render: s.render,
@@ -480,7 +510,7 @@ class He {
480
510
  var l;
481
511
  (l = a.target.canvas) == null || l.setCursor("grabbing");
482
512
  });
483
- }), ye.ownDefaults.controls = e;
513
+ }), pe.ownDefaults.controls = e;
484
514
  }
485
515
  }
486
516
  const Ye = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNi44NzUgMi41YS42MjUuNjI1IDAgMCAwLS42MjUuNjI0VjYuMjVIMy4xMjVhLjYyNS42MjUgMCAwIDAtLjYyNS42MjV2MTBjMCAuMzQ1LjI4LjYyNS42MjUuNjI1aDEwYy4zNDUgMCAuNjI1LS4yOC42MjUtLjYyNXYtMy4xMjZoMy4xMjVjLjM0NSAwIC42MjUtLjI4LjYyNS0uNjI1di0xMGEuNjI1LjYyNSAwIDAgMC0uNjI1LS42MjVoLTEwWm02Ljg3NSAxMGgyLjVWMy43NUg3LjV2Mi41aDUuNjI1Yy4zNDUgMCAuNjI1LjI4LjYyNS42MjV2NS42MjRabS0xMCAzLjc1VjcuNWg4Ljc1djguNzVIMy43NVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==", We = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMi41IDcuNWMwLS42OS41Ni0xLjI1IDEuMjUtMS4yNWgxMi41Yy42OSAwIDEuMjUuNTYgMS4yNSAxLjI1djguNzVjMCAuNjktLjU2IDEuMjUtMS4yNSAxLjI1SDMuNzVjLS42OSAwLTEuMjUtLjU2LTEuMjUtMS4yNVY3LjVabTEzLjc1IDBIMy43NXY4Ljc1aDEyLjVWNy41WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTAgMS44NzVhMi4xODggMi4xODggMCAwIDAtMi4xODggMi4xODh2Mi44MTJhLjYyNS42MjUgMCAxIDEtMS4yNSAwVjQuMDYyYTMuNDM3IDMuNDM3IDAgMSAxIDYuODc1IDB2Mi44MTNhLjYyNS42MjUgMCAxIDEtMS4yNSAwVjQuMDYyQTIuMTg4IDIuMTg4IDAgMCAwIDEwIDEuODc2WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTEwIDEyLjgxM2EuOTM3LjkzNyAwIDEgMCAwLTEuODc1LjkzNy45MzcgMCAwIDAgMCAxLjg3NFoiLz48L3N2Zz4=", _e = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE2LjI1IDYuMjVINy41VjQuMzc1YTIuNSAyLjUgMCAwIDEgMi41LTIuNWMxLjIgMCAyLjI4MS44NiAyLjUxMiAyYS42MjUuNjI1IDAgMCAwIDEuMjI2LS4yNWMtLjM1NC0xLjczOC0xLjkyNS0zLTMuNzM4LTNhMy43NTQgMy43NTQgMCAwIDAtMy43NSAzLjc1VjYuMjVoLTIuNUExLjI1IDEuMjUgMCAwIDAgMi41IDcuNXY4Ljc1YTEuMjUgMS4yNSAwIDAgMCAxLjI1IDEuMjVoMTIuNWExLjI1IDEuMjUgMCAwIDAgMS4yNS0xLjI1VjcuNWExLjI1IDEuMjUgMCAwIDAtMS4yNS0xLjI1Wm0wIDEwSDMuNzVWNy41aDEyLjV2OC43NVptLTUuMzEzLTQuMzc1YS45MzcuOTM3IDAgMSAxLTEuODc0IDAgLjkzNy45MzcgMCAwIDEgMS44NzQgMFoiLz48L3N2Zz4K", Pe = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTIuNSA4LjEyNSAxMCAxMi41bDcuNS00LjM3NUwxMCAzLjc1IDIuNSA4LjEyNVoiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik05LjY4NSAzLjIxYS42MjUuNjI1IDAgMCAxIC42MyAwbDcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMSAwIDEuMDhsLTcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtNy41LTQuMzc1YS42MjUuNjI1IDAgMCAxIDAtMS4wOGw3LjUtNC4zNzVaTTMuNzQgOC4xMjUgMTAgMTEuNzc2bDYuMjYtMy42NTFMMTAgNC40NzQgMy43NCA4LjEyNVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTUuNCA5LjQ2YS42MjUuNjI1IDAgMCAxIC42MyAwTDEwIDExLjc3NmwzLjk3LTIuMzE2YS42MjUuNjI1IDAgMCAxIC42MyAwbDMuMjE1IDEuODc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4TDUuNCA5LjQ2Wm0tMS42NiAyLjQxNUwxMCAxNS41MjZsNi4yNi0zLjY1MS0xLjk3NC0xLjE1MS0zLjk3MSAyLjMxNmEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtMy45Ny0yLjMxNi0xLjk3NSAxLjE1MVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==", Fe = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOS42ODUgMy4yMWEuNjI1LjYyNSAwIDAgMSAuNjMgMGw3LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEgMCAxLjA4bC03LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTcuNS00LjM3NWEuNjI1LjYyNSAwIDAgMSAwLTEuMDhsNy41LTQuMzc1Wk0zLjc0IDguMTI1IDEwIDExLjc3Nmw2LjI2LTMuNjUxTDEwIDQuNDc0IDMuNzQgOC4xMjVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjcxNCAxMCAxMCAxMi41bDQuMjg2LTIuNSAzLjIxNCAxLjg3NUwxMCAxNi4yNWwtNy41LTQuMzc1TDUuNzE0IDEwWiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNS40IDkuNDZhLjYyNS42MjUgMCAwIDEgLjYzIDBMMTAgMTEuNzc2bDMuOTctMi4zMTZhLjYyNS42MjUgMCAwIDEgLjYzIDBsMy4yMTUgMS44NzVhLjYyNS42MjUgMCAwIDEgMCAxLjA4bC03LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTcuNS00LjM3NWEuNjI1LjYyNSAwIDAgMSAwLTEuMDhMNS40IDkuNDZabS0xLjY2IDIuNDE1TDEwIDE1LjUyNmw2LjI2LTMuNjUxLTEuOTc0LTEuMTUxLTMuOTcxIDIuMzE2YS42MjUuNjI1IDAgMCAxLS42MyAwbC0zLjk3LTIuMzE2LTEuOTc1IDEuMTUxWiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+", Ve = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTIuNSA2LjI1IDcuNSA0LjM3NSA3LjUtNC4zNzVMMTAgMS44NzUgMi41IDYuMjVaIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOS42ODUgMS4zMzVhLjYyNS42MjUgMCAwIDEgLjYzIDBsNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4bDcuNS00LjM3NVpNMy43NCA2LjI1IDEwIDkuOTAxbDYuMjYtMy42NTFMMTAgMi41OTkgMy43NCA2LjI1WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNS40IDExLjMzNWEuNjI1LjYyNSAwIDAgMSAuNjMgMEwxMCAxMy42NTFsMy45Ny0yLjMxNmEuNjI1LjYyNSAwIDAgMSAuNjMgMGwzLjIxNSAxLjg3NWEuNjI1LjYyNSAwIDAgMSAwIDEuMDhsLTcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtNy41LTQuMzc1YS42MjUuNjI1IDAgMCAxIDAtMS4wOEw1LjQgMTEuMzM1Wk0zLjc0IDEzLjc1IDEwIDE3LjQwMWw2LjI2LTMuNjUxLTEuOTc0LTEuMTUxLTMuOTcxIDIuMzE2YS42MjUuNjI1IDAgMCAxLS42MyAwbC0zLjk3LTIuMzE2TDMuNzQgMTMuNzVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjQgNy41ODVhLjYyNS42MjUgMCAwIDEgLjYzIDBMMTAgOS45MDFsMy45Ny0yLjMxNmEuNjI1LjYyNSAwIDAgMSAuNjMgMGwzLjIxNSAxLjg3NWEuNjI1LjYyNSAwIDAgMSAwIDEuMDhsLTcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtNy41LTQuMzc1YS42MjUuNjI1IDAgMCAxIDAtMS4wOEw1LjQgNy41ODVaTTMuNzQgMTAgMTAgMTMuNjUxIDE2LjI2IDEwbC0xLjk3NC0xLjE1MS0zLjk3MSAyLjMxNmEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtMy45Ny0yLjMxNkwzLjc0IDEwWiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+", Ge = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMS45NiAxMy40MzVhLjYyNS42MjUgMCAwIDEgLjg1NS0uMjI1TDEwIDE3LjQwMWw3LjE4NS00LjE5YS42MjUuNjI1IDAgMCAxIC42MyAxLjA3OWwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEtLjIyNS0uODU1Wk05LjY4NSAxLjMzNWEuNjI1LjYyNSAwIDAgMSAuNjMgMGw3LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEgMCAxLjA4bC03LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTcuNS00LjM3NWEuNjI1LjYyNSAwIDAgMSAwLTEuMDhsNy41LTQuMzc1Wk0zLjc0IDYuMjUgMTAgOS45MDFsNi4yNi0zLjY1MUwxMCAyLjU5OSAzLjc0IDYuMjVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Im01LjcxNCAxMS44NzUgNC4yODYgMi41IDQuMjg2LTIuNUwxNy41IDEzLjc1IDEwIDE4LjEyNSAyLjUgMTMuNzVsMy4yMTQtMS44NzVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjQgMTEuMzM1YS42MjUuNjI1IDAgMCAxIC42MyAwTDEwIDEzLjY1MWwzLjk3LTIuMzE2YS42MjUuNjI1IDAgMCAxIC42MyAwbDMuMjE1IDEuODc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4TDUuNCAxMS4zMzVaTTMuNzQgMTMuNzUgMTAgMTcuNDAxbDYuMjYtMy42NTEtMS45NzQtMS4xNTEtMy45NzEgMi4zMTZhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTMuOTctMi4zMTZMMy43NCAxMy43NVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTUuNCA3LjU4NWEuNjI1LjYyNSAwIDAgMSAuNjMgMEwxMCA5LjkwMWwzLjk3LTIuMzE2YS42MjUuNjI1IDAgMCAxIC42MyAwbDMuMjE1IDEuODc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4TDUuNCA3LjU4NVpNMy43NCAxMCAxMCAxMy42NTEgMTYuMjYgMTBsLTEuOTc0LTEuMTUxLTMuOTcxIDIuMzE2YS42MjUuNjI1IDAgMCAxLS42MyAwbC0zLjk3LTIuMzE2TDMuNzQgMTBaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=", Xe = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI0VDNEU0MCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOC4xMjUgMS4yNUExLjg3NSAxLjg3NSAwIDAgMCA2LjI1IDMuMTI1di42MjVIMy4xMjVhLjYyNS42MjUgMCAwIDAgMCAxLjI1aC42MjV2MTEuMjVBMS4yNSAxLjI1IDAgMCAwIDUgMTcuNWgxMGExLjI1IDEuMjUgMCAwIDAgMS4yNS0xLjI1VjVoLjYyNWEuNjI1LjYyNSAwIDAgMCAwLTEuMjVIMTMuNzV2LS42MjVhMS44NzUgMS44NzUgMCAwIDAtMS44NzUtMS44NzVoLTMuNzVabTQuMzc1IDIuNXYtLjYyNWEuNjI1LjYyNSAwIDAgMC0uNjI1LS42MjVoLTMuNzVhLjYyNS42MjUgMCAwIDAtLjYyNS42MjV2LjYyNWg1Wk01IDE2LjI1VjVoMTB2MTEuMjVINVpNOC4xMjUgNy41Yy4zNDUgMCAuNjI1LjI4LjYyNS42MjV2NWEuNjI1LjYyNSAwIDEgMS0xLjI1IDB2LTVjMC0uMzQ1LjI4LS42MjUuNjI1LS42MjVabTQuMzc1IDUuNjI1di01YS42MjUuNjI1IDAgMCAwLTEuMjUgMHY1YS42MjUuNjI1IDAgMSAwIDEuMjUgMFoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==", U = {
@@ -595,11 +625,11 @@ class Qe {
595
625
  _initToolbar() {
596
626
  if (!this.options.showToolbar) return;
597
627
  const e = this.options.toolbar || {};
598
- this.config = le(p(p({}, U), e), {
599
- style: p(p({}, U.style), e.style || {}),
600
- btnStyle: p(p({}, U.btnStyle), e.btnStyle || {}),
601
- icons: p(p({}, U.icons), e.icons || {}),
602
- handlers: p(p({}, U.handlers), e.handlers || {})
628
+ this.config = le(y(y({}, U), e), {
629
+ style: y(y({}, U.style), e.style || {}),
630
+ btnStyle: y(y({}, U.btnStyle), e.btnStyle || {}),
631
+ icons: y(y({}, U.icons), e.icons || {}),
632
+ handlers: y(y({}, U.handlers), e.handlers || {})
603
633
  }), this.currentTarget = null, this.currentLocked = !1, this.isTransforming = !1, this._onMouseDown = this._handleMouseDown.bind(this), this._onObjectMoving = this._startTransform.bind(this), this._onObjectScaling = this._startTransform.bind(this), this._onObjectRotating = this._startTransform.bind(this), this._onMouseUp = this._endTransform.bind(this), this._onObjectModified = this._endTransform.bind(this), this._onSelectionChange = this._updateToolbar.bind(this), this._onSelectionClear = () => {
604
634
  this.el.style.display = "none";
605
635
  }, this._createDOM(), this._bindEvents();
@@ -702,7 +732,7 @@ class Qe {
702
732
  this.el.removeEventListener("mouseover", this._onBtnOver), this.el.removeEventListener("mouseout", this._onBtnOut), this.canvas.off("mouse:down", this._onMouseDown), this.canvas.off("object:moving", this._onObjectMoving), this.canvas.off("object:scaling", this._onObjectScaling), this.canvas.off("object:rotating", this._onObjectRotating), this.canvas.off("mouse:up", this._onMouseUp), this.canvas.off("object:modified", this._onObjectModified), this.canvas.off("selection:created", this._onSelectionChange), this.canvas.off("selection:updated", this._onSelectionChange), this.canvas.off("after:render", this._onSelectionChange), this.canvas.off("selection:cleared", this._onSelectionClear), this.el.remove();
703
733
  }
704
734
  }
705
- class Je {
735
+ class $e {
706
736
  constructor({ editor: e }) {
707
737
  this.editor = e, this.canvas = e.canvas, this._historySuspendCount = 0, this.baseState = null, this.patches = [], this.currentIndex = 0, this.maxHistoryLength = e.options.maxHistoryLength, this.totalChangesCount = 0, this.baseStateChangesCount = 0, this._createDiffPatcher();
708
738
  }
@@ -905,7 +935,7 @@ class Je {
905
935
  });
906
936
  }
907
937
  }
908
- const $e = 0.1, Ke = 2, qe = 0.1, et = 90, x = 16, B = 16, O = 4096, T = 4096;
938
+ const Je = 0.1, Ke = 2, qe = 0.1, et = 90, x = 16, B = 16, O = 4096, T = 4096;
909
939
  class D {
910
940
  constructor({ editor: e }) {
911
941
  this.editor = e, this.options = e.options, this._createdBlobUrls = [], this.acceptContentTypes = this.editor.options.acceptContentTypes, this.acceptFormats = this.getAllowedFormatsFromContentTypes();
@@ -1054,14 +1084,14 @@ class D {
1054
1084
  o.setCoords();
1055
1085
  const { left: g, top: u, width: m, height: M } = o.getBoundingRect(), f = yield a.clone(["id", "format", "locked"]);
1056
1086
  ["image/jpg", "image/jpeg"].includes(l) && (f.backgroundColor = "#ffffff");
1057
- const j = f.getObjects().find((y) => y.id === o.id);
1087
+ const j = f.getObjects().find((p) => p.id === o.id);
1058
1088
  j && (j.visible = !1), f.viewportTransform = [1, 0, 0, 1, -g, -u], f.setDimensions({ width: m, height: M }, { backstoreOnly: !0 }), f.renderAll();
1059
- const A = f.getObjects().filter((y) => y.format).every((y) => y.format === "svg");
1089
+ const A = f.getObjects().filter((p) => p.format).every((p) => p.format === "svg");
1060
1090
  if (h === "svg" && A) {
1061
- const y = f.toSVG();
1091
+ const p = f.toSVG();
1062
1092
  f.dispose();
1063
1093
  const C = {
1064
- image: D._exportSVGStringAsFile(y, {
1094
+ image: D._exportSVGStringAsFile(p, {
1065
1095
  exportAsBase64: n,
1066
1096
  exportAsBlob: i,
1067
1097
  fileName: t
@@ -1072,19 +1102,19 @@ class D {
1072
1102
  };
1073
1103
  return a.fire("editor:canvas-exported", C), C;
1074
1104
  }
1075
- const b = yield new Promise((y, k) => {
1105
+ const b = yield new Promise((p, k) => {
1076
1106
  f.getElement().toBlob((C) => {
1077
- C ? y(C) : k(new Error("Failed to create Blob from canvas"));
1107
+ C ? p(C) : k(new Error("Failed to create Blob from canvas"));
1078
1108
  });
1079
1109
  });
1080
1110
  if (f.dispose(), i) {
1081
- const y = {
1111
+ const p = {
1082
1112
  image: b,
1083
1113
  format: h,
1084
1114
  contentType: l,
1085
1115
  fileName: t
1086
1116
  };
1087
- return a.fire("editor:canvas-exported", y), y;
1117
+ return a.fire("editor:canvas-exported", p), p;
1088
1118
  }
1089
1119
  const S = yield createImageBitmap(b), w = yield d.post(
1090
1120
  "toDataURL",
@@ -1115,13 +1145,13 @@ class D {
1115
1145
  return a.fire("editor:canvas-exported", ae), ae;
1116
1146
  }
1117
1147
  if (n) {
1118
- const y = {
1148
+ const p = {
1119
1149
  image: w,
1120
1150
  format: h,
1121
1151
  contentType: l,
1122
1152
  fileName: t
1123
1153
  };
1124
- return a.fire("editor:canvas-exported", y), y;
1154
+ return a.fire("editor:canvas-exported", p), p;
1125
1155
  }
1126
1156
  const E = h === "svg" && !A ? t.replace(/\.[^/.]+$/, ".png") : t, ie = {
1127
1157
  image: new File([b], E, { type: l }),
@@ -1730,7 +1760,7 @@ class tt {
1730
1760
  }
1731
1761
  class st {
1732
1762
  constructor({ editor: e }) {
1733
- this.editor = e, this.options = e.options, this.minZoom = this.options.minZoom || $e, this.maxZoom = this.options.maxZoom || Ke, this.defaultZoom = this.options.defaultScale, this.maxZoomFactor = this.options.maxZoomFactor;
1763
+ this.editor = e, this.options = e.options, this.minZoom = this.options.minZoom || Je, this.maxZoom = this.options.maxZoom || Ke, this.defaultZoom = this.options.defaultScale, this.maxZoomFactor = this.options.maxZoomFactor;
1734
1764
  }
1735
1765
  /**
1736
1766
  * Метод рассчитывает и применяет зум по умолчанию для монтажной области редактора.
@@ -2179,7 +2209,7 @@ class it {
2179
2209
  "height",
2180
2210
  "fill"
2181
2211
  ]);
2182
- const { canvas: g } = this.editor, u = new ve(p({
2212
+ const { canvas: g } = this.editor, u = new ve(y({
2183
2213
  id: e,
2184
2214
  left: t,
2185
2215
  top: s,
@@ -2219,7 +2249,7 @@ class it {
2219
2249
  "radius",
2220
2250
  "fill"
2221
2251
  ]);
2222
- const { canvas: h } = this.editor, g = new Ae(p({
2252
+ const { canvas: h } = this.editor, g = new Ae(y({
2223
2253
  id: e,
2224
2254
  left: t,
2225
2255
  top: s,
@@ -2261,7 +2291,7 @@ class it {
2261
2291
  "height",
2262
2292
  "fill"
2263
2293
  ]);
2264
- const { canvas: g } = this.editor, u = new Se(p({
2294
+ const { canvas: g } = this.editor, u = new Se(y({
2265
2295
  id: e,
2266
2296
  left: t,
2267
2297
  top: s,
@@ -2650,7 +2680,7 @@ class V {
2650
2680
  message: a,
2651
2681
  data: n
2652
2682
  };
2653
- this._buffer.push(p({
2683
+ this._buffer.push(y({
2654
2684
  type: "editor:error"
2655
2685
  }, o)), this.editor.canvas.fire("editor:error", o);
2656
2686
  }
@@ -2678,7 +2708,7 @@ class V {
2678
2708
  message: a,
2679
2709
  data: i
2680
2710
  };
2681
- this._buffer.push(p({
2711
+ this._buffer.push(y({
2682
2712
  type: "editor:warning"
2683
2713
  }, o)), this.editor.canvas.fire("editor:warning", o);
2684
2714
  }
@@ -2719,7 +2749,7 @@ class ne {
2719
2749
  scaleType: r,
2720
2750
  _onReadyCallback: l
2721
2751
  } = this.options;
2722
- if (He.apply(), this.canvas = new Ce(this.containerId, this.options), this.moduleLoader = new Ee(), this.workerManager = new Te(), this.errorManager = new V({ editor: this }), this.historyManager = new Je({ editor: this }), this.toolbar = new Qe({ editor: this }), this.transformManager = new st({ editor: this }), this.canvasManager = new tt({ editor: this }), this.imageManager = new D({ editor: this }), this.layerManager = new P({ editor: this }), this.shapeManager = new it({ editor: this }), this.interactionBlocker = new nt({ editor: this }), this.clipboardManager = new at({ editor: this }), this.objectLockManager = new F({ editor: this }), this.groupingManager = new ot({ editor: this }), this.selectionManager = new rt({ editor: this }), this.deletionManager = new ct({ editor: this }), this._createMontageArea(), this._createClippingArea(), this.listeners = new z({ editor: this, options: this.options }), this.canvasManager.setEditorContainerWidth(e), this.canvasManager.setEditorContainerHeight(t), this.canvasManager.setCanvasWrapperWidth(s), this.canvasManager.setCanvasWrapperHeight(n), this.canvasManager.setCanvasCSSWidth(i), this.canvasManager.setCanvasCSSHeight(a), o != null && o.source) {
2752
+ if (He.apply(), this.canvas = new Ce(this.containerId, this.options), this.moduleLoader = new Ee(), this.workerManager = new Te(), this.errorManager = new V({ editor: this }), this.historyManager = new $e({ editor: this }), this.toolbar = new Qe({ editor: this }), this.transformManager = new st({ editor: this }), this.canvasManager = new tt({ editor: this }), this.imageManager = new D({ editor: this }), this.layerManager = new P({ editor: this }), this.shapeManager = new it({ editor: this }), this.interactionBlocker = new nt({ editor: this }), this.clipboardManager = new at({ editor: this }), this.objectLockManager = new F({ editor: this }), this.groupingManager = new ot({ editor: this }), this.selectionManager = new rt({ editor: this }), this.deletionManager = new ct({ editor: this }), this._createMontageArea(), this._createClippingArea(), this.listeners = new z({ editor: this, options: this.options }), this.canvasManager.setEditorContainerWidth(e), this.canvasManager.setEditorContainerHeight(t), this.canvasManager.setCanvasWrapperWidth(s), this.canvasManager.setCanvasWrapperHeight(n), this.canvasManager.setCanvasCSSWidth(i), this.canvasManager.setCanvasCSSHeight(a), o != null && o.source) {
2723
2753
  const {
2724
2754
  source: h,
2725
2755
  scale: g = `image-${r}`,
@@ -2884,10 +2914,11 @@ const lt = {
2884
2914
  undoRedoByHotKeys: !0,
2885
2915
  selectAllByHotkey: !0,
2886
2916
  deleteObjectsByHotkey: !0,
2887
- resetObjectFitByDoubleClick: !0
2917
+ resetObjectFitByDoubleClick: !0,
2918
+ keyboardIgnoreSelectors: []
2888
2919
  };
2889
2920
  function bt(c, e = {}) {
2890
- const t = p(p({}, lt), e), s = document.getElementById(c);
2921
+ const t = y(y({}, lt), e), s = document.getElementById(c);
2891
2922
  if (!s)
2892
2923
  return Promise.reject(new Error(`Контейнер с ID "${c}" не найден.`));
2893
2924
  const n = document.createElement("canvas");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anu3ev/fabric-image-editor",
3
- "version": "0.1.59",
3
+ "version": "0.1.60",
4
4
  "description": "JavaScript image editor built on FabricJS, allowing you to create instances with an integrated montage area and providing an API to modify and manage state.",
5
5
  "module": "dist/main.js",
6
6
  "files": [
@@ -14,12 +14,15 @@
14
14
  "build": "vite build --config vite.config.prod.js",
15
15
  "build:docs": "vite build --config vite.config.docs.js",
16
16
  "preview": "vite preview",
17
- "lint": "eslint \"src/**/*.{js,ts}\""
17
+ "lint": "eslint \"src/**/*.{js,ts}\"",
18
+ "test": "jest --coverage",
19
+ "test:watch": "jest --watch"
18
20
  },
19
21
  "devDependencies": {
20
22
  "@babel/core": "^7.26.7",
21
23
  "@babel/preset-env": "^7.26.7",
22
24
  "@eslint/js": "^9.16.0",
25
+ "@types/jest": "^30.0.0",
23
26
  "@typescript-eslint/eslint-plugin": "^8.36.0",
24
27
  "@typescript-eslint/parser": "^8.36.0",
25
28
  "eslint": "^8.57.1",
@@ -31,7 +34,11 @@
31
34
  "eslint-plugin-sort-keys-fix": "^1.1.2",
32
35
  "eslint-plugin-vue": "^9.32.0",
33
36
  "globals": "^15.13.0",
37
+ "jest": "^29.7.0",
38
+ "jest-environment-jsdom": "^29.7.0",
34
39
  "prettier": "^3.4.2",
40
+ "ts-jest": "^29.4.1",
41
+ "ts-node": "^10.9.2",
35
42
  "vite": "^6.3.5",
36
43
  "vite-bundle-analyzer": "^0.21.0",
37
44
  "vite-plugin-babel": "^1.3.0",