@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
@@ -6,16 +6,17 @@ import {
6
6
  ConfigurationService,
7
7
  ToolSessionService,
8
8
  } from "@pooder/core";
9
- import { CanvasService, RenderObjectSpec } from "../services";
10
- import { resolveFeaturePosition } from "./geometry";
11
- import { ConstraintRegistry, ConstraintFeature } from "./constraints";
12
- import { completeFeaturesStrict } from "./featureComplete";
9
+ import { CanvasService, RenderObjectSpec } from "../../services";
10
+ import { resolveFeaturePosition } from "../geometry";
11
+ import { ConstraintRegistry, ConstraintFeature } from "../constraints";
12
+ import { completeFeaturesStrict } from "../featureComplete";
13
13
  import {
14
14
  readSizeState,
15
15
  type SceneGeometrySnapshot as DielineGeometry,
16
- } from "./sceneLayoutModel";
17
-
18
- const FEATURE_OVERLAY_LAYER_ID = "feature-overlay";
16
+ } from "../../shared/scene/sceneLayoutModel";
17
+ import { FEATURE_OVERLAY_LAYER_ID } from "../../shared/constants/layers";
18
+ import { SubscriptionBag } from "../../shared/runtime/subscriptions";
19
+ import { cloneWithJson } from "../../shared/runtime/sessionState";
19
20
  const FEATURE_STROKE_WIDTH = 2;
20
21
  const DEFAULT_RECT_SIZE = 10;
21
22
  const DEFAULT_CIRCLE_RADIUS = 5;
@@ -69,6 +70,7 @@ export class FeatureTool implements Extension {
69
70
  private renderProducerDisposable?: { dispose: () => void };
70
71
  private specs: RenderObjectSpec[] = [];
71
72
  private renderSeq = 0;
73
+ private readonly subscriptions = new SubscriptionBag();
72
74
 
73
75
  private handleMoving: ((e: any) => void) | null = null;
74
76
  private handleModified: ((e: any) => void) | null = null;
@@ -89,6 +91,7 @@ export class FeatureTool implements Extension {
89
91
  }
90
92
 
91
93
  activate(context: ExtensionContext) {
94
+ this.subscriptions.disposeAll();
92
95
  this.context = context;
93
96
  this.canvasService = context.services.get<CanvasService>("CanvasService");
94
97
 
@@ -122,18 +125,21 @@ export class FeatureTool implements Extension {
122
125
  this.workingFeatures = this.cloneFeatures(features);
123
126
  this.hasWorkingChanges = false;
124
127
 
125
- configService.onAnyChange((e: { key: string; value: any }) => {
126
- if (this.isUpdatingConfig) return;
128
+ this.subscriptions.onConfigChange(
129
+ configService,
130
+ (e: { key: string; value: any }) => {
131
+ if (this.isUpdatingConfig) return;
127
132
 
128
- if (e.key === "dieline.features") {
129
- if (this.isFeatureSessionActive) return;
130
- const next = (e.value || []) as ConstraintFeature[];
131
- this.workingFeatures = this.cloneFeatures(next);
132
- this.hasWorkingChanges = false;
133
- this.redraw();
134
- this.emitWorkingChange();
135
- }
136
- });
133
+ if (e.key === "dieline.features") {
134
+ if (this.isFeatureSessionActive) return;
135
+ const next = (e.value || []) as ConstraintFeature[];
136
+ this.workingFeatures = this.cloneFeatures(next);
137
+ this.hasWorkingChanges = false;
138
+ this.redraw();
139
+ this.emitWorkingChange();
140
+ }
141
+ },
142
+ );
137
143
  }
138
144
 
139
145
  const toolSessionService =
@@ -143,13 +149,13 @@ export class FeatureTool implements Extension {
143
149
  () => this.hasWorkingChanges,
144
150
  );
145
151
 
146
- context.eventBus.on("tool:activated", this.onToolActivated);
152
+ this.subscriptions.on(context.eventBus, "tool:activated", this.onToolActivated);
147
153
 
148
154
  this.setup();
149
155
  }
150
156
 
151
157
  deactivate(context: ExtensionContext) {
152
- context.eventBus.off("tool:activated", this.onToolActivated);
158
+ this.subscriptions.disposeAll();
153
159
  this.restoreSessionFeaturesToConfig();
154
160
  this.dirtyTrackerDisposable?.dispose();
155
161
  this.dirtyTrackerDisposable = undefined;
@@ -303,7 +309,7 @@ export class FeatureTool implements Extension {
303
309
  }
304
310
 
305
311
  private cloneFeatures(features: ConstraintFeature[]): ConstraintFeature[] {
306
- return JSON.parse(JSON.stringify(features || [])) as ConstraintFeature[];
312
+ return cloneWithJson(features || []) as ConstraintFeature[];
307
313
  }
308
314
 
309
315
  private getConfigService(): ConfigurationService | undefined {
@@ -0,0 +1 @@
1
+ export * from "./FeatureTool";
@@ -7,14 +7,15 @@ import {
7
7
  ConfigurationService,
8
8
  } from "@pooder/core";
9
9
  import { FabricImage } from "fabric";
10
- import { CanvasService, RenderObjectSpec } from "../services";
11
-
12
- interface SourceSize {
13
- width: number;
14
- height: number;
15
- }
10
+ import { CanvasService, RenderObjectSpec } from "../../services";
11
+ import { FILM_LAYER_ID } from "../../shared/constants/layers";
12
+ import {
13
+ createSourceSizeCache,
14
+ getCoverScale,
15
+ type SourceSize,
16
+ } from "../../shared/imaging/sourceSizeCache";
17
+ import { SubscriptionBag } from "../../shared/runtime/subscriptions";
16
18
 
17
- const FILM_LAYER_ID = "overlay";
18
19
  const FILM_IMAGE_ID = "film-image";
19
20
  const DEFAULT_WIDTH = 800;
20
21
  const DEFAULT_HEIGHT = 600;
@@ -34,8 +35,10 @@ export class FilmTool implements Extension {
34
35
  private renderProducerDisposable?: { dispose: () => void };
35
36
  private renderSeq = 0;
36
37
  private renderImageUrl = "";
37
- private sourceSizeBySrc: Map<string, SourceSize> = new Map();
38
- private pendingSizeBySrc: Map<string, Promise<SourceSize | null>> = new Map();
38
+ private sourceSizeCache = createSourceSizeCache((src) =>
39
+ this.loadImageSize(src),
40
+ );
41
+ private readonly subscriptions = new SubscriptionBag();
39
42
  private onCanvasResized = () => {
40
43
  this.updateFilm();
41
44
  };
@@ -52,6 +55,7 @@ export class FilmTool implements Extension {
52
55
  }
53
56
 
54
57
  activate(context: ExtensionContext) {
58
+ this.subscriptions.disposeAll();
55
59
  this.canvasService = context.services.get<CanvasService>("CanvasService");
56
60
  if (!this.canvasService) {
57
61
  console.warn("CanvasService not found for FilmTool");
@@ -83,29 +87,33 @@ export class FilmTool implements Extension {
83
87
  this.opacity = configService.get("film.opacity", this.opacity);
84
88
 
85
89
  // Listen for changes
86
- configService.onAnyChange((e: { key: string; value: any }) => {
87
- if (e.key.startsWith("film.")) {
88
- const prop = e.key.split(".")[1];
89
- console.log(
90
- `[FilmTool] Config change detected: ${e.key} -> ${e.value}`,
91
- );
92
- if (prop && prop in this) {
93
- (this as any)[prop] = e.value;
94
- this.updateFilm();
90
+ this.subscriptions.onConfigChange(
91
+ configService,
92
+ (e: { key: string; value: any }) => {
93
+ if (e.key.startsWith("film.")) {
94
+ const prop = e.key.split(".")[1];
95
+ console.log(
96
+ `[FilmTool] Config change detected: ${e.key} -> ${e.value}`,
97
+ );
98
+ if (prop && prop in this) {
99
+ (this as any)[prop] = e.value;
100
+ this.updateFilm();
101
+ }
95
102
  }
96
103
  }
97
- });
104
+ );
98
105
  }
99
106
 
100
- context.eventBus.on("canvas:resized", this.onCanvasResized);
107
+ this.subscriptions.on(context.eventBus, "canvas:resized", this.onCanvasResized);
101
108
  this.updateFilm();
102
109
  }
103
110
 
104
111
  deactivate(context: ExtensionContext) {
105
- context.eventBus.off("canvas:resized", this.onCanvasResized);
112
+ this.subscriptions.disposeAll();
106
113
  this.renderSeq += 1;
107
114
  this.specs = [];
108
115
  this.renderImageUrl = "";
116
+ this.sourceSizeCache.clear();
109
117
  this.renderProducerDisposable?.dispose();
110
118
  this.renderProducerDisposable = undefined;
111
119
  if (!this.canvasService) return;
@@ -173,10 +181,13 @@ export class FilmTool implements Extension {
173
181
  return [];
174
182
  }
175
183
  const { width, height } = this.getViewportSize();
176
- const sourceSize = this.sourceSizeBySrc.get(imageUrl);
184
+ const sourceSize = this.sourceSizeCache.getSourceSize(imageUrl);
177
185
  const sourceWidth = Math.max(1, Number(sourceSize?.width || width));
178
186
  const sourceHeight = Math.max(1, Number(sourceSize?.height || height));
179
- const coverScale = Math.max(width / sourceWidth, height / sourceHeight);
187
+ const coverScale = getCoverScale(
188
+ { width, height },
189
+ { width: sourceWidth, height: sourceHeight },
190
+ );
180
191
  return [
181
192
  {
182
193
  id: FILM_IMAGE_ID,
@@ -204,27 +215,6 @@ export class FilmTool implements Extension {
204
215
  ];
205
216
  }
206
217
 
207
- private async ensureImageSize(src: string): Promise<SourceSize | null> {
208
- if (!src) return null;
209
- const cached = this.sourceSizeBySrc.get(src);
210
- if (cached) return cached;
211
-
212
- const pending = this.pendingSizeBySrc.get(src);
213
- if (pending) {
214
- return pending;
215
- }
216
-
217
- const task = this.loadImageSize(src);
218
- this.pendingSizeBySrc.set(src, task);
219
- try {
220
- return await task;
221
- } finally {
222
- if (this.pendingSizeBySrc.get(src) === task) {
223
- this.pendingSizeBySrc.delete(src);
224
- }
225
- }
226
- }
227
-
228
218
  private async loadImageSize(src: string): Promise<SourceSize | null> {
229
219
  try {
230
220
  const image = await FabricImage.fromURL(src, {
@@ -233,9 +223,7 @@ export class FilmTool implements Extension {
233
223
  const width = Number(image?.width || 0);
234
224
  const height = Number(image?.height || 0);
235
225
  if (width > 0 && height > 0) {
236
- const size = { width, height };
237
- this.sourceSizeBySrc.set(src, size);
238
- return size;
226
+ return { width, height };
239
227
  }
240
228
  } catch (error) {
241
229
  console.error("[FilmTool] Failed to load film image", src, error);
@@ -255,7 +243,7 @@ export class FilmTool implements Extension {
255
243
  if (!nextUrl) {
256
244
  this.renderImageUrl = "";
257
245
  } else if (nextUrl !== this.renderImageUrl) {
258
- const loaded = await this.ensureImageSize(nextUrl);
246
+ const loaded = await this.sourceSizeCache.ensureImageSize(nextUrl);
259
247
  if (seq !== this.renderSeq) return;
260
248
  if (loaded) {
261
249
  this.renderImageUrl = nextUrl;
@@ -0,0 +1 @@
1
+ export * from "./FilmTool";