@pooder/kit 6.0.0 → 6.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.
Files changed (99) hide show
  1. package/.test-dist/src/extensions/background/BackgroundTool.js +524 -0
  2. package/.test-dist/src/extensions/background/index.js +17 -0
  3. package/.test-dist/src/extensions/background.js +1 -1
  4. package/.test-dist/src/extensions/dieline/DielineTool.js +748 -0
  5. package/.test-dist/src/extensions/dieline/commands.js +127 -0
  6. package/.test-dist/src/extensions/dieline/config.js +107 -0
  7. package/.test-dist/src/extensions/dieline/index.js +21 -0
  8. package/.test-dist/src/extensions/dieline/model.js +2 -0
  9. package/.test-dist/src/extensions/dieline/renderer.js +2 -0
  10. package/.test-dist/src/extensions/dieline.js +4 -0
  11. package/.test-dist/src/extensions/feature/FeatureTool.js +914 -0
  12. package/.test-dist/src/extensions/feature/index.js +17 -0
  13. package/.test-dist/src/extensions/film/FilmTool.js +207 -0
  14. package/.test-dist/src/extensions/film/index.js +17 -0
  15. package/.test-dist/src/extensions/image/ImageTool.js +1499 -0
  16. package/.test-dist/src/extensions/image/commands.js +162 -0
  17. package/.test-dist/src/extensions/image/config.js +129 -0
  18. package/.test-dist/src/extensions/image/index.js +21 -0
  19. package/.test-dist/src/extensions/image/model.js +2 -0
  20. package/.test-dist/src/extensions/image/renderer.js +5 -0
  21. package/.test-dist/src/extensions/image.js +182 -7
  22. package/.test-dist/src/extensions/mirror/MirrorTool.js +104 -0
  23. package/.test-dist/src/extensions/mirror/index.js +17 -0
  24. package/.test-dist/src/extensions/ruler/RulerTool.js +442 -0
  25. package/.test-dist/src/extensions/ruler/index.js +17 -0
  26. package/.test-dist/src/extensions/sceneLayout.js +2 -93
  27. package/.test-dist/src/extensions/sceneLayoutModel.js +15 -200
  28. package/.test-dist/src/extensions/size/SizeTool.js +332 -0
  29. package/.test-dist/src/extensions/size/index.js +17 -0
  30. package/.test-dist/src/extensions/white-ink/WhiteInkTool.js +1003 -0
  31. package/.test-dist/src/extensions/white-ink/commands.js +148 -0
  32. package/.test-dist/src/extensions/white-ink/config.js +31 -0
  33. package/.test-dist/src/extensions/white-ink/index.js +21 -0
  34. package/.test-dist/src/extensions/white-ink/model.js +2 -0
  35. package/.test-dist/src/extensions/white-ink/renderer.js +5 -0
  36. package/.test-dist/src/services/CanvasService.js +34 -13
  37. package/.test-dist/src/services/SceneLayoutService.js +96 -0
  38. package/.test-dist/src/services/index.js +1 -0
  39. package/.test-dist/src/services/visibility.js +3 -0
  40. package/.test-dist/src/shared/constants/layers.js +25 -0
  41. package/.test-dist/src/shared/imaging/sourceSizeCache.js +82 -0
  42. package/.test-dist/src/shared/index.js +22 -0
  43. package/.test-dist/src/shared/runtime/sessionState.js +74 -0
  44. package/.test-dist/src/shared/runtime/subscriptions.js +30 -0
  45. package/.test-dist/src/shared/scene/frame.js +34 -0
  46. package/.test-dist/src/shared/scene/sceneLayoutModel.js +202 -0
  47. package/.test-dist/tests/run.js +118 -0
  48. package/CHANGELOG.md +12 -0
  49. package/dist/index.d.mts +403 -366
  50. package/dist/index.d.ts +403 -366
  51. package/dist/index.js +5172 -4752
  52. package/dist/index.mjs +1410 -2027
  53. package/dist/tracer-PO7CRBYY.mjs +1016 -0
  54. package/package.json +1 -1
  55. package/src/extensions/{background.ts → background/BackgroundTool.ts} +33 -50
  56. package/src/extensions/background/index.ts +1 -0
  57. package/src/extensions/{dieline.ts → dieline/DielineTool.ts} +18 -218
  58. package/src/extensions/dieline/commands.ts +109 -0
  59. package/src/extensions/dieline/config.ts +106 -0
  60. package/src/extensions/dieline/index.ts +5 -0
  61. package/src/extensions/dieline/model.ts +1 -0
  62. package/src/extensions/dieline/renderer.ts +1 -0
  63. package/src/extensions/{feature.ts → feature/FeatureTool.ts} +27 -21
  64. package/src/extensions/feature/index.ts +1 -0
  65. package/src/extensions/{film.ts → film/FilmTool.ts} +36 -48
  66. package/src/extensions/film/index.ts +1 -0
  67. package/src/extensions/{image.ts → image/ImageTool.ts} +289 -335
  68. package/src/extensions/image/commands.ts +176 -0
  69. package/src/extensions/image/config.ts +128 -0
  70. package/src/extensions/image/index.ts +5 -0
  71. package/src/extensions/image/model.ts +1 -0
  72. package/src/extensions/image/renderer.ts +1 -0
  73. package/src/extensions/{mirror.ts → mirror/MirrorTool.ts} +1 -1
  74. package/src/extensions/mirror/index.ts +1 -0
  75. package/src/extensions/{ruler.ts → ruler/RulerTool.ts} +4 -5
  76. package/src/extensions/ruler/index.ts +1 -0
  77. package/src/extensions/sceneLayout.ts +1 -140
  78. package/src/extensions/sceneLayoutModel.ts +1 -364
  79. package/src/extensions/{size.ts → size/SizeTool.ts} +7 -6
  80. package/src/extensions/size/index.ts +1 -0
  81. package/src/extensions/{white-ink.ts → white-ink/WhiteInkTool.ts} +130 -317
  82. package/src/extensions/white-ink/commands.ts +157 -0
  83. package/src/extensions/white-ink/config.ts +30 -0
  84. package/src/extensions/white-ink/index.ts +5 -0
  85. package/src/extensions/white-ink/model.ts +1 -0
  86. package/src/extensions/white-ink/renderer.ts +1 -0
  87. package/src/services/CanvasService.ts +43 -12
  88. package/src/services/SceneLayoutService.ts +139 -0
  89. package/src/services/index.ts +1 -0
  90. package/src/services/renderSpec.ts +2 -0
  91. package/src/services/visibility.ts +5 -0
  92. package/src/shared/constants/layers.ts +23 -0
  93. package/src/shared/imaging/sourceSizeCache.ts +103 -0
  94. package/src/shared/index.ts +6 -0
  95. package/src/shared/runtime/sessionState.ts +105 -0
  96. package/src/shared/runtime/subscriptions.ts +45 -0
  97. package/src/shared/scene/frame.ts +46 -0
  98. package/src/shared/scene/sceneLayoutModel.ts +367 -0
  99. package/tests/run.ts +151 -0
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createImageCommands = createImageCommands;
4
+ function createImageCommands(tool) {
5
+ return [
6
+ {
7
+ command: "addImage",
8
+ id: "addImage",
9
+ title: "Add Image",
10
+ handler: async (url, options) => {
11
+ const result = await tool.upsertImageEntry(url, {
12
+ mode: "add",
13
+ addOptions: options,
14
+ });
15
+ return result.id;
16
+ },
17
+ },
18
+ {
19
+ command: "upsertImage",
20
+ id: "upsertImage",
21
+ title: "Upsert Image",
22
+ handler: async (url, options = {}) => {
23
+ return await tool.upsertImageEntry(url, options);
24
+ },
25
+ },
26
+ {
27
+ command: "getWorkingImages",
28
+ id: "getWorkingImages",
29
+ title: "Get Working Images",
30
+ handler: () => {
31
+ return tool.cloneItems(tool.workingItems);
32
+ },
33
+ },
34
+ {
35
+ command: "setWorkingImage",
36
+ id: "setWorkingImage",
37
+ title: "Set Working Image",
38
+ handler: (id, updates) => {
39
+ tool.updateImageInWorking(id, updates);
40
+ },
41
+ },
42
+ {
43
+ command: "resetWorkingImages",
44
+ id: "resetWorkingImages",
45
+ title: "Reset Working Images",
46
+ handler: () => {
47
+ tool.workingItems = tool.cloneItems(tool.items);
48
+ tool.hasWorkingChanges = false;
49
+ tool.updateImages();
50
+ tool.emitWorkingChange();
51
+ },
52
+ },
53
+ {
54
+ command: "completeImages",
55
+ id: "completeImages",
56
+ title: "Complete Images",
57
+ handler: async () => {
58
+ return await tool.commitWorkingImagesAsCropped();
59
+ },
60
+ },
61
+ {
62
+ command: "exportUserCroppedImage",
63
+ id: "exportUserCroppedImage",
64
+ title: "Export User Cropped Image",
65
+ handler: async (options = {}) => {
66
+ return await tool.exportUserCroppedImage(options);
67
+ },
68
+ },
69
+ {
70
+ command: "fitImageToArea",
71
+ id: "fitImageToArea",
72
+ title: "Fit Image to Area",
73
+ handler: async (id, area) => {
74
+ await tool.fitImageToArea(id, area);
75
+ },
76
+ },
77
+ {
78
+ command: "fitImageToDefaultArea",
79
+ id: "fitImageToDefaultArea",
80
+ title: "Fit Image to Default Area",
81
+ handler: async (id) => {
82
+ await tool.fitImageToDefaultArea(id);
83
+ },
84
+ },
85
+ {
86
+ command: "focusImage",
87
+ id: "focusImage",
88
+ title: "Focus Image",
89
+ handler: (id, options = {}) => {
90
+ return tool.setImageFocus(id, options);
91
+ },
92
+ },
93
+ {
94
+ command: "removeImage",
95
+ id: "removeImage",
96
+ title: "Remove Image",
97
+ handler: (id) => {
98
+ const removed = tool.items.find((item) => item.id === id);
99
+ const next = tool.items.filter((item) => item.id !== id);
100
+ if (next.length !== tool.items.length) {
101
+ tool.purgeSourceSizeCacheForItem(removed);
102
+ if (tool.focusedImageId === id) {
103
+ tool.setImageFocus(null, {
104
+ syncCanvasSelection: true,
105
+ skipRender: true,
106
+ });
107
+ }
108
+ tool.updateConfig(next);
109
+ }
110
+ },
111
+ },
112
+ {
113
+ command: "updateImage",
114
+ id: "updateImage",
115
+ title: "Update Image",
116
+ handler: async (id, updates, options = {}) => {
117
+ await tool.updateImage(id, updates, options);
118
+ },
119
+ },
120
+ {
121
+ command: "clearImages",
122
+ id: "clearImages",
123
+ title: "Clear Images",
124
+ handler: () => {
125
+ tool.sourceSizeCache.clear();
126
+ tool.setImageFocus(null, {
127
+ syncCanvasSelection: true,
128
+ skipRender: true,
129
+ });
130
+ tool.updateConfig([]);
131
+ },
132
+ },
133
+ {
134
+ command: "bringToFront",
135
+ id: "bringToFront",
136
+ title: "Bring Image to Front",
137
+ handler: (id) => {
138
+ const index = tool.items.findIndex((item) => item.id === id);
139
+ if (index !== -1 && index < tool.items.length - 1) {
140
+ const next = [...tool.items];
141
+ const [item] = next.splice(index, 1);
142
+ next.push(item);
143
+ tool.updateConfig(next);
144
+ }
145
+ },
146
+ },
147
+ {
148
+ command: "sendToBack",
149
+ id: "sendToBack",
150
+ title: "Send Image to Back",
151
+ handler: (id) => {
152
+ const index = tool.items.findIndex((item) => item.id === id);
153
+ if (index > 0) {
154
+ const next = [...tool.items];
155
+ const [item] = next.splice(index, 1);
156
+ next.unshift(item);
157
+ tool.updateConfig(next);
158
+ }
159
+ },
160
+ },
161
+ ];
162
+ }
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createImageConfigurations = createImageConfigurations;
4
+ function createImageConfigurations() {
5
+ return [
6
+ {
7
+ id: "image.items",
8
+ type: "array",
9
+ label: "Images",
10
+ default: [],
11
+ },
12
+ {
13
+ id: "image.debug",
14
+ type: "boolean",
15
+ label: "Image Debug Log",
16
+ default: false,
17
+ },
18
+ {
19
+ id: "image.control.cornerSize",
20
+ type: "number",
21
+ label: "Image Control Corner Size",
22
+ min: 4,
23
+ max: 64,
24
+ step: 1,
25
+ default: 14,
26
+ },
27
+ {
28
+ id: "image.control.touchCornerSize",
29
+ type: "number",
30
+ label: "Image Control Touch Corner Size",
31
+ min: 8,
32
+ max: 96,
33
+ step: 1,
34
+ default: 24,
35
+ },
36
+ {
37
+ id: "image.control.cornerStyle",
38
+ type: "select",
39
+ label: "Image Control Corner Style",
40
+ options: ["circle", "rect"],
41
+ default: "circle",
42
+ },
43
+ {
44
+ id: "image.control.cornerColor",
45
+ type: "color",
46
+ label: "Image Control Corner Color",
47
+ default: "#ffffff",
48
+ },
49
+ {
50
+ id: "image.control.cornerStrokeColor",
51
+ type: "color",
52
+ label: "Image Control Corner Stroke Color",
53
+ default: "#1677ff",
54
+ },
55
+ {
56
+ id: "image.control.transparentCorners",
57
+ type: "boolean",
58
+ label: "Image Control Transparent Corners",
59
+ default: false,
60
+ },
61
+ {
62
+ id: "image.control.borderColor",
63
+ type: "color",
64
+ label: "Image Control Border Color",
65
+ default: "#1677ff",
66
+ },
67
+ {
68
+ id: "image.control.borderScaleFactor",
69
+ type: "number",
70
+ label: "Image Control Border Width",
71
+ min: 0.5,
72
+ max: 8,
73
+ step: 0.1,
74
+ default: 1.5,
75
+ },
76
+ {
77
+ id: "image.control.padding",
78
+ type: "number",
79
+ label: "Image Control Padding",
80
+ min: 0,
81
+ max: 64,
82
+ step: 1,
83
+ default: 0,
84
+ },
85
+ {
86
+ id: "image.frame.strokeColor",
87
+ type: "color",
88
+ label: "Image Frame Stroke Color",
89
+ default: "#808080",
90
+ },
91
+ {
92
+ id: "image.frame.strokeWidth",
93
+ type: "number",
94
+ label: "Image Frame Stroke Width",
95
+ min: 0,
96
+ max: 20,
97
+ step: 0.5,
98
+ default: 2,
99
+ },
100
+ {
101
+ id: "image.frame.strokeStyle",
102
+ type: "select",
103
+ label: "Image Frame Stroke Style",
104
+ options: ["solid", "dashed", "hidden"],
105
+ default: "dashed",
106
+ },
107
+ {
108
+ id: "image.frame.dashLength",
109
+ type: "number",
110
+ label: "Image Frame Dash Length",
111
+ min: 1,
112
+ max: 40,
113
+ step: 1,
114
+ default: 8,
115
+ },
116
+ {
117
+ id: "image.frame.innerBackground",
118
+ type: "color",
119
+ label: "Image Frame Inner Background",
120
+ default: "rgba(0,0,0,0)",
121
+ },
122
+ {
123
+ id: "image.frame.outerBackground",
124
+ type: "color",
125
+ label: "Image Frame Outer Background",
126
+ default: "#f5f5f5",
127
+ },
128
+ ];
129
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ImageTool"), exports);
18
+ __exportStar(require("./commands"), exports);
19
+ __exportStar(require("./config"), exports);
20
+ __exportStar(require("./model"), exports);
21
+ __exportStar(require("./renderer"), exports);
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeImageCoverScale = void 0;
4
+ var sourceSizeCache_1 = require("../../shared/imaging/sourceSizeCache");
5
+ Object.defineProperty(exports, "computeImageCoverScale", { enumerable: true, get: function () { return sourceSizeCache_1.getCoverScale; } });
@@ -8,6 +8,34 @@ const geometry_1 = require("./geometry");
8
8
  const sceneLayoutModel_1 = require("./sceneLayoutModel");
9
9
  const IMAGE_OBJECT_LAYER_ID = "image.user";
10
10
  const IMAGE_OVERLAY_LAYER_ID = "image-overlay";
11
+ const IMAGE_DEFAULT_CONTROL_CAPABILITIES = [
12
+ "rotate",
13
+ "scale",
14
+ ];
15
+ const IMAGE_CONTROL_DESCRIPTORS = [
16
+ {
17
+ key: "tl",
18
+ capability: "rotate",
19
+ create: () => new fabric_1.Control({
20
+ x: -0.5,
21
+ y: -0.5,
22
+ actionName: "rotate",
23
+ actionHandler: fabric_1.controlsUtils.rotationWithSnapping,
24
+ cursorStyleHandler: fabric_1.controlsUtils.rotationStyleHandler,
25
+ }),
26
+ },
27
+ {
28
+ key: "br",
29
+ capability: "scale",
30
+ create: () => new fabric_1.Control({
31
+ x: 0.5,
32
+ y: 0.5,
33
+ actionName: "scale",
34
+ actionHandler: fabric_1.controlsUtils.scalingEqually,
35
+ cursorStyleHandler: fabric_1.controlsUtils.scaleCursorStyleHandler,
36
+ }),
37
+ },
38
+ ];
11
39
  class ImageTool {
12
40
  constructor() {
13
41
  this.id = "pooder.kit.image";
@@ -26,6 +54,7 @@ class ImageTool {
26
54
  this.renderSeq = 0;
27
55
  this.imageSpecs = [];
28
56
  this.overlaySpecs = [];
57
+ this.imageControlsByCapabilityKey = new Map();
29
58
  this.onToolActivated = (event) => {
30
59
  const before = this.isToolActive;
31
60
  this.syncToolActiveFromWorkbench(event.id);
@@ -183,7 +212,12 @@ class ImageTool {
183
212
  this.updateImages();
184
213
  return;
185
214
  }
186
- if (e.key.startsWith("size.") || e.key.startsWith("image.frame.")) {
215
+ if (e.key.startsWith("size.") ||
216
+ e.key.startsWith("image.frame.") ||
217
+ e.key.startsWith("image.control.")) {
218
+ if (e.key.startsWith("image.control.")) {
219
+ this.imageControlsByCapabilityKey.clear();
220
+ }
187
221
  this.updateImages();
188
222
  }
189
223
  });
@@ -207,6 +241,7 @@ class ImageTool {
207
241
  this.cropShapeHatchPatternKey = undefined;
208
242
  this.imageSpecs = [];
209
243
  this.overlaySpecs = [];
244
+ this.imageControlsByCapabilityKey.clear();
210
245
  this.clearRenderedImages();
211
246
  this.renderProducerDisposable?.dispose();
212
247
  this.renderProducerDisposable = undefined;
@@ -228,6 +263,83 @@ class ImageTool {
228
263
  isImageEditingVisible() {
229
264
  return (this.isToolActive || this.isImageSelectionActive || !!this.focusedImageId);
230
265
  }
266
+ getEnabledImageControlCapabilities() {
267
+ return IMAGE_DEFAULT_CONTROL_CAPABILITIES;
268
+ }
269
+ getImageControls(capabilities) {
270
+ const normalized = [...new Set(capabilities)].sort();
271
+ const cacheKey = normalized.join("|");
272
+ const cached = this.imageControlsByCapabilityKey.get(cacheKey);
273
+ if (cached) {
274
+ return cached;
275
+ }
276
+ const enabled = new Set(normalized);
277
+ const controls = {};
278
+ IMAGE_CONTROL_DESCRIPTORS.forEach((descriptor) => {
279
+ if (!enabled.has(descriptor.capability))
280
+ return;
281
+ controls[descriptor.key] = descriptor.create();
282
+ });
283
+ this.imageControlsByCapabilityKey.set(cacheKey, controls);
284
+ return controls;
285
+ }
286
+ getImageControlVisualConfig() {
287
+ const cornerSizeRaw = Number(this.getConfig("image.control.cornerSize", 14) ?? 14);
288
+ const touchCornerSizeRaw = Number(this.getConfig("image.control.touchCornerSize", 24) ?? 24);
289
+ const borderScaleFactorRaw = Number(this.getConfig("image.control.borderScaleFactor", 1.5) ?? 1.5);
290
+ const paddingRaw = Number(this.getConfig("image.control.padding", 0) ?? 0);
291
+ const cornerStyleRaw = (this.getConfig("image.control.cornerStyle", "circle") || "circle");
292
+ const cornerStyle = cornerStyleRaw === "rect" ? "rect" : "circle";
293
+ return {
294
+ cornerSize: Number.isFinite(cornerSizeRaw)
295
+ ? Math.max(4, Math.min(64, cornerSizeRaw))
296
+ : 14,
297
+ touchCornerSize: Number.isFinite(touchCornerSizeRaw)
298
+ ? Math.max(8, Math.min(96, touchCornerSizeRaw))
299
+ : 24,
300
+ cornerStyle,
301
+ cornerColor: this.getConfig("image.control.cornerColor", "#ffffff") ||
302
+ "#ffffff",
303
+ cornerStrokeColor: this.getConfig("image.control.cornerStrokeColor", "#1677ff") ||
304
+ "#1677ff",
305
+ transparentCorners: !!this.getConfig("image.control.transparentCorners", false),
306
+ borderColor: this.getConfig("image.control.borderColor", "#1677ff") ||
307
+ "#1677ff",
308
+ borderScaleFactor: Number.isFinite(borderScaleFactorRaw)
309
+ ? Math.max(0.5, Math.min(8, borderScaleFactorRaw))
310
+ : 1.5,
311
+ padding: Number.isFinite(paddingRaw)
312
+ ? Math.max(0, Math.min(64, paddingRaw))
313
+ : 0,
314
+ };
315
+ }
316
+ applyImageObjectInteractionState(obj) {
317
+ if (!obj)
318
+ return;
319
+ const visible = this.isImageEditingVisible();
320
+ const visual = this.getImageControlVisualConfig();
321
+ obj.set({
322
+ selectable: visible,
323
+ evented: visible,
324
+ hasControls: visible,
325
+ hasBorders: visible,
326
+ lockScalingFlip: true,
327
+ cornerSize: visual.cornerSize,
328
+ touchCornerSize: visual.touchCornerSize,
329
+ cornerStyle: visual.cornerStyle,
330
+ cornerColor: visual.cornerColor,
331
+ cornerStrokeColor: visual.cornerStrokeColor,
332
+ transparentCorners: visual.transparentCorners,
333
+ borderColor: visual.borderColor,
334
+ borderScaleFactor: visual.borderScaleFactor,
335
+ padding: visual.padding,
336
+ });
337
+ obj.controls = this.getImageControls(this.getEnabledImageControlCapabilities());
338
+ obj.setCoords?.();
339
+ }
340
+ refreshImageObjectInteractionState() {
341
+ this.getImageObjects().forEach((obj) => this.applyImageObjectInteractionState(obj));
342
+ }
231
343
  isDebugEnabled() {
232
344
  return !!this.getConfig("image.debug", false);
233
345
  }
@@ -271,6 +383,73 @@ class ImageTool {
271
383
  label: "Image Debug Log",
272
384
  default: false,
273
385
  },
386
+ {
387
+ id: "image.control.cornerSize",
388
+ type: "number",
389
+ label: "Image Control Corner Size",
390
+ min: 4,
391
+ max: 64,
392
+ step: 1,
393
+ default: 14,
394
+ },
395
+ {
396
+ id: "image.control.touchCornerSize",
397
+ type: "number",
398
+ label: "Image Control Touch Corner Size",
399
+ min: 8,
400
+ max: 96,
401
+ step: 1,
402
+ default: 24,
403
+ },
404
+ {
405
+ id: "image.control.cornerStyle",
406
+ type: "select",
407
+ label: "Image Control Corner Style",
408
+ options: ["circle", "rect"],
409
+ default: "circle",
410
+ },
411
+ {
412
+ id: "image.control.cornerColor",
413
+ type: "color",
414
+ label: "Image Control Corner Color",
415
+ default: "#ffffff",
416
+ },
417
+ {
418
+ id: "image.control.cornerStrokeColor",
419
+ type: "color",
420
+ label: "Image Control Corner Stroke Color",
421
+ default: "#1677ff",
422
+ },
423
+ {
424
+ id: "image.control.transparentCorners",
425
+ type: "boolean",
426
+ label: "Image Control Transparent Corners",
427
+ default: false,
428
+ },
429
+ {
430
+ id: "image.control.borderColor",
431
+ type: "color",
432
+ label: "Image Control Border Color",
433
+ default: "#1677ff",
434
+ },
435
+ {
436
+ id: "image.control.borderScaleFactor",
437
+ type: "number",
438
+ label: "Image Control Border Width",
439
+ min: 0.5,
440
+ max: 8,
441
+ step: 0.1,
442
+ default: 1.5,
443
+ },
444
+ {
445
+ id: "image.control.padding",
446
+ type: "number",
447
+ label: "Image Control Padding",
448
+ min: 0,
449
+ max: 64,
450
+ step: 1,
451
+ default: 0,
452
+ },
274
453
  {
275
454
  id: "image.frame.strokeColor",
276
455
  type: "color",
@@ -513,12 +692,7 @@ class ImageTool {
513
692
  else {
514
693
  const obj = this.getImageObject(id);
515
694
  if (obj) {
516
- obj.set({
517
- selectable: true,
518
- evented: true,
519
- hasControls: true,
520
- hasBorders: true,
521
- });
695
+ this.applyImageObjectInteractionState(obj);
522
696
  canvas.setActiveObject(obj);
523
697
  }
524
698
  }
@@ -1317,6 +1491,7 @@ class ImageTool {
1317
1491
  await this.canvasService.flushRenderFromProducers();
1318
1492
  if (seq !== this.renderSeq)
1319
1493
  return;
1494
+ this.refreshImageObjectInteractionState();
1320
1495
  renderItems.forEach((item) => {
1321
1496
  if (!this.getImageObject(item.id))
1322
1497
  return;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MirrorTool = void 0;
4
+ const core_1 = require("@pooder/core");
5
+ class MirrorTool {
6
+ constructor(options) {
7
+ this.id = "pooder.kit.mirror";
8
+ this.metadata = {
9
+ name: "MirrorTool",
10
+ };
11
+ this.enabled = false;
12
+ if (options) {
13
+ Object.assign(this, options);
14
+ }
15
+ }
16
+ toJSON() {
17
+ return {
18
+ enabled: this.enabled,
19
+ };
20
+ }
21
+ loadFromJSON(json) {
22
+ this.enabled = json.enabled;
23
+ }
24
+ activate(context) {
25
+ this.canvasService = context.services.get("CanvasService");
26
+ if (!this.canvasService) {
27
+ console.warn("CanvasService not found for MirrorTool");
28
+ return;
29
+ }
30
+ const configService = context.services.get("ConfigurationService");
31
+ if (configService) {
32
+ // Load initial config
33
+ this.enabled = configService.get("mirror.enabled", this.enabled);
34
+ // Listen for changes
35
+ configService.onAnyChange((e) => {
36
+ if (e.key === "mirror.enabled") {
37
+ this.applyMirror(e.value);
38
+ }
39
+ });
40
+ }
41
+ // Initialize with current state (if enabled was persisted)
42
+ if (this.enabled) {
43
+ this.applyMirror(true);
44
+ }
45
+ }
46
+ deactivate(context) {
47
+ this.applyMirror(false);
48
+ this.canvasService = undefined;
49
+ }
50
+ contribute() {
51
+ return {
52
+ [core_1.ContributionPointIds.CONFIGURATIONS]: [
53
+ {
54
+ id: "mirror.enabled",
55
+ type: "boolean",
56
+ label: "Enable Mirror",
57
+ default: false,
58
+ },
59
+ ],
60
+ [core_1.ContributionPointIds.COMMANDS]: [
61
+ {
62
+ command: "setMirror",
63
+ title: "Set Mirror",
64
+ handler: (enabled) => {
65
+ this.applyMirror(enabled);
66
+ return true;
67
+ },
68
+ },
69
+ ],
70
+ };
71
+ }
72
+ applyMirror(enabled) {
73
+ if (!this.canvasService)
74
+ return;
75
+ const canvas = this.canvasService.canvas;
76
+ if (!canvas)
77
+ return;
78
+ const width = canvas.width || 800;
79
+ // Fabric.js v6+ uses viewportTransform property
80
+ let vpt = canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
81
+ // Create a copy to avoid mutating the reference directly before setting
82
+ vpt = [...vpt];
83
+ // If we are enabling and currently not flipped (scaleX > 0)
84
+ // Or disabling and currently flipped (scaleX < 0)
85
+ const isFlipped = vpt[0] < 0;
86
+ if (enabled && !isFlipped) {
87
+ // Flip scale X
88
+ vpt[0] = -vpt[0]; // Flip scale
89
+ vpt[4] = width - vpt[4]; // Adjust pan X
90
+ canvas.setViewportTransform(vpt);
91
+ canvas.requestRenderAll();
92
+ this.enabled = true;
93
+ }
94
+ else if (!enabled && isFlipped) {
95
+ // Restore
96
+ vpt[0] = -vpt[0]; // Unflip scale
97
+ vpt[4] = width - vpt[4]; // Restore pan X
98
+ canvas.setViewportTransform(vpt);
99
+ canvas.requestRenderAll();
100
+ this.enabled = false;
101
+ }
102
+ }
103
+ }
104
+ exports.MirrorTool = MirrorTool;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./MirrorTool"), exports);