@overtone-art/canvas-editor-core 0.8.2 → 0.8.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/index.js CHANGED
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  LayerManager: () => LayerManager,
40
40
  LayerMaskManager: () => LayerMaskManager,
41
41
  LicenseManager: () => LicenseManager,
42
+ MAX_MASK_LAYERS: () => MAX_MASK_LAYERS,
42
43
  MaskController: () => MaskController,
43
44
  MaskPresetManager: () => MaskPresetManager,
44
45
  MaskRefinementError: () => MaskRefinementError,
@@ -4315,6 +4316,7 @@ function installClip(host, entries, sources, box, absolute) {
4315
4316
 
4316
4317
  // src/masks/store.ts
4317
4318
  var CANVAS_MASK_TARGET = "canvas";
4319
+ var MAX_MASK_LAYERS = 10;
4318
4320
  var DEFAULT_ENTRY = {
4319
4321
  mode: "add",
4320
4322
  linked: true,
@@ -4533,13 +4535,16 @@ var LayerMaskManager = class extends MaskStackStore {
4533
4535
  if (!host) return null;
4534
4536
  const sources = this.unwrap(target, host);
4535
4537
  const entries = this.entriesFor(target, sources);
4538
+ if (entries.length >= MAX_MASK_LAYERS) return null;
4536
4539
  const entry = {
4537
4540
  ...DEFAULT_ENTRY,
4538
4541
  id: generateId(),
4539
4542
  name: options.name ?? "Mask",
4540
4543
  ...options.mode ? { mode: options.mode } : {},
4541
4544
  ...options.linked === void 0 ? {} : { linked: options.linked },
4542
- ...options.meta ? { meta: options.meta } : {}
4545
+ ...options.meta ? { meta: options.meta } : {},
4546
+ ...options.sourceLayer ? { sourceLayer: options.sourceLayer } : {},
4547
+ ...options.sourceObject ? { sourceObject: options.sourceObject } : {}
4543
4548
  };
4544
4549
  if (target === CANVAS_MASK_TARGET) entry.linked = false;
4545
4550
  if (options.fit !== false) {
@@ -4609,6 +4614,52 @@ var LayerMaskManager = class extends MaskStackStore {
4609
4614
  this.commit(target, host, [], []);
4610
4615
  return true;
4611
4616
  }
4617
+ /**
4618
+ * Remove one mask from its host and restore it as an ordinary canvas layer.
4619
+ * Its shape, text, paint and transform survive; only the mask relationship is
4620
+ * removed, so it can be edited through every normal layer property panel.
4621
+ */
4622
+ unmask(target, maskId) {
4623
+ const host = this.host(target);
4624
+ if (!host) return null;
4625
+ const entries = [...this.list(target)];
4626
+ const index = entries.findIndex((entry2) => entry2.id === maskId);
4627
+ if (index === -1) return null;
4628
+ const sources = this.unwrap(target, host);
4629
+ const source = sources[index];
4630
+ if (!source) return null;
4631
+ const entry = entries[index];
4632
+ this.history.beginTransaction();
4633
+ try {
4634
+ this.endEdit(false);
4635
+ entries.splice(index, 1);
4636
+ sources.splice(index, 1);
4637
+ if (!source.absolutePositioned && target !== CANVAS_MASK_TARGET) toCanvasSpace(source, host);
4638
+ source.set({
4639
+ absolutePositioned: false,
4640
+ opacity: entry.sourceObject?.opacity ?? 1,
4641
+ globalCompositeOperation: entry.sourceObject?.globalCompositeOperation ?? "source-over",
4642
+ objectCaching: entry.sourceObject?.objectCaching ?? true
4643
+ });
4644
+ if (this.selected?.maskId === maskId) this.select(null, null);
4645
+ this.commit(target, host, entries, sources, false);
4646
+ const saved = entry.sourceLayer;
4647
+ const restored = this.layers.add(
4648
+ saved?.type ?? layerTypeOf(source),
4649
+ source,
4650
+ saved?.name ?? entry.name
4651
+ );
4652
+ restored.meta = saved?.meta ? structuredClone(saved.meta) : {};
4653
+ this.layers.setVisibility(restored.id, saved?.visible ?? true);
4654
+ this.layers.setLocked(restored.id, saved?.locked ?? false);
4655
+ this.layers.setOpacity(restored.id, saved?.opacity ?? 1);
4656
+ this.layers.select(restored.id);
4657
+ this.history.save();
4658
+ return restored;
4659
+ } finally {
4660
+ this.history.endTransaction();
4661
+ }
4662
+ }
4612
4663
  reorder(target, maskId, index) {
4613
4664
  const host = this.host(target);
4614
4665
  if (!host) return false;
@@ -4683,7 +4734,21 @@ var LayerMaskManager = class extends MaskStackStore {
4683
4734
  const below = index > 0 ? ordered[index - 1] : void 0;
4684
4735
  const resolved = target ?? (below && !below.meta.canvasMask ? below.id : CANVAS_MASK_TARGET);
4685
4736
  if (resolved === layerId) return null;
4737
+ if (this.list(resolved).length >= MAX_MASK_LAYERS) return null;
4686
4738
  const object = layer.fabricObject;
4739
+ const sourceLayer = {
4740
+ type: layer.type,
4741
+ name: layer.name,
4742
+ visible: layer.visible,
4743
+ locked: layer.locked,
4744
+ opacity: layer.opacity,
4745
+ ...Object.keys(layer.meta).length > 0 ? { meta: structuredClone(layer.meta) } : {}
4746
+ };
4747
+ const sourceObject = {
4748
+ opacity: object.opacity ?? 1,
4749
+ globalCompositeOperation: object.globalCompositeOperation ?? "source-over",
4750
+ objectCaching: object.objectCaching
4751
+ };
4687
4752
  if (!object.fill && object.type !== "image") object.set({ fill: "#000000" });
4688
4753
  const stackHost = this.host(resolved);
4689
4754
  const absolute = resolved === CANVAS_MASK_TARGET || needsAbsoluteSpace(this.list(resolved));
@@ -4693,7 +4758,12 @@ var LayerMaskManager = class extends MaskStackStore {
4693
4758
  if (this.canvas.getActiveObject() === object) this.canvas.discardActiveObject();
4694
4759
  this.canvas.remove(object);
4695
4760
  this.layers.remove(layerId);
4696
- const entry = this.add(resolved, object, { name: layer.name, fit: false });
4761
+ const entry = this.add(resolved, object, {
4762
+ name: layer.name,
4763
+ fit: false,
4764
+ sourceLayer,
4765
+ sourceObject
4766
+ });
4697
4767
  return entry ? { target: resolved, entry } : null;
4698
4768
  } finally {
4699
4769
  this.history.endTransaction();
@@ -4771,6 +4841,12 @@ var LayerMaskManager = class extends MaskStackStore {
4771
4841
  return true;
4772
4842
  }
4773
4843
  };
4844
+ function layerTypeOf(object) {
4845
+ if (object.type === "image") return "image";
4846
+ if (object.type === "text" || object.type === "textbox" || object.type === "i-text")
4847
+ return "text";
4848
+ return "shape";
4849
+ }
4774
4850
 
4775
4851
  // src/gradient.ts
4776
4852
  var import_fabric21 = require("fabric");
@@ -4877,7 +4953,7 @@ function readGradientConfig(object) {
4877
4953
  }
4878
4954
 
4879
4955
  // src/editor.ts
4880
- var MIN_ZOOM = 0.1;
4956
+ var MIN_ZOOM = 0.01;
4881
4957
  var MAX_ZOOM = 8;
4882
4958
  function isTaintedCanvasError(error) {
4883
4959
  return error instanceof DOMException && error.name === "SecurityError" || error instanceof Error && /taint|cross-origin|insecure/i.test(error.message);
@@ -6017,6 +6093,7 @@ var AnnotationOverlay = class {
6017
6093
  LayerManager,
6018
6094
  LayerMaskManager,
6019
6095
  LicenseManager,
6096
+ MAX_MASK_LAYERS,
6020
6097
  MaskController,
6021
6098
  MaskPresetManager,
6022
6099
  MaskRefinementError,