@pooder/kit 6.0.0 → 6.0.1

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
@@ -1589,6 +1589,34 @@ function getPathBounds(pathData) {
1589
1589
  // src/extensions/image.ts
1590
1590
  var IMAGE_OBJECT_LAYER_ID = "image.user";
1591
1591
  var IMAGE_OVERLAY_LAYER_ID = "image-overlay";
1592
+ var IMAGE_DEFAULT_CONTROL_CAPABILITIES = [
1593
+ "rotate",
1594
+ "scale"
1595
+ ];
1596
+ var IMAGE_CONTROL_DESCRIPTORS = [
1597
+ {
1598
+ key: "tl",
1599
+ capability: "rotate",
1600
+ create: () => new import_fabric2.Control({
1601
+ x: -0.5,
1602
+ y: -0.5,
1603
+ actionName: "rotate",
1604
+ actionHandler: import_fabric2.controlsUtils.rotationWithSnapping,
1605
+ cursorStyleHandler: import_fabric2.controlsUtils.rotationStyleHandler
1606
+ })
1607
+ },
1608
+ {
1609
+ key: "br",
1610
+ capability: "scale",
1611
+ create: () => new import_fabric2.Control({
1612
+ x: 0.5,
1613
+ y: 0.5,
1614
+ actionName: "scale",
1615
+ actionHandler: import_fabric2.controlsUtils.scalingEqually,
1616
+ cursorStyleHandler: import_fabric2.controlsUtils.scaleCursorStyleHandler
1617
+ })
1618
+ }
1619
+ ];
1592
1620
  var ImageTool = class {
1593
1621
  constructor() {
1594
1622
  this.id = "pooder.kit.image";
@@ -1607,6 +1635,7 @@ var ImageTool = class {
1607
1635
  this.renderSeq = 0;
1608
1636
  this.imageSpecs = [];
1609
1637
  this.overlaySpecs = [];
1638
+ this.imageControlsByCapabilityKey = /* @__PURE__ */ new Map();
1610
1639
  this.onToolActivated = (event) => {
1611
1640
  const before = this.isToolActive;
1612
1641
  this.syncToolActiveFromWorkbench(event.id);
@@ -1771,7 +1800,10 @@ var ImageTool = class {
1771
1800
  this.updateImages();
1772
1801
  return;
1773
1802
  }
1774
- if (e.key.startsWith("size.") || e.key.startsWith("image.frame.")) {
1803
+ if (e.key.startsWith("size.") || e.key.startsWith("image.frame.") || e.key.startsWith("image.control.")) {
1804
+ if (e.key.startsWith("image.control.")) {
1805
+ this.imageControlsByCapabilityKey.clear();
1806
+ }
1775
1807
  this.updateImages();
1776
1808
  }
1777
1809
  });
@@ -1799,6 +1831,7 @@ var ImageTool = class {
1799
1831
  this.cropShapeHatchPatternKey = void 0;
1800
1832
  this.imageSpecs = [];
1801
1833
  this.overlaySpecs = [];
1834
+ this.imageControlsByCapabilityKey.clear();
1802
1835
  this.clearRenderedImages();
1803
1836
  (_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
1804
1837
  this.renderProducerDisposable = void 0;
@@ -1821,6 +1854,90 @@ var ImageTool = class {
1821
1854
  isImageEditingVisible() {
1822
1855
  return this.isToolActive || this.isImageSelectionActive || !!this.focusedImageId;
1823
1856
  }
1857
+ getEnabledImageControlCapabilities() {
1858
+ return IMAGE_DEFAULT_CONTROL_CAPABILITIES;
1859
+ }
1860
+ getImageControls(capabilities) {
1861
+ const normalized = [...new Set(capabilities)].sort();
1862
+ const cacheKey = normalized.join("|");
1863
+ const cached = this.imageControlsByCapabilityKey.get(cacheKey);
1864
+ if (cached) {
1865
+ return cached;
1866
+ }
1867
+ const enabled = new Set(normalized);
1868
+ const controls = {};
1869
+ IMAGE_CONTROL_DESCRIPTORS.forEach((descriptor) => {
1870
+ if (!enabled.has(descriptor.capability)) return;
1871
+ controls[descriptor.key] = descriptor.create();
1872
+ });
1873
+ this.imageControlsByCapabilityKey.set(cacheKey, controls);
1874
+ return controls;
1875
+ }
1876
+ getImageControlVisualConfig() {
1877
+ var _a, _b, _c, _d;
1878
+ const cornerSizeRaw = Number(
1879
+ (_a = this.getConfig("image.control.cornerSize", 14)) != null ? _a : 14
1880
+ );
1881
+ const touchCornerSizeRaw = Number(
1882
+ (_b = this.getConfig("image.control.touchCornerSize", 24)) != null ? _b : 24
1883
+ );
1884
+ const borderScaleFactorRaw = Number(
1885
+ (_c = this.getConfig("image.control.borderScaleFactor", 1.5)) != null ? _c : 1.5
1886
+ );
1887
+ const paddingRaw = Number(
1888
+ (_d = this.getConfig("image.control.padding", 0)) != null ? _d : 0
1889
+ );
1890
+ const cornerStyleRaw = this.getConfig(
1891
+ "image.control.cornerStyle",
1892
+ "circle"
1893
+ ) || "circle";
1894
+ const cornerStyle = cornerStyleRaw === "rect" ? "rect" : "circle";
1895
+ return {
1896
+ cornerSize: Number.isFinite(cornerSizeRaw) ? Math.max(4, Math.min(64, cornerSizeRaw)) : 14,
1897
+ touchCornerSize: Number.isFinite(touchCornerSizeRaw) ? Math.max(8, Math.min(96, touchCornerSizeRaw)) : 24,
1898
+ cornerStyle,
1899
+ cornerColor: this.getConfig("image.control.cornerColor", "#ffffff") || "#ffffff",
1900
+ cornerStrokeColor: this.getConfig("image.control.cornerStrokeColor", "#1677ff") || "#1677ff",
1901
+ transparentCorners: !!this.getConfig(
1902
+ "image.control.transparentCorners",
1903
+ false
1904
+ ),
1905
+ borderColor: this.getConfig("image.control.borderColor", "#1677ff") || "#1677ff",
1906
+ borderScaleFactor: Number.isFinite(borderScaleFactorRaw) ? Math.max(0.5, Math.min(8, borderScaleFactorRaw)) : 1.5,
1907
+ padding: Number.isFinite(paddingRaw) ? Math.max(0, Math.min(64, paddingRaw)) : 0
1908
+ };
1909
+ }
1910
+ applyImageObjectInteractionState(obj) {
1911
+ var _a;
1912
+ if (!obj) return;
1913
+ const visible = this.isImageEditingVisible();
1914
+ const visual = this.getImageControlVisualConfig();
1915
+ obj.set({
1916
+ selectable: visible,
1917
+ evented: visible,
1918
+ hasControls: visible,
1919
+ hasBorders: visible,
1920
+ lockScalingFlip: true,
1921
+ cornerSize: visual.cornerSize,
1922
+ touchCornerSize: visual.touchCornerSize,
1923
+ cornerStyle: visual.cornerStyle,
1924
+ cornerColor: visual.cornerColor,
1925
+ cornerStrokeColor: visual.cornerStrokeColor,
1926
+ transparentCorners: visual.transparentCorners,
1927
+ borderColor: visual.borderColor,
1928
+ borderScaleFactor: visual.borderScaleFactor,
1929
+ padding: visual.padding
1930
+ });
1931
+ obj.controls = this.getImageControls(
1932
+ this.getEnabledImageControlCapabilities()
1933
+ );
1934
+ (_a = obj.setCoords) == null ? void 0 : _a.call(obj);
1935
+ }
1936
+ refreshImageObjectInteractionState() {
1937
+ this.getImageObjects().forEach(
1938
+ (obj) => this.applyImageObjectInteractionState(obj)
1939
+ );
1940
+ }
1824
1941
  isDebugEnabled() {
1825
1942
  return !!this.getConfig("image.debug", false);
1826
1943
  }
@@ -1863,6 +1980,73 @@ var ImageTool = class {
1863
1980
  label: "Image Debug Log",
1864
1981
  default: false
1865
1982
  },
1983
+ {
1984
+ id: "image.control.cornerSize",
1985
+ type: "number",
1986
+ label: "Image Control Corner Size",
1987
+ min: 4,
1988
+ max: 64,
1989
+ step: 1,
1990
+ default: 14
1991
+ },
1992
+ {
1993
+ id: "image.control.touchCornerSize",
1994
+ type: "number",
1995
+ label: "Image Control Touch Corner Size",
1996
+ min: 8,
1997
+ max: 96,
1998
+ step: 1,
1999
+ default: 24
2000
+ },
2001
+ {
2002
+ id: "image.control.cornerStyle",
2003
+ type: "select",
2004
+ label: "Image Control Corner Style",
2005
+ options: ["circle", "rect"],
2006
+ default: "circle"
2007
+ },
2008
+ {
2009
+ id: "image.control.cornerColor",
2010
+ type: "color",
2011
+ label: "Image Control Corner Color",
2012
+ default: "#ffffff"
2013
+ },
2014
+ {
2015
+ id: "image.control.cornerStrokeColor",
2016
+ type: "color",
2017
+ label: "Image Control Corner Stroke Color",
2018
+ default: "#1677ff"
2019
+ },
2020
+ {
2021
+ id: "image.control.transparentCorners",
2022
+ type: "boolean",
2023
+ label: "Image Control Transparent Corners",
2024
+ default: false
2025
+ },
2026
+ {
2027
+ id: "image.control.borderColor",
2028
+ type: "color",
2029
+ label: "Image Control Border Color",
2030
+ default: "#1677ff"
2031
+ },
2032
+ {
2033
+ id: "image.control.borderScaleFactor",
2034
+ type: "number",
2035
+ label: "Image Control Border Width",
2036
+ min: 0.5,
2037
+ max: 8,
2038
+ step: 0.1,
2039
+ default: 1.5
2040
+ },
2041
+ {
2042
+ id: "image.control.padding",
2043
+ type: "number",
2044
+ label: "Image Control Padding",
2045
+ min: 0,
2046
+ max: 64,
2047
+ step: 1,
2048
+ default: 0
2049
+ },
1866
2050
  {
1867
2051
  id: "image.frame.strokeColor",
1868
2052
  type: "color",
@@ -2100,12 +2284,7 @@ var ImageTool = class {
2100
2284
  } else {
2101
2285
  const obj = this.getImageObject(id);
2102
2286
  if (obj) {
2103
- obj.set({
2104
- selectable: true,
2105
- evented: true,
2106
- hasControls: true,
2107
- hasBorders: true
2108
- });
2287
+ this.applyImageObjectInteractionState(obj);
2109
2288
  canvas.setActiveObject(obj);
2110
2289
  }
2111
2290
  }
@@ -2902,6 +3081,7 @@ var ImageTool = class {
2902
3081
  this.overlaySpecs = this.buildOverlaySpecs(frame, sceneGeometry);
2903
3082
  await this.canvasService.flushRenderFromProducers();
2904
3083
  if (seq !== this.renderSeq) return;
3084
+ this.refreshImageObjectInteractionState();
2905
3085
  renderItems.forEach((item) => {
2906
3086
  if (!this.getImageObject(item.id)) return;
2907
3087
  const resolver = this.loadResolvers.get(item.id);
@@ -5253,6 +5433,10 @@ var DielineTool = class {
5253
5433
  {
5254
5434
  type: "clipPath",
5255
5435
  id: "dieline.clip.image",
5436
+ visibility: {
5437
+ op: "not",
5438
+ expr: { op: "anySessionActive" }
5439
+ },
5256
5440
  targetPassIds: [IMAGE_OBJECT_LAYER_ID2],
5257
5441
  source: {
5258
5442
  id: "dieline.effect.clip-path",
@@ -8890,6 +9074,9 @@ function evaluateVisibilityExpr(expr, context) {
8890
9074
  if (!toolId) return false;
8891
9075
  return context.isSessionActive ? context.isSessionActive(toolId) : false;
8892
9076
  }
9077
+ if (expr.op === "anySessionActive") {
9078
+ return context.hasAnyActiveSession ? context.hasAnyActiveSession() : false;
9079
+ }
8893
9080
  if (expr.op === "layerExists") {
8894
9081
  return layerState(context, expr.layerId).exists === true;
8895
9082
  }
@@ -8923,6 +9110,7 @@ var CanvasService = class {
8923
9110
  this.visibilityRefreshScheduled = false;
8924
9111
  this.managedProducerPassIds = /* @__PURE__ */ new Set();
8925
9112
  this.managedPassMetas = /* @__PURE__ */ new Map();
9113
+ this.managedPassEffects = [];
8926
9114
  this.canvasForwardersBound = false;
8927
9115
  this.forwardSelectionCreated = (e) => {
8928
9116
  var _a;
@@ -8950,9 +9138,11 @@ var CanvasService = class {
8950
9138
  };
8951
9139
  this.onToolActivated = () => {
8952
9140
  this.applyManagedPassVisibility();
9141
+ void this.applyManagedPassEffects(void 0, { render: true });
8953
9142
  };
8954
9143
  this.onToolSessionChanged = () => {
8955
9144
  this.applyManagedPassVisibility();
9145
+ void this.applyManagedPassEffects(void 0, { render: true });
8956
9146
  };
8957
9147
  this.onCanvasObjectChanged = () => {
8958
9148
  if (this.producerApplyInProgress) return;
@@ -9017,6 +9207,7 @@ var CanvasService = class {
9017
9207
  this.renderProducers.clear();
9018
9208
  this.managedProducerPassIds.clear();
9019
9209
  this.managedPassMetas.clear();
9210
+ this.managedPassEffects = [];
9020
9211
  this.context = void 0;
9021
9212
  this.workbenchService = void 0;
9022
9213
  this.toolSessionService = void 0;
@@ -9123,6 +9314,7 @@ var CanvasService = class {
9123
9314
  return {
9124
9315
  type: "clipPath",
9125
9316
  key,
9317
+ visibility: effect.visibility,
9126
9318
  source: {
9127
9319
  ...source,
9128
9320
  id: sourceId
@@ -9230,22 +9422,30 @@ var CanvasService = class {
9230
9422
  });
9231
9423
  return state;
9232
9424
  }
9233
- applyManagedPassVisibility(options = {}) {
9425
+ isSessionActive(toolId) {
9426
+ if (!this.toolSessionService) return false;
9427
+ return this.toolSessionService.getState(toolId).status === "active";
9428
+ }
9429
+ hasAnyActiveSession() {
9234
9430
  var _a, _b;
9431
+ return (_b = (_a = this.toolSessionService) == null ? void 0 : _a.hasAnyActiveSession()) != null ? _b : false;
9432
+ }
9433
+ buildVisibilityEvalContext(layers) {
9434
+ var _a, _b;
9435
+ return {
9436
+ activeToolId: (_b = (_a = this.workbenchService) == null ? void 0 : _a.activeToolId) != null ? _b : null,
9437
+ isSessionActive: (toolId) => this.isSessionActive(toolId),
9438
+ hasAnyActiveSession: () => this.hasAnyActiveSession(),
9439
+ layers
9440
+ };
9441
+ }
9442
+ applyManagedPassVisibility(options = {}) {
9235
9443
  if (!this.managedPassMetas.size) return false;
9236
9444
  const layers = this.getPassRuntimeState();
9237
- const activeToolId = (_b = (_a = this.workbenchService) == null ? void 0 : _a.activeToolId) != null ? _b : null;
9238
- const isSessionActive = (toolId) => {
9239
- if (!this.toolSessionService) return false;
9240
- return this.toolSessionService.getState(toolId).status === "active";
9241
- };
9445
+ const context = this.buildVisibilityEvalContext(layers);
9242
9446
  let changed = false;
9243
9447
  this.managedPassMetas.forEach((meta) => {
9244
- const visible = evaluateVisibilityExpr(meta.visibility, {
9245
- activeToolId,
9246
- isSessionActive,
9247
- layers
9248
- });
9448
+ const visible = evaluateVisibilityExpr(meta.visibility, context);
9249
9449
  changed = this.setPassVisibility(meta.id, visible) || changed;
9250
9450
  });
9251
9451
  if (changed && options.render !== false) {
@@ -9313,18 +9513,24 @@ var CanvasService = class {
9313
9513
  }
9314
9514
  this.managedProducerPassIds = nextPassIds;
9315
9515
  this.managedPassMetas = nextManagedPassMetas;
9516
+ this.managedPassEffects = nextEffects;
9316
9517
  this.syncManagedPassStacking(Array.from(nextManagedPassMetas.values()));
9317
- await this.applyManagedPassEffects(nextEffects);
9518
+ await this.applyManagedPassEffects(nextEffects, { render: false });
9318
9519
  this.applyManagedPassVisibility({ render: false });
9319
9520
  } finally {
9320
9521
  this.producerApplyInProgress = false;
9321
9522
  }
9322
9523
  this.requestRenderAll();
9323
9524
  }
9324
- async applyManagedPassEffects(effects) {
9525
+ async applyManagedPassEffects(effects = this.managedPassEffects, options = {}) {
9325
9526
  const effectTargetMap = /* @__PURE__ */ new Map();
9527
+ const layers = this.getPassRuntimeState();
9528
+ const visibilityContext = this.buildVisibilityEvalContext(layers);
9326
9529
  for (const effect of effects) {
9327
9530
  if (effect.type !== "clipPath") continue;
9531
+ if (!evaluateVisibilityExpr(effect.visibility, visibilityContext)) {
9532
+ continue;
9533
+ }
9328
9534
  effect.targetPassIds.forEach((targetPassId) => {
9329
9535
  this.getPassCanvasObjects(targetPassId).forEach((obj) => {
9330
9536
  effectTargetMap.set(obj, effect);
@@ -9356,6 +9562,9 @@ var CanvasService = class {
9356
9562
  targetEffect.key
9357
9563
  );
9358
9564
  }
9565
+ if (options.render !== false) {
9566
+ this.requestRenderAll();
9567
+ }
9359
9568
  }
9360
9569
  getObject(id, passId) {
9361
9570
  const normalizedId = String(id || "").trim();