@pooder/kit 6.0.1 → 6.1.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.
Files changed (91) 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/dieline/DielineTool.js +748 -0
  4. package/.test-dist/src/extensions/dieline/commands.js +127 -0
  5. package/.test-dist/src/extensions/dieline/config.js +107 -0
  6. package/.test-dist/src/extensions/dieline/index.js +21 -0
  7. package/.test-dist/src/extensions/dieline/model.js +2 -0
  8. package/.test-dist/src/extensions/dieline/renderer.js +2 -0
  9. package/.test-dist/src/extensions/feature/FeatureTool.js +914 -0
  10. package/.test-dist/src/extensions/feature/index.js +17 -0
  11. package/.test-dist/src/extensions/film/FilmTool.js +207 -0
  12. package/.test-dist/src/extensions/film/index.js +17 -0
  13. package/.test-dist/src/extensions/image/ImageTool.js +1499 -0
  14. package/.test-dist/src/extensions/image/commands.js +162 -0
  15. package/.test-dist/src/extensions/image/config.js +129 -0
  16. package/.test-dist/src/extensions/image/index.js +21 -0
  17. package/.test-dist/src/extensions/image/model.js +2 -0
  18. package/.test-dist/src/extensions/image/renderer.js +5 -0
  19. package/.test-dist/src/extensions/mirror/MirrorTool.js +104 -0
  20. package/.test-dist/src/extensions/mirror/index.js +17 -0
  21. package/.test-dist/src/extensions/ruler/RulerTool.js +442 -0
  22. package/.test-dist/src/extensions/ruler/index.js +17 -0
  23. package/.test-dist/src/extensions/sceneLayout.js +2 -93
  24. package/.test-dist/src/extensions/sceneLayoutModel.js +15 -200
  25. package/.test-dist/src/extensions/size/SizeTool.js +332 -0
  26. package/.test-dist/src/extensions/size/index.js +17 -0
  27. package/.test-dist/src/extensions/white-ink/WhiteInkTool.js +1003 -0
  28. package/.test-dist/src/extensions/white-ink/commands.js +148 -0
  29. package/.test-dist/src/extensions/white-ink/config.js +31 -0
  30. package/.test-dist/src/extensions/white-ink/index.js +21 -0
  31. package/.test-dist/src/extensions/white-ink/model.js +2 -0
  32. package/.test-dist/src/extensions/white-ink/renderer.js +5 -0
  33. package/.test-dist/src/services/SceneLayoutService.js +96 -0
  34. package/.test-dist/src/services/index.js +1 -0
  35. package/.test-dist/src/shared/constants/layers.js +25 -0
  36. package/.test-dist/src/shared/imaging/sourceSizeCache.js +82 -0
  37. package/.test-dist/src/shared/index.js +22 -0
  38. package/.test-dist/src/shared/runtime/sessionState.js +74 -0
  39. package/.test-dist/src/shared/runtime/subscriptions.js +30 -0
  40. package/.test-dist/src/shared/scene/frame.js +34 -0
  41. package/.test-dist/src/shared/scene/sceneLayoutModel.js +202 -0
  42. package/.test-dist/tests/run.js +116 -0
  43. package/CHANGELOG.md +14 -0
  44. package/dist/index.d.mts +390 -367
  45. package/dist/index.d.ts +390 -367
  46. package/dist/index.js +5138 -4927
  47. package/dist/index.mjs +1149 -1977
  48. package/dist/tracer-PO7CRBYY.mjs +1016 -0
  49. package/package.json +2 -2
  50. package/src/extensions/{background.ts → background/BackgroundTool.ts} +33 -50
  51. package/src/extensions/background/index.ts +1 -0
  52. package/src/extensions/{dieline.ts → dieline/DielineTool.ts} +14 -218
  53. package/src/extensions/dieline/commands.ts +109 -0
  54. package/src/extensions/dieline/config.ts +106 -0
  55. package/src/extensions/dieline/index.ts +5 -0
  56. package/src/extensions/dieline/model.ts +1 -0
  57. package/src/extensions/dieline/renderer.ts +1 -0
  58. package/src/extensions/{feature.ts → feature/FeatureTool.ts} +27 -21
  59. package/src/extensions/feature/index.ts +1 -0
  60. package/src/extensions/{film.ts → film/FilmTool.ts} +36 -48
  61. package/src/extensions/film/index.ts +1 -0
  62. package/src/extensions/{image.ts → image/ImageTool.ts} +123 -402
  63. package/src/extensions/image/commands.ts +176 -0
  64. package/src/extensions/image/config.ts +128 -0
  65. package/src/extensions/image/index.ts +5 -0
  66. package/src/extensions/image/model.ts +1 -0
  67. package/src/extensions/image/renderer.ts +1 -0
  68. package/src/extensions/{mirror.ts → mirror/MirrorTool.ts} +1 -1
  69. package/src/extensions/mirror/index.ts +1 -0
  70. package/src/extensions/{ruler.ts → ruler/RulerTool.ts} +4 -5
  71. package/src/extensions/ruler/index.ts +1 -0
  72. package/src/extensions/sceneLayout.ts +1 -140
  73. package/src/extensions/sceneLayoutModel.ts +1 -364
  74. package/src/extensions/{size.ts → size/SizeTool.ts} +7 -6
  75. package/src/extensions/size/index.ts +1 -0
  76. package/src/extensions/{white-ink.ts → white-ink/WhiteInkTool.ts} +130 -317
  77. package/src/extensions/white-ink/commands.ts +157 -0
  78. package/src/extensions/white-ink/config.ts +30 -0
  79. package/src/extensions/white-ink/index.ts +5 -0
  80. package/src/extensions/white-ink/model.ts +1 -0
  81. package/src/extensions/white-ink/renderer.ts +1 -0
  82. package/src/services/SceneLayoutService.ts +139 -0
  83. package/src/services/index.ts +1 -0
  84. package/src/shared/constants/layers.ts +23 -0
  85. package/src/shared/imaging/sourceSizeCache.ts +103 -0
  86. package/src/shared/index.ts +6 -0
  87. package/src/shared/runtime/sessionState.ts +105 -0
  88. package/src/shared/runtime/subscriptions.ts +45 -0
  89. package/src/shared/scene/frame.ts +46 -0
  90. package/src/shared/scene/sceneLayoutModel.ts +367 -0
  91. package/tests/run.ts +146 -0
@@ -0,0 +1,524 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BackgroundTool = void 0;
4
+ const core_1 = require("@pooder/core");
5
+ const fabric_1 = require("fabric");
6
+ const sceneLayoutModel_1 = require("../../shared/scene/sceneLayoutModel");
7
+ const layers_1 = require("../../shared/constants/layers");
8
+ const sourceSizeCache_1 = require("../../shared/imaging/sourceSizeCache");
9
+ const subscriptions_1 = require("../../shared/runtime/subscriptions");
10
+ const BACKGROUND_CONFIG_KEY = "background.config";
11
+ const DEFAULT_WIDTH = 800;
12
+ const DEFAULT_HEIGHT = 600;
13
+ const DEFAULT_BACKGROUND_CONFIG = {
14
+ version: 1,
15
+ layers: [
16
+ {
17
+ id: "base-color",
18
+ kind: "color",
19
+ anchor: "viewport",
20
+ fit: "cover",
21
+ opacity: 1,
22
+ order: 0,
23
+ enabled: true,
24
+ exportable: false,
25
+ color: "#fff",
26
+ },
27
+ ],
28
+ };
29
+ function clampOpacity(value, fallback) {
30
+ const numeric = Number(value);
31
+ if (!Number.isFinite(numeric)) {
32
+ return Math.max(0, Math.min(1, fallback));
33
+ }
34
+ return Math.max(0, Math.min(1, numeric));
35
+ }
36
+ function normalizeLayerKind(value, fallback) {
37
+ if (value === "color" || value === "image") {
38
+ return value;
39
+ }
40
+ return fallback;
41
+ }
42
+ function normalizeFitMode(value, fallback) {
43
+ if (value === "contain" || value === "cover" || value === "stretch") {
44
+ return value;
45
+ }
46
+ return fallback;
47
+ }
48
+ function normalizeAnchor(value, fallback) {
49
+ if (typeof value !== "string")
50
+ return fallback;
51
+ const trimmed = value.trim();
52
+ return trimmed || fallback;
53
+ }
54
+ function normalizeOrder(value, fallback) {
55
+ const numeric = Number(value);
56
+ if (!Number.isFinite(numeric))
57
+ return fallback;
58
+ return numeric;
59
+ }
60
+ function normalizeLayer(raw, index, fallback) {
61
+ const fallbackLayer = fallback || {
62
+ id: `layer-${index + 1}`,
63
+ kind: "image",
64
+ anchor: "viewport",
65
+ fit: "contain",
66
+ opacity: 1,
67
+ order: index,
68
+ enabled: true,
69
+ exportable: false,
70
+ src: "",
71
+ };
72
+ if (!raw || typeof raw !== "object") {
73
+ return { ...fallbackLayer };
74
+ }
75
+ const input = raw;
76
+ const kind = normalizeLayerKind(input.kind, fallbackLayer.kind);
77
+ return {
78
+ id: typeof input.id === "string" && input.id.trim().length > 0
79
+ ? input.id.trim()
80
+ : fallbackLayer.id,
81
+ kind,
82
+ anchor: normalizeAnchor(input.anchor, fallbackLayer.anchor),
83
+ fit: normalizeFitMode(input.fit, fallbackLayer.fit),
84
+ opacity: clampOpacity(input.opacity, fallbackLayer.opacity),
85
+ order: normalizeOrder(input.order, fallbackLayer.order),
86
+ enabled: typeof input.enabled === "boolean"
87
+ ? input.enabled
88
+ : fallbackLayer.enabled,
89
+ exportable: typeof input.exportable === "boolean"
90
+ ? input.exportable
91
+ : fallbackLayer.exportable,
92
+ color: kind === "color"
93
+ ? typeof input.color === "string"
94
+ ? input.color
95
+ : typeof fallbackLayer.color === "string"
96
+ ? fallbackLayer.color
97
+ : "#ffffff"
98
+ : undefined,
99
+ src: kind === "image"
100
+ ? typeof input.src === "string"
101
+ ? input.src.trim()
102
+ : typeof fallbackLayer.src === "string"
103
+ ? fallbackLayer.src
104
+ : ""
105
+ : undefined,
106
+ };
107
+ }
108
+ function normalizeConfig(raw) {
109
+ if (!raw || typeof raw !== "object") {
110
+ return cloneConfig(DEFAULT_BACKGROUND_CONFIG);
111
+ }
112
+ const input = raw;
113
+ const version = Number.isFinite(Number(input.version))
114
+ ? Number(input.version)
115
+ : DEFAULT_BACKGROUND_CONFIG.version;
116
+ const baseLayers = Array.isArray(input.layers)
117
+ ? input.layers.map((layer, index) => normalizeLayer(layer, index))
118
+ : cloneConfig(DEFAULT_BACKGROUND_CONFIG).layers;
119
+ const uniqueLayers = [];
120
+ const seen = new Set();
121
+ baseLayers.forEach((layer, index) => {
122
+ let nextId = layer.id || `layer-${index + 1}`;
123
+ let serial = 1;
124
+ while (seen.has(nextId)) {
125
+ serial += 1;
126
+ nextId = `${layer.id || `layer-${index + 1}`}-${serial}`;
127
+ }
128
+ seen.add(nextId);
129
+ uniqueLayers.push({ ...layer, id: nextId });
130
+ });
131
+ return {
132
+ version,
133
+ layers: uniqueLayers,
134
+ };
135
+ }
136
+ function cloneConfig(config) {
137
+ return {
138
+ version: config.version,
139
+ layers: (config.layers || []).map((layer) => ({ ...layer })),
140
+ };
141
+ }
142
+ function mergeConfig(base, patch) {
143
+ const merged = {
144
+ version: patch.version === undefined
145
+ ? base.version
146
+ : Number.isFinite(Number(patch.version))
147
+ ? Number(patch.version)
148
+ : base.version,
149
+ layers: Array.isArray(patch.layers)
150
+ ? patch.layers.map((layer, index) => normalizeLayer(layer, index))
151
+ : base.layers.map((layer) => ({ ...layer })),
152
+ };
153
+ return normalizeConfig(merged);
154
+ }
155
+ function configSignature(config) {
156
+ return JSON.stringify(config);
157
+ }
158
+ class BackgroundTool {
159
+ constructor(options) {
160
+ this.id = "pooder.kit.background";
161
+ this.metadata = {
162
+ name: "BackgroundTool",
163
+ };
164
+ this.config = cloneConfig(DEFAULT_BACKGROUND_CONFIG);
165
+ this.specs = [];
166
+ this.subscriptions = new subscriptions_1.SubscriptionBag();
167
+ this.renderSeq = 0;
168
+ this.latestSceneLayout = null;
169
+ this.sourceSizeCache = (0, sourceSizeCache_1.createSourceSizeCache)((src) => this.loadImageSize(src));
170
+ this.onCanvasResized = () => {
171
+ this.latestSceneLayout = null;
172
+ this.updateBackground();
173
+ };
174
+ this.onSceneLayoutChanged = (layout) => {
175
+ this.latestSceneLayout = layout;
176
+ this.updateBackground();
177
+ };
178
+ if (options && typeof options === "object") {
179
+ this.config = mergeConfig(this.config, options);
180
+ }
181
+ }
182
+ activate(context) {
183
+ this.subscriptions.disposeAll();
184
+ this.canvasService = context.services.get("CanvasService");
185
+ if (!this.canvasService) {
186
+ console.warn("CanvasService not found for BackgroundTool");
187
+ return;
188
+ }
189
+ this.configService = context.services.get("ConfigurationService");
190
+ if (this.configService) {
191
+ this.config = normalizeConfig(this.configService.get(BACKGROUND_CONFIG_KEY, DEFAULT_BACKGROUND_CONFIG));
192
+ this.subscriptions.onConfigChange(this.configService, (e) => {
193
+ if (e.key === BACKGROUND_CONFIG_KEY) {
194
+ this.config = normalizeConfig(e.value);
195
+ this.updateBackground();
196
+ return;
197
+ }
198
+ if (e.key.startsWith("size.")) {
199
+ this.latestSceneLayout = null;
200
+ this.updateBackground();
201
+ }
202
+ });
203
+ }
204
+ this.renderProducerDisposable?.dispose();
205
+ this.renderProducerDisposable = this.canvasService.registerRenderProducer(this.id, () => ({
206
+ passes: [
207
+ {
208
+ id: layers_1.BACKGROUND_LAYER_ID,
209
+ stack: 0,
210
+ order: 0,
211
+ objects: this.specs,
212
+ },
213
+ ],
214
+ }), { priority: 0 });
215
+ this.subscriptions.on(context.eventBus, "canvas:resized", this.onCanvasResized);
216
+ this.subscriptions.on(context.eventBus, "scene:layout:change", this.onSceneLayoutChanged);
217
+ this.updateBackground();
218
+ }
219
+ deactivate(context) {
220
+ this.subscriptions.disposeAll();
221
+ this.renderSeq += 1;
222
+ this.specs = [];
223
+ this.latestSceneLayout = null;
224
+ this.sourceSizeCache.clear();
225
+ this.renderProducerDisposable?.dispose();
226
+ this.renderProducerDisposable = undefined;
227
+ if (!this.canvasService)
228
+ return;
229
+ void this.canvasService.flushRenderFromProducers();
230
+ this.canvasService.requestRenderAll();
231
+ this.canvasService = undefined;
232
+ this.configService = undefined;
233
+ }
234
+ contribute() {
235
+ return {
236
+ [core_1.ContributionPointIds.CONFIGURATIONS]: [
237
+ {
238
+ id: BACKGROUND_CONFIG_KEY,
239
+ type: "json",
240
+ label: "Background Config",
241
+ default: cloneConfig(DEFAULT_BACKGROUND_CONFIG),
242
+ },
243
+ ],
244
+ [core_1.ContributionPointIds.COMMANDS]: [
245
+ {
246
+ command: "background.getConfig",
247
+ title: "Get Background Config",
248
+ handler: () => cloneConfig(this.config),
249
+ },
250
+ {
251
+ command: "background.resetConfig",
252
+ title: "Reset Background Config",
253
+ handler: () => {
254
+ this.commitConfig(cloneConfig(DEFAULT_BACKGROUND_CONFIG));
255
+ return true;
256
+ },
257
+ },
258
+ {
259
+ command: "background.replaceConfig",
260
+ title: "Replace Background Config",
261
+ handler: (config) => {
262
+ this.commitConfig(normalizeConfig(config));
263
+ return true;
264
+ },
265
+ },
266
+ {
267
+ command: "background.patchConfig",
268
+ title: "Patch Background Config",
269
+ handler: (patch) => {
270
+ this.commitConfig(mergeConfig(this.config, patch || {}));
271
+ return true;
272
+ },
273
+ },
274
+ {
275
+ command: "background.upsertLayer",
276
+ title: "Upsert Background Layer",
277
+ handler: (layer) => {
278
+ const normalized = normalizeLayer(layer, 0);
279
+ const existingIndex = this.config.layers.findIndex((item) => item.id === normalized.id);
280
+ const nextLayers = [...this.config.layers];
281
+ if (existingIndex >= 0) {
282
+ nextLayers[existingIndex] = normalizeLayer({ ...nextLayers[existingIndex], ...layer }, existingIndex, nextLayers[existingIndex]);
283
+ }
284
+ else {
285
+ nextLayers.push(normalizeLayer({
286
+ ...normalized,
287
+ order: Number.isFinite(Number(layer.order))
288
+ ? Number(layer.order)
289
+ : nextLayers.length,
290
+ }, nextLayers.length));
291
+ }
292
+ this.commitConfig(normalizeConfig({
293
+ ...this.config,
294
+ layers: nextLayers,
295
+ }));
296
+ return true;
297
+ },
298
+ },
299
+ {
300
+ command: "background.removeLayer",
301
+ title: "Remove Background Layer",
302
+ handler: (id) => {
303
+ const nextLayers = this.config.layers.filter((layer) => layer.id !== id);
304
+ this.commitConfig(normalizeConfig({
305
+ ...this.config,
306
+ layers: nextLayers,
307
+ }));
308
+ return true;
309
+ },
310
+ },
311
+ ],
312
+ };
313
+ }
314
+ commitConfig(next) {
315
+ const normalized = normalizeConfig(next);
316
+ if (configSignature(normalized) === configSignature(this.config)) {
317
+ return;
318
+ }
319
+ if (this.configService) {
320
+ this.configService.update(BACKGROUND_CONFIG_KEY, cloneConfig(normalized));
321
+ return;
322
+ }
323
+ this.config = normalized;
324
+ this.updateBackground();
325
+ }
326
+ getViewportRect() {
327
+ const width = Number(this.canvasService?.canvas.width || 0);
328
+ const height = Number(this.canvasService?.canvas.height || 0);
329
+ return {
330
+ left: 0,
331
+ top: 0,
332
+ width: width > 0 ? width : DEFAULT_WIDTH,
333
+ height: height > 0 ? height : DEFAULT_HEIGHT,
334
+ };
335
+ }
336
+ resolveSceneLayout() {
337
+ if (this.latestSceneLayout)
338
+ return this.latestSceneLayout;
339
+ if (!this.canvasService || !this.configService)
340
+ return null;
341
+ const layout = (0, sceneLayoutModel_1.computeSceneLayout)(this.canvasService, (0, sceneLayoutModel_1.readSizeState)(this.configService));
342
+ this.latestSceneLayout = layout;
343
+ return layout;
344
+ }
345
+ resolveFocusRect() {
346
+ const layout = this.resolveSceneLayout();
347
+ if (!layout)
348
+ return null;
349
+ return {
350
+ left: layout.trimRect.left,
351
+ top: layout.trimRect.top,
352
+ width: layout.trimRect.width,
353
+ height: layout.trimRect.height,
354
+ };
355
+ }
356
+ resolveAnchorRect(anchor) {
357
+ if (anchor === "focus") {
358
+ return this.resolveFocusRect() || this.getViewportRect();
359
+ }
360
+ if (anchor !== "viewport") {
361
+ return this.getViewportRect();
362
+ }
363
+ return this.getViewportRect();
364
+ }
365
+ resolveImagePlacement(target, sourceSize, fit) {
366
+ const targetWidth = Math.max(1, Number(target.width || 0));
367
+ const targetHeight = Math.max(1, Number(target.height || 0));
368
+ const sourceWidth = Math.max(1, Number(sourceSize.width || 0));
369
+ const sourceHeight = Math.max(1, Number(sourceSize.height || 0));
370
+ if (fit === "stretch") {
371
+ return {
372
+ left: target.left,
373
+ top: target.top,
374
+ scaleX: targetWidth / sourceWidth,
375
+ scaleY: targetHeight / sourceHeight,
376
+ };
377
+ }
378
+ const scale = fit === "contain"
379
+ ? Math.min(targetWidth / sourceWidth, targetHeight / sourceHeight)
380
+ : Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);
381
+ const renderWidth = sourceWidth * scale;
382
+ const renderHeight = sourceHeight * scale;
383
+ return {
384
+ left: target.left + (targetWidth - renderWidth) / 2,
385
+ top: target.top + (targetHeight - renderHeight) / 2,
386
+ scaleX: scale,
387
+ scaleY: scale,
388
+ };
389
+ }
390
+ buildColorLayerSpec(layer) {
391
+ const rect = this.resolveAnchorRect(layer.anchor);
392
+ return {
393
+ id: `background.layer.${layer.id}.color`,
394
+ type: "rect",
395
+ space: "screen",
396
+ data: {
397
+ id: `background.layer.${layer.id}.color`,
398
+ layerId: layers_1.BACKGROUND_LAYER_ID,
399
+ type: "background-layer",
400
+ layerRef: layer.id,
401
+ layerKind: layer.kind,
402
+ },
403
+ props: {
404
+ left: rect.left,
405
+ top: rect.top,
406
+ width: rect.width,
407
+ height: rect.height,
408
+ originX: "left",
409
+ originY: "top",
410
+ fill: layer.color || "transparent",
411
+ opacity: layer.opacity,
412
+ selectable: false,
413
+ evented: false,
414
+ excludeFromExport: !layer.exportable,
415
+ },
416
+ };
417
+ }
418
+ buildImageLayerSpec(layer) {
419
+ const src = String(layer.src || "").trim();
420
+ if (!src)
421
+ return [];
422
+ const sourceSize = this.sourceSizeCache.getSourceSize(src);
423
+ if (!sourceSize)
424
+ return [];
425
+ const rect = this.resolveAnchorRect(layer.anchor);
426
+ const placement = this.resolveImagePlacement(rect, sourceSize, layer.fit);
427
+ return [
428
+ {
429
+ id: `background.layer.${layer.id}.image`,
430
+ type: "image",
431
+ src,
432
+ space: "screen",
433
+ data: {
434
+ id: `background.layer.${layer.id}.image`,
435
+ layerId: layers_1.BACKGROUND_LAYER_ID,
436
+ type: "background-layer",
437
+ layerRef: layer.id,
438
+ layerKind: layer.kind,
439
+ },
440
+ props: {
441
+ left: placement.left,
442
+ top: placement.top,
443
+ originX: "left",
444
+ originY: "top",
445
+ scaleX: placement.scaleX,
446
+ scaleY: placement.scaleY,
447
+ opacity: layer.opacity,
448
+ selectable: false,
449
+ evented: false,
450
+ excludeFromExport: !layer.exportable,
451
+ },
452
+ },
453
+ ];
454
+ }
455
+ buildBackgroundSpecs(config) {
456
+ const activeLayers = (config.layers || [])
457
+ .filter((layer) => layer.enabled)
458
+ .map((layer, index) => ({ layer, index }))
459
+ .sort((a, b) => {
460
+ if (a.layer.order !== b.layer.order) {
461
+ return a.layer.order - b.layer.order;
462
+ }
463
+ return a.index - b.index;
464
+ });
465
+ const specs = [];
466
+ activeLayers.forEach(({ layer }) => {
467
+ if (layer.kind === "color") {
468
+ specs.push(this.buildColorLayerSpec(layer));
469
+ return;
470
+ }
471
+ specs.push(...this.buildImageLayerSpec(layer));
472
+ });
473
+ return specs;
474
+ }
475
+ collectActiveImageUrls(config) {
476
+ const urls = new Set();
477
+ (config.layers || []).forEach((layer) => {
478
+ if (!layer.enabled || layer.kind !== "image")
479
+ return;
480
+ const src = String(layer.src || "").trim();
481
+ if (!src)
482
+ return;
483
+ urls.add(src);
484
+ });
485
+ return Array.from(urls);
486
+ }
487
+ async loadImageSize(src) {
488
+ try {
489
+ const image = await fabric_1.FabricImage.fromURL(src, {
490
+ crossOrigin: "anonymous",
491
+ });
492
+ const width = Number(image?.width || 0);
493
+ const height = Number(image?.height || 0);
494
+ if (width > 0 && height > 0) {
495
+ return { width, height };
496
+ }
497
+ }
498
+ catch (error) {
499
+ console.error("[BackgroundTool] Failed to load image", src, error);
500
+ }
501
+ return null;
502
+ }
503
+ updateBackground() {
504
+ void this.updateBackgroundAsync();
505
+ }
506
+ async updateBackgroundAsync() {
507
+ if (!this.canvasService)
508
+ return;
509
+ const seq = ++this.renderSeq;
510
+ const currentConfig = cloneConfig(this.config);
511
+ const activeUrls = this.collectActiveImageUrls(currentConfig);
512
+ if (activeUrls.length > 0) {
513
+ await Promise.all(activeUrls.map((url) => this.sourceSizeCache.ensureImageSize(url)));
514
+ if (seq !== this.renderSeq)
515
+ return;
516
+ }
517
+ this.specs = this.buildBackgroundSpecs(currentConfig);
518
+ await this.canvasService.flushRenderFromProducers();
519
+ if (seq !== this.renderSeq)
520
+ return;
521
+ this.canvasService.requestRenderAll();
522
+ }
523
+ }
524
+ exports.BackgroundTool = BackgroundTool;
@@ -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("./BackgroundTool"), exports);