@pooder/kit 5.0.2 → 5.0.3

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.
@@ -16,6 +16,8 @@ class FeatureTool {
16
16
  this.workingFeatures = [];
17
17
  this.isUpdatingConfig = false;
18
18
  this.isToolActive = false;
19
+ this.isFeatureSessionActive = false;
20
+ this.sessionOriginalFeatures = null;
19
21
  this.hasWorkingChanges = false;
20
22
  this.handleMoving = null;
21
23
  this.handleModified = null;
@@ -23,6 +25,9 @@ class FeatureTool {
23
25
  this.currentGeometry = null;
24
26
  this.onToolActivated = (event) => {
25
27
  this.isToolActive = event.id === this.id;
28
+ if (!this.isToolActive) {
29
+ this.restoreSessionFeaturesToConfig();
30
+ }
26
31
  this.updateVisibility();
27
32
  };
28
33
  if (options) {
@@ -46,6 +51,8 @@ class FeatureTool {
46
51
  if (this.isUpdatingConfig)
47
52
  return;
48
53
  if (e.key === "dieline.features") {
54
+ if (this.isFeatureSessionActive)
55
+ return;
49
56
  const next = (e.value || []);
50
57
  this.workingFeatures = this.cloneFeatures(next);
51
58
  this.hasWorkingChanges = false;
@@ -62,6 +69,7 @@ class FeatureTool {
62
69
  }
63
70
  deactivate(context) {
64
71
  context.eventBus.off("tool:activated", this.onToolActivated);
72
+ this.restoreSessionFeaturesToConfig();
65
73
  this.dirtyTrackerDisposable?.dispose();
66
74
  this.dirtyTrackerDisposable = undefined;
67
75
  this.teardown();
@@ -95,9 +103,9 @@ class FeatureTool {
95
103
  name: "Feature",
96
104
  interaction: "session",
97
105
  commands: {
98
- begin: "resetWorkingFeatures",
106
+ begin: "beginFeatureSession",
99
107
  commit: "completeFeatures",
100
- rollback: "resetWorkingFeatures",
108
+ rollback: "rollbackFeatureSession",
101
109
  },
102
110
  session: {
103
111
  autoBegin: false,
@@ -106,6 +114,25 @@ class FeatureTool {
106
114
  },
107
115
  ],
108
116
  [core_1.ContributionPointIds.COMMANDS]: [
117
+ {
118
+ command: "beginFeatureSession",
119
+ title: "Begin Feature Session",
120
+ handler: async () => {
121
+ if (this.isFeatureSessionActive) {
122
+ return { ok: true };
123
+ }
124
+ const original = this.getCommittedFeatures();
125
+ this.sessionOriginalFeatures = this.cloneFeatures(original);
126
+ this.isFeatureSessionActive = true;
127
+ await this.refreshGeometry();
128
+ this.setWorkingFeatures(this.cloneFeatures(original));
129
+ this.hasWorkingChanges = false;
130
+ this.redraw();
131
+ this.emitWorkingChange();
132
+ this.updateCommittedFeatures([]);
133
+ return { ok: true };
134
+ },
135
+ },
109
136
  {
110
137
  command: "addFeature",
111
138
  title: "Add Edge Feature",
@@ -158,17 +185,25 @@ class FeatureTool {
158
185
  },
159
186
  },
160
187
  {
161
- command: "resetWorkingFeatures",
162
- title: "Reset Working Features",
188
+ command: "rollbackFeatureSession",
189
+ title: "Rollback Feature Session",
163
190
  handler: async () => {
164
- const configService = this.context?.services.get("ConfigurationService");
165
- const next = (configService?.get("dieline.features", []) ||
166
- []);
191
+ const original = this.cloneFeatures(this.sessionOriginalFeatures || this.getCommittedFeatures());
167
192
  await this.refreshGeometry();
168
- this.setWorkingFeatures(this.cloneFeatures(next));
193
+ this.setWorkingFeatures(original);
169
194
  this.hasWorkingChanges = false;
170
195
  this.redraw();
171
196
  this.emitWorkingChange();
197
+ this.updateCommittedFeatures(original);
198
+ this.clearFeatureSessionState();
199
+ return { ok: true };
200
+ },
201
+ },
202
+ {
203
+ command: "resetWorkingFeatures",
204
+ title: "Reset Working Features",
205
+ handler: async () => {
206
+ await this.resetWorkingFeaturesFromSource();
172
207
  return { ok: true };
173
208
  },
174
209
  },
@@ -192,6 +227,38 @@ class FeatureTool {
192
227
  cloneFeatures(features) {
193
228
  return JSON.parse(JSON.stringify(features || []));
194
229
  }
230
+ getConfigService() {
231
+ return this.context?.services.get("ConfigurationService");
232
+ }
233
+ getCommittedFeatures() {
234
+ const configService = this.getConfigService();
235
+ const committed = (configService?.get("dieline.features", []) ||
236
+ []);
237
+ return this.cloneFeatures(committed);
238
+ }
239
+ updateCommittedFeatures(next) {
240
+ const configService = this.getConfigService();
241
+ if (!configService)
242
+ return;
243
+ this.isUpdatingConfig = true;
244
+ try {
245
+ configService.update("dieline.features", next);
246
+ }
247
+ finally {
248
+ this.isUpdatingConfig = false;
249
+ }
250
+ }
251
+ clearFeatureSessionState() {
252
+ this.isFeatureSessionActive = false;
253
+ this.sessionOriginalFeatures = null;
254
+ }
255
+ restoreSessionFeaturesToConfig() {
256
+ if (!this.isFeatureSessionActive)
257
+ return;
258
+ const original = this.cloneFeatures(this.sessionOriginalFeatures || this.getCommittedFeatures());
259
+ this.updateCommittedFeatures(original);
260
+ this.clearFeatureSessionState();
261
+ }
195
262
  emitWorkingChange() {
196
263
  this.context?.eventBus.emit("feature:working:change", {
197
264
  features: this.cloneFeatures(this.workingFeatures),
@@ -210,6 +277,16 @@ class FeatureTool {
210
277
  }
211
278
  catch (e) { }
212
279
  }
280
+ async resetWorkingFeaturesFromSource() {
281
+ const next = this.cloneFeatures(this.isFeatureSessionActive && this.sessionOriginalFeatures
282
+ ? this.sessionOriginalFeatures
283
+ : this.getCommittedFeatures());
284
+ await this.refreshGeometry();
285
+ this.setWorkingFeatures(next);
286
+ this.hasWorkingChanges = false;
287
+ this.redraw();
288
+ this.emitWorkingChange();
289
+ }
213
290
  setWorkingFeatures(next) {
214
291
  this.workingFeatures = next;
215
292
  }
@@ -265,13 +342,7 @@ class FeatureTool {
265
342
  const dielineWidth = sizeState.actualWidthMm;
266
343
  const dielineHeight = sizeState.actualHeightMm;
267
344
  const result = (0, featureComplete_1.completeFeaturesStrict)(this.workingFeatures, { dielineWidth, dielineHeight }, (next) => {
268
- this.isUpdatingConfig = true;
269
- try {
270
- configService.update("dieline.features", next);
271
- }
272
- finally {
273
- this.isUpdatingConfig = false;
274
- }
345
+ this.updateCommittedFeatures(next);
275
346
  this.workingFeatures = this.cloneFeatures(next);
276
347
  this.emitWorkingChange();
277
348
  });
@@ -282,6 +353,7 @@ class FeatureTool {
282
353
  };
283
354
  }
284
355
  this.hasWorkingChanges = false;
356
+ this.clearFeatureSessionState();
285
357
  // Keep feature markers above dieline overlay after config-driven redraw.
286
358
  this.redraw();
287
359
  return { ok: true };
@@ -275,7 +275,7 @@ class ImageTool {
275
275
  id: "image.frame.outerBackground",
276
276
  type: "color",
277
277
  label: "Image Frame Outer Background",
278
- default: "rgba(0,0,0,0.18)",
278
+ default: "#f5f5f5",
279
279
  },
280
280
  ],
281
281
  [core_1.ContributionPointIds.COMMANDS]: [
@@ -318,6 +318,7 @@ class ImageTool {
318
318
  this.workingItems = this.cloneItems(this.items);
319
319
  this.hasWorkingChanges = false;
320
320
  this.updateImages();
321
+ this.emitWorkingChange();
321
322
  },
322
323
  },
323
324
  {
@@ -436,6 +437,12 @@ class ImageTool {
436
437
  cloneItems(items) {
437
438
  return this.normalizeItems((items || []).map((i) => ({ ...i })));
438
439
  }
440
+ emitWorkingChange(changedId = null) {
441
+ this.context?.eventBus.emit("image:working:change", {
442
+ changedId,
443
+ items: this.cloneItems(this.workingItems),
444
+ });
445
+ }
439
446
  generateId() {
440
447
  return Math.random().toString(36).substring(2, 9);
441
448
  }
@@ -509,6 +516,7 @@ class ImageTool {
509
516
  return;
510
517
  this.workingItems = this.cloneItems([...this.workingItems, item]);
511
518
  this.updateImages();
519
+ this.emitWorkingChange(item.id);
512
520
  }
513
521
  async updateImage(id, updates, options = {}) {
514
522
  this.syncToolActiveFromWorkbench();
@@ -681,7 +689,7 @@ class ImageTool {
681
689
  strokeStyle,
682
690
  dashLength: Number.isFinite(dashLength) ? Math.max(1, dashLength) : 8,
683
691
  innerBackground: this.getConfig("image.frame.innerBackground", "rgba(0,0,0,0)") || "rgba(0,0,0,0)",
684
- outerBackground: this.getConfig("image.frame.outerBackground", "rgba(0,0,0,0.18)") || "rgba(0,0,0,0.18)",
692
+ outerBackground: "#f5f5f5",
685
693
  };
686
694
  }
687
695
  resolveRenderImageState(item) {
@@ -833,10 +841,15 @@ class ImageTool {
833
841
  const canvasW = this.canvasService.canvas.width || 0;
834
842
  const canvasH = this.canvasService.canvas.height || 0;
835
843
  const visual = this.getFrameVisualConfig();
836
- const topH = Math.max(0, frame.top);
837
- const bottomH = Math.max(0, canvasH - (frame.top + frame.height));
838
- const leftW = Math.max(0, frame.left);
839
- const rightW = Math.max(0, canvasW - (frame.left + frame.width));
844
+ const frameLeft = Math.max(0, Math.min(canvasW, frame.left));
845
+ const frameTop = Math.max(0, Math.min(canvasH, frame.top));
846
+ const frameRight = Math.max(frameLeft, Math.min(canvasW, frame.left + frame.width));
847
+ const frameBottom = Math.max(frameTop, Math.min(canvasH, frame.top + frame.height));
848
+ const visibleFrameH = Math.max(0, frameBottom - frameTop);
849
+ const topH = frameTop;
850
+ const bottomH = Math.max(0, canvasH - frameBottom);
851
+ const leftW = frameLeft;
852
+ const rightW = Math.max(0, canvasW - frameRight);
840
853
  const mask = [
841
854
  {
842
855
  id: "image.cropMask.top",
@@ -860,7 +873,7 @@ class ImageTool {
860
873
  data: { id: "image.cropMask.bottom", zIndex: 2 },
861
874
  props: {
862
875
  left: canvasW / 2,
863
- top: frame.top + frame.height + bottomH / 2,
876
+ top: frameBottom + bottomH / 2,
864
877
  width: canvasW,
865
878
  height: bottomH,
866
879
  originX: "center",
@@ -876,9 +889,9 @@ class ImageTool {
876
889
  data: { id: "image.cropMask.left", zIndex: 3 },
877
890
  props: {
878
891
  left: leftW / 2,
879
- top: frame.top + frame.height / 2,
892
+ top: frameTop + visibleFrameH / 2,
880
893
  width: leftW,
881
- height: frame.height,
894
+ height: visibleFrameH,
882
895
  originX: "center",
883
896
  originY: "center",
884
897
  fill: visual.outerBackground,
@@ -891,10 +904,10 @@ class ImageTool {
891
904
  type: "rect",
892
905
  data: { id: "image.cropMask.right", zIndex: 4 },
893
906
  props: {
894
- left: frame.left + frame.width + rightW / 2,
895
- top: frame.top + frame.height / 2,
907
+ left: frameRight + rightW / 2,
908
+ top: frameTop + visibleFrameH / 2,
896
909
  width: rightW,
897
- height: frame.height,
910
+ height: visibleFrameH,
898
911
  originX: "center",
899
912
  originY: "center",
900
913
  fill: visual.outerBackground,
@@ -988,6 +1001,7 @@ class ImageTool {
988
1001
  if (this.isToolActive) {
989
1002
  this.updateImages();
990
1003
  }
1004
+ this.emitWorkingChange(id);
991
1005
  }
992
1006
  async updateImageInConfig(id, updates) {
993
1007
  const index = this.items.findIndex((item) => item.id === id);
@@ -1073,6 +1087,7 @@ class ImageTool {
1073
1087
  this.isImageSelectionActive = true;
1074
1088
  this.focusedImageId = id;
1075
1089
  this.updateImages();
1090
+ this.emitWorkingChange(id);
1076
1091
  }
1077
1092
  focusImageSelection(id) {
1078
1093
  if (!this.canvasService)
@@ -1162,6 +1177,7 @@ class ImageTool {
1162
1177
  this.hasWorkingChanges = false;
1163
1178
  this.workingItems = this.cloneItems(next);
1164
1179
  this.updateConfig(next);
1180
+ this.emitWorkingChange(focusId);
1165
1181
  if (focusId) {
1166
1182
  this.focusedImageId = focusId;
1167
1183
  this.isImageSelectionActive = true;
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @pooder/kit
2
2
 
3
+ ## 5.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - bugfix
8
+
3
9
  ## 5.0.2
4
10
 
5
11
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -178,6 +178,8 @@ declare class FeatureTool implements Extension {
178
178
  private context?;
179
179
  private isUpdatingConfig;
180
180
  private isToolActive;
181
+ private isFeatureSessionActive;
182
+ private sessionOriginalFeatures;
181
183
  private hasWorkingChanges;
182
184
  private dirtyTrackerDisposable?;
183
185
  private handleMoving;
@@ -209,8 +211,14 @@ declare class FeatureTool implements Extension {
209
211
  [ContributionPointIds.COMMANDS]: CommandContribution[];
210
212
  };
211
213
  private cloneFeatures;
214
+ private getConfigService;
215
+ private getCommittedFeatures;
216
+ private updateCommittedFeatures;
217
+ private clearFeatureSessionState;
218
+ private restoreSessionFeaturesToConfig;
212
219
  private emitWorkingChange;
213
220
  private refreshGeometry;
221
+ private resetWorkingFeaturesFromSource;
214
222
  private setWorkingFeatures;
215
223
  private updateWorkingGroupPosition;
216
224
  private completeFeatures;
package/dist/index.d.ts CHANGED
@@ -178,6 +178,8 @@ declare class FeatureTool implements Extension {
178
178
  private context?;
179
179
  private isUpdatingConfig;
180
180
  private isToolActive;
181
+ private isFeatureSessionActive;
182
+ private sessionOriginalFeatures;
181
183
  private hasWorkingChanges;
182
184
  private dirtyTrackerDisposable?;
183
185
  private handleMoving;
@@ -209,8 +211,14 @@ declare class FeatureTool implements Extension {
209
211
  [ContributionPointIds.COMMANDS]: CommandContribution[];
210
212
  };
211
213
  private cloneFeatures;
214
+ private getConfigService;
215
+ private getCommittedFeatures;
216
+ private updateCommittedFeatures;
217
+ private clearFeatureSessionState;
218
+ private restoreSessionFeaturesToConfig;
212
219
  private emitWorkingChange;
213
220
  private refreshGeometry;
221
+ private resetWorkingFeaturesFromSource;
214
222
  private setWorkingFeatures;
215
223
  private updateWorkingGroupPosition;
216
224
  private completeFeatures;
package/dist/index.js CHANGED
@@ -3005,6 +3005,8 @@ var FeatureTool = class {
3005
3005
  this.workingFeatures = [];
3006
3006
  this.isUpdatingConfig = false;
3007
3007
  this.isToolActive = false;
3008
+ this.isFeatureSessionActive = false;
3009
+ this.sessionOriginalFeatures = null;
3008
3010
  this.hasWorkingChanges = false;
3009
3011
  this.handleMoving = null;
3010
3012
  this.handleModified = null;
@@ -3012,6 +3014,9 @@ var FeatureTool = class {
3012
3014
  this.currentGeometry = null;
3013
3015
  this.onToolActivated = (event) => {
3014
3016
  this.isToolActive = event.id === this.id;
3017
+ if (!this.isToolActive) {
3018
+ this.restoreSessionFeaturesToConfig();
3019
+ }
3015
3020
  this.updateVisibility();
3016
3021
  };
3017
3022
  if (options) {
@@ -3035,6 +3040,7 @@ var FeatureTool = class {
3035
3040
  configService.onAnyChange((e) => {
3036
3041
  if (this.isUpdatingConfig) return;
3037
3042
  if (e.key === "dieline.features") {
3043
+ if (this.isFeatureSessionActive) return;
3038
3044
  const next = e.value || [];
3039
3045
  this.workingFeatures = this.cloneFeatures(next);
3040
3046
  this.hasWorkingChanges = false;
@@ -3054,6 +3060,7 @@ var FeatureTool = class {
3054
3060
  deactivate(context) {
3055
3061
  var _a;
3056
3062
  context.eventBus.off("tool:activated", this.onToolActivated);
3063
+ this.restoreSessionFeaturesToConfig();
3057
3064
  (_a = this.dirtyTrackerDisposable) == null ? void 0 : _a.dispose();
3058
3065
  this.dirtyTrackerDisposable = void 0;
3059
3066
  this.teardown();
@@ -3085,9 +3092,9 @@ var FeatureTool = class {
3085
3092
  name: "Feature",
3086
3093
  interaction: "session",
3087
3094
  commands: {
3088
- begin: "resetWorkingFeatures",
3095
+ begin: "beginFeatureSession",
3089
3096
  commit: "completeFeatures",
3090
- rollback: "resetWorkingFeatures"
3097
+ rollback: "rollbackFeatureSession"
3091
3098
  },
3092
3099
  session: {
3093
3100
  autoBegin: false,
@@ -3096,6 +3103,25 @@ var FeatureTool = class {
3096
3103
  }
3097
3104
  ],
3098
3105
  [import_core4.ContributionPointIds.COMMANDS]: [
3106
+ {
3107
+ command: "beginFeatureSession",
3108
+ title: "Begin Feature Session",
3109
+ handler: async () => {
3110
+ if (this.isFeatureSessionActive) {
3111
+ return { ok: true };
3112
+ }
3113
+ const original = this.getCommittedFeatures();
3114
+ this.sessionOriginalFeatures = this.cloneFeatures(original);
3115
+ this.isFeatureSessionActive = true;
3116
+ await this.refreshGeometry();
3117
+ this.setWorkingFeatures(this.cloneFeatures(original));
3118
+ this.hasWorkingChanges = false;
3119
+ this.redraw();
3120
+ this.emitWorkingChange();
3121
+ this.updateCommittedFeatures([]);
3122
+ return { ok: true };
3123
+ }
3124
+ },
3099
3125
  {
3100
3126
  command: "addFeature",
3101
3127
  title: "Add Edge Feature",
@@ -3148,19 +3174,27 @@ var FeatureTool = class {
3148
3174
  }
3149
3175
  },
3150
3176
  {
3151
- command: "resetWorkingFeatures",
3152
- title: "Reset Working Features",
3177
+ command: "rollbackFeatureSession",
3178
+ title: "Rollback Feature Session",
3153
3179
  handler: async () => {
3154
- var _a;
3155
- const configService = (_a = this.context) == null ? void 0 : _a.services.get(
3156
- "ConfigurationService"
3180
+ const original = this.cloneFeatures(
3181
+ this.sessionOriginalFeatures || this.getCommittedFeatures()
3157
3182
  );
3158
- const next = (configService == null ? void 0 : configService.get("dieline.features", [])) || [];
3159
3183
  await this.refreshGeometry();
3160
- this.setWorkingFeatures(this.cloneFeatures(next));
3184
+ this.setWorkingFeatures(original);
3161
3185
  this.hasWorkingChanges = false;
3162
3186
  this.redraw();
3163
3187
  this.emitWorkingChange();
3188
+ this.updateCommittedFeatures(original);
3189
+ this.clearFeatureSessionState();
3190
+ return { ok: true };
3191
+ }
3192
+ },
3193
+ {
3194
+ command: "resetWorkingFeatures",
3195
+ title: "Reset Working Features",
3196
+ handler: async () => {
3197
+ await this.resetWorkingFeaturesFromSource();
3164
3198
  return { ok: true };
3165
3199
  }
3166
3200
  },
@@ -3184,6 +3218,37 @@ var FeatureTool = class {
3184
3218
  cloneFeatures(features) {
3185
3219
  return JSON.parse(JSON.stringify(features || []));
3186
3220
  }
3221
+ getConfigService() {
3222
+ var _a;
3223
+ return (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
3224
+ }
3225
+ getCommittedFeatures() {
3226
+ const configService = this.getConfigService();
3227
+ const committed = (configService == null ? void 0 : configService.get("dieline.features", [])) || [];
3228
+ return this.cloneFeatures(committed);
3229
+ }
3230
+ updateCommittedFeatures(next) {
3231
+ const configService = this.getConfigService();
3232
+ if (!configService) return;
3233
+ this.isUpdatingConfig = true;
3234
+ try {
3235
+ configService.update("dieline.features", next);
3236
+ } finally {
3237
+ this.isUpdatingConfig = false;
3238
+ }
3239
+ }
3240
+ clearFeatureSessionState() {
3241
+ this.isFeatureSessionActive = false;
3242
+ this.sessionOriginalFeatures = null;
3243
+ }
3244
+ restoreSessionFeaturesToConfig() {
3245
+ if (!this.isFeatureSessionActive) return;
3246
+ const original = this.cloneFeatures(
3247
+ this.sessionOriginalFeatures || this.getCommittedFeatures()
3248
+ );
3249
+ this.updateCommittedFeatures(original);
3250
+ this.clearFeatureSessionState();
3251
+ }
3187
3252
  emitWorkingChange() {
3188
3253
  var _a;
3189
3254
  (_a = this.context) == null ? void 0 : _a.eventBus.emit("feature:working:change", {
@@ -3202,6 +3267,16 @@ var FeatureTool = class {
3202
3267
  } catch (e) {
3203
3268
  }
3204
3269
  }
3270
+ async resetWorkingFeaturesFromSource() {
3271
+ const next = this.cloneFeatures(
3272
+ this.isFeatureSessionActive && this.sessionOriginalFeatures ? this.sessionOriginalFeatures : this.getCommittedFeatures()
3273
+ );
3274
+ await this.refreshGeometry();
3275
+ this.setWorkingFeatures(next);
3276
+ this.hasWorkingChanges = false;
3277
+ this.redraw();
3278
+ this.emitWorkingChange();
3279
+ }
3205
3280
  setWorkingFeatures(next) {
3206
3281
  this.workingFeatures = next;
3207
3282
  }
@@ -3258,12 +3333,7 @@ var FeatureTool = class {
3258
3333
  this.workingFeatures,
3259
3334
  { dielineWidth, dielineHeight },
3260
3335
  (next) => {
3261
- this.isUpdatingConfig = true;
3262
- try {
3263
- configService.update("dieline.features", next);
3264
- } finally {
3265
- this.isUpdatingConfig = false;
3266
- }
3336
+ this.updateCommittedFeatures(next);
3267
3337
  this.workingFeatures = this.cloneFeatures(next);
3268
3338
  this.emitWorkingChange();
3269
3339
  }
@@ -3275,6 +3345,7 @@ var FeatureTool = class {
3275
3345
  };
3276
3346
  }
3277
3347
  this.hasWorkingChanges = false;
3348
+ this.clearFeatureSessionState();
3278
3349
  this.redraw();
3279
3350
  return { ok: true };
3280
3351
  }
package/dist/index.mjs CHANGED
@@ -2954,6 +2954,8 @@ var FeatureTool = class {
2954
2954
  this.workingFeatures = [];
2955
2955
  this.isUpdatingConfig = false;
2956
2956
  this.isToolActive = false;
2957
+ this.isFeatureSessionActive = false;
2958
+ this.sessionOriginalFeatures = null;
2957
2959
  this.hasWorkingChanges = false;
2958
2960
  this.handleMoving = null;
2959
2961
  this.handleModified = null;
@@ -2961,6 +2963,9 @@ var FeatureTool = class {
2961
2963
  this.currentGeometry = null;
2962
2964
  this.onToolActivated = (event) => {
2963
2965
  this.isToolActive = event.id === this.id;
2966
+ if (!this.isToolActive) {
2967
+ this.restoreSessionFeaturesToConfig();
2968
+ }
2964
2969
  this.updateVisibility();
2965
2970
  };
2966
2971
  if (options) {
@@ -2984,6 +2989,7 @@ var FeatureTool = class {
2984
2989
  configService.onAnyChange((e) => {
2985
2990
  if (this.isUpdatingConfig) return;
2986
2991
  if (e.key === "dieline.features") {
2992
+ if (this.isFeatureSessionActive) return;
2987
2993
  const next = e.value || [];
2988
2994
  this.workingFeatures = this.cloneFeatures(next);
2989
2995
  this.hasWorkingChanges = false;
@@ -3003,6 +3009,7 @@ var FeatureTool = class {
3003
3009
  deactivate(context) {
3004
3010
  var _a;
3005
3011
  context.eventBus.off("tool:activated", this.onToolActivated);
3012
+ this.restoreSessionFeaturesToConfig();
3006
3013
  (_a = this.dirtyTrackerDisposable) == null ? void 0 : _a.dispose();
3007
3014
  this.dirtyTrackerDisposable = void 0;
3008
3015
  this.teardown();
@@ -3034,9 +3041,9 @@ var FeatureTool = class {
3034
3041
  name: "Feature",
3035
3042
  interaction: "session",
3036
3043
  commands: {
3037
- begin: "resetWorkingFeatures",
3044
+ begin: "beginFeatureSession",
3038
3045
  commit: "completeFeatures",
3039
- rollback: "resetWorkingFeatures"
3046
+ rollback: "rollbackFeatureSession"
3040
3047
  },
3041
3048
  session: {
3042
3049
  autoBegin: false,
@@ -3045,6 +3052,25 @@ var FeatureTool = class {
3045
3052
  }
3046
3053
  ],
3047
3054
  [ContributionPointIds4.COMMANDS]: [
3055
+ {
3056
+ command: "beginFeatureSession",
3057
+ title: "Begin Feature Session",
3058
+ handler: async () => {
3059
+ if (this.isFeatureSessionActive) {
3060
+ return { ok: true };
3061
+ }
3062
+ const original = this.getCommittedFeatures();
3063
+ this.sessionOriginalFeatures = this.cloneFeatures(original);
3064
+ this.isFeatureSessionActive = true;
3065
+ await this.refreshGeometry();
3066
+ this.setWorkingFeatures(this.cloneFeatures(original));
3067
+ this.hasWorkingChanges = false;
3068
+ this.redraw();
3069
+ this.emitWorkingChange();
3070
+ this.updateCommittedFeatures([]);
3071
+ return { ok: true };
3072
+ }
3073
+ },
3048
3074
  {
3049
3075
  command: "addFeature",
3050
3076
  title: "Add Edge Feature",
@@ -3097,19 +3123,27 @@ var FeatureTool = class {
3097
3123
  }
3098
3124
  },
3099
3125
  {
3100
- command: "resetWorkingFeatures",
3101
- title: "Reset Working Features",
3126
+ command: "rollbackFeatureSession",
3127
+ title: "Rollback Feature Session",
3102
3128
  handler: async () => {
3103
- var _a;
3104
- const configService = (_a = this.context) == null ? void 0 : _a.services.get(
3105
- "ConfigurationService"
3129
+ const original = this.cloneFeatures(
3130
+ this.sessionOriginalFeatures || this.getCommittedFeatures()
3106
3131
  );
3107
- const next = (configService == null ? void 0 : configService.get("dieline.features", [])) || [];
3108
3132
  await this.refreshGeometry();
3109
- this.setWorkingFeatures(this.cloneFeatures(next));
3133
+ this.setWorkingFeatures(original);
3110
3134
  this.hasWorkingChanges = false;
3111
3135
  this.redraw();
3112
3136
  this.emitWorkingChange();
3137
+ this.updateCommittedFeatures(original);
3138
+ this.clearFeatureSessionState();
3139
+ return { ok: true };
3140
+ }
3141
+ },
3142
+ {
3143
+ command: "resetWorkingFeatures",
3144
+ title: "Reset Working Features",
3145
+ handler: async () => {
3146
+ await this.resetWorkingFeaturesFromSource();
3113
3147
  return { ok: true };
3114
3148
  }
3115
3149
  },
@@ -3133,6 +3167,37 @@ var FeatureTool = class {
3133
3167
  cloneFeatures(features) {
3134
3168
  return JSON.parse(JSON.stringify(features || []));
3135
3169
  }
3170
+ getConfigService() {
3171
+ var _a;
3172
+ return (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
3173
+ }
3174
+ getCommittedFeatures() {
3175
+ const configService = this.getConfigService();
3176
+ const committed = (configService == null ? void 0 : configService.get("dieline.features", [])) || [];
3177
+ return this.cloneFeatures(committed);
3178
+ }
3179
+ updateCommittedFeatures(next) {
3180
+ const configService = this.getConfigService();
3181
+ if (!configService) return;
3182
+ this.isUpdatingConfig = true;
3183
+ try {
3184
+ configService.update("dieline.features", next);
3185
+ } finally {
3186
+ this.isUpdatingConfig = false;
3187
+ }
3188
+ }
3189
+ clearFeatureSessionState() {
3190
+ this.isFeatureSessionActive = false;
3191
+ this.sessionOriginalFeatures = null;
3192
+ }
3193
+ restoreSessionFeaturesToConfig() {
3194
+ if (!this.isFeatureSessionActive) return;
3195
+ const original = this.cloneFeatures(
3196
+ this.sessionOriginalFeatures || this.getCommittedFeatures()
3197
+ );
3198
+ this.updateCommittedFeatures(original);
3199
+ this.clearFeatureSessionState();
3200
+ }
3136
3201
  emitWorkingChange() {
3137
3202
  var _a;
3138
3203
  (_a = this.context) == null ? void 0 : _a.eventBus.emit("feature:working:change", {
@@ -3151,6 +3216,16 @@ var FeatureTool = class {
3151
3216
  } catch (e) {
3152
3217
  }
3153
3218
  }
3219
+ async resetWorkingFeaturesFromSource() {
3220
+ const next = this.cloneFeatures(
3221
+ this.isFeatureSessionActive && this.sessionOriginalFeatures ? this.sessionOriginalFeatures : this.getCommittedFeatures()
3222
+ );
3223
+ await this.refreshGeometry();
3224
+ this.setWorkingFeatures(next);
3225
+ this.hasWorkingChanges = false;
3226
+ this.redraw();
3227
+ this.emitWorkingChange();
3228
+ }
3154
3229
  setWorkingFeatures(next) {
3155
3230
  this.workingFeatures = next;
3156
3231
  }
@@ -3207,12 +3282,7 @@ var FeatureTool = class {
3207
3282
  this.workingFeatures,
3208
3283
  { dielineWidth, dielineHeight },
3209
3284
  (next) => {
3210
- this.isUpdatingConfig = true;
3211
- try {
3212
- configService.update("dieline.features", next);
3213
- } finally {
3214
- this.isUpdatingConfig = false;
3215
- }
3285
+ this.updateCommittedFeatures(next);
3216
3286
  this.workingFeatures = this.cloneFeatures(next);
3217
3287
  this.emitWorkingChange();
3218
3288
  }
@@ -3224,6 +3294,7 @@ var FeatureTool = class {
3224
3294
  };
3225
3295
  }
3226
3296
  this.hasWorkingChanges = false;
3297
+ this.clearFeatureSessionState();
3227
3298
  this.redraw();
3228
3299
  return { ok: true };
3229
3300
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pooder/kit",
3
- "version": "5.0.2",
3
+ "version": "5.0.3",
4
4
  "description": "Standard plugins for Pooder editor",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/src/feature.ts CHANGED
@@ -34,6 +34,8 @@ export class FeatureTool implements Extension {
34
34
  private context?: ExtensionContext;
35
35
  private isUpdatingConfig = false;
36
36
  private isToolActive = false;
37
+ private isFeatureSessionActive = false;
38
+ private sessionOriginalFeatures: ConstraintFeature[] | null = null;
37
39
  private hasWorkingChanges = false;
38
40
  private dirtyTrackerDisposable?: { dispose(): void };
39
41
 
@@ -76,6 +78,7 @@ export class FeatureTool implements Extension {
76
78
  if (this.isUpdatingConfig) return;
77
79
 
78
80
  if (e.key === "dieline.features") {
81
+ if (this.isFeatureSessionActive) return;
79
82
  const next = (e.value || []) as ConstraintFeature[];
80
83
  this.workingFeatures = this.cloneFeatures(next);
81
84
  this.hasWorkingChanges = false;
@@ -100,6 +103,7 @@ export class FeatureTool implements Extension {
100
103
 
101
104
  deactivate(context: ExtensionContext) {
102
105
  context.eventBus.off("tool:activated", this.onToolActivated);
106
+ this.restoreSessionFeaturesToConfig();
103
107
  this.dirtyTrackerDisposable?.dispose();
104
108
  this.dirtyTrackerDisposable = undefined;
105
109
  this.teardown();
@@ -107,8 +111,11 @@ export class FeatureTool implements Extension {
107
111
  this.context = undefined;
108
112
  }
109
113
 
110
- private onToolActivated = (event: { id: string }) => {
114
+ private onToolActivated = (event: { id: string | null }) => {
111
115
  this.isToolActive = event.id === this.id;
116
+ if (!this.isToolActive) {
117
+ this.restoreSessionFeaturesToConfig();
118
+ }
112
119
  this.updateVisibility();
113
120
  };
114
121
 
@@ -140,9 +147,9 @@ export class FeatureTool implements Extension {
140
147
  name: "Feature",
141
148
  interaction: "session",
142
149
  commands: {
143
- begin: "resetWorkingFeatures",
150
+ begin: "beginFeatureSession",
144
151
  commit: "completeFeatures",
145
- rollback: "resetWorkingFeatures",
152
+ rollback: "rollbackFeatureSession",
146
153
  },
147
154
  session: {
148
155
  autoBegin: false,
@@ -151,6 +158,25 @@ export class FeatureTool implements Extension {
151
158
  },
152
159
  ],
153
160
  [ContributionPointIds.COMMANDS]: [
161
+ {
162
+ command: "beginFeatureSession",
163
+ title: "Begin Feature Session",
164
+ handler: async () => {
165
+ if (this.isFeatureSessionActive) {
166
+ return { ok: true };
167
+ }
168
+ const original = this.getCommittedFeatures();
169
+ this.sessionOriginalFeatures = this.cloneFeatures(original);
170
+ this.isFeatureSessionActive = true;
171
+ await this.refreshGeometry();
172
+ this.setWorkingFeatures(this.cloneFeatures(original));
173
+ this.hasWorkingChanges = false;
174
+ this.redraw();
175
+ this.emitWorkingChange();
176
+ this.updateCommittedFeatures([]);
177
+ return { ok: true };
178
+ },
179
+ },
154
180
  {
155
181
  command: "addFeature",
156
182
  title: "Add Edge Feature",
@@ -203,21 +229,27 @@ export class FeatureTool implements Extension {
203
229
  },
204
230
  },
205
231
  {
206
- command: "resetWorkingFeatures",
207
- title: "Reset Working Features",
232
+ command: "rollbackFeatureSession",
233
+ title: "Rollback Feature Session",
208
234
  handler: async () => {
209
- const configService =
210
- this.context?.services.get<ConfigurationService>(
211
- "ConfigurationService",
212
- );
213
- const next = (configService?.get("dieline.features", []) ||
214
- []) as ConstraintFeature[];
215
-
235
+ const original = this.cloneFeatures(
236
+ this.sessionOriginalFeatures || this.getCommittedFeatures(),
237
+ );
216
238
  await this.refreshGeometry();
217
- this.setWorkingFeatures(this.cloneFeatures(next));
239
+ this.setWorkingFeatures(original);
218
240
  this.hasWorkingChanges = false;
219
241
  this.redraw();
220
242
  this.emitWorkingChange();
243
+ this.updateCommittedFeatures(original);
244
+ this.clearFeatureSessionState();
245
+ return { ok: true };
246
+ },
247
+ },
248
+ {
249
+ command: "resetWorkingFeatures",
250
+ title: "Reset Working Features",
251
+ handler: async () => {
252
+ await this.resetWorkingFeaturesFromSource();
221
253
  return { ok: true };
222
254
  },
223
255
  },
@@ -243,6 +275,42 @@ export class FeatureTool implements Extension {
243
275
  return JSON.parse(JSON.stringify(features || [])) as ConstraintFeature[];
244
276
  }
245
277
 
278
+ private getConfigService(): ConfigurationService | undefined {
279
+ return this.context?.services.get<ConfigurationService>("ConfigurationService");
280
+ }
281
+
282
+ private getCommittedFeatures(): ConstraintFeature[] {
283
+ const configService = this.getConfigService();
284
+ const committed = (configService?.get("dieline.features", []) ||
285
+ []) as ConstraintFeature[];
286
+ return this.cloneFeatures(committed);
287
+ }
288
+
289
+ private updateCommittedFeatures(next: ConstraintFeature[]) {
290
+ const configService = this.getConfigService();
291
+ if (!configService) return;
292
+ this.isUpdatingConfig = true;
293
+ try {
294
+ configService.update("dieline.features", next);
295
+ } finally {
296
+ this.isUpdatingConfig = false;
297
+ }
298
+ }
299
+
300
+ private clearFeatureSessionState() {
301
+ this.isFeatureSessionActive = false;
302
+ this.sessionOriginalFeatures = null;
303
+ }
304
+
305
+ private restoreSessionFeaturesToConfig() {
306
+ if (!this.isFeatureSessionActive) return;
307
+ const original = this.cloneFeatures(
308
+ this.sessionOriginalFeatures || this.getCommittedFeatures(),
309
+ );
310
+ this.updateCommittedFeatures(original);
311
+ this.clearFeatureSessionState();
312
+ }
313
+
246
314
  private emitWorkingChange() {
247
315
  this.context?.eventBus.emit("feature:working:change", {
248
316
  features: this.cloneFeatures(this.workingFeatures),
@@ -261,6 +329,19 @@ export class FeatureTool implements Extension {
261
329
  } catch (e) {}
262
330
  }
263
331
 
332
+ private async resetWorkingFeaturesFromSource() {
333
+ const next = this.cloneFeatures(
334
+ this.isFeatureSessionActive && this.sessionOriginalFeatures
335
+ ? this.sessionOriginalFeatures
336
+ : this.getCommittedFeatures(),
337
+ );
338
+ await this.refreshGeometry();
339
+ this.setWorkingFeatures(next);
340
+ this.hasWorkingChanges = false;
341
+ this.redraw();
342
+ this.emitWorkingChange();
343
+ }
344
+
264
345
  private setWorkingFeatures(next: ConstraintFeature[]) {
265
346
  this.workingFeatures = next;
266
347
  }
@@ -335,13 +416,7 @@ export class FeatureTool implements Extension {
335
416
  this.workingFeatures,
336
417
  { dielineWidth, dielineHeight },
337
418
  (next) => {
338
- this.isUpdatingConfig = true;
339
- try {
340
- configService.update("dieline.features", next);
341
- } finally {
342
- this.isUpdatingConfig = false;
343
- }
344
-
419
+ this.updateCommittedFeatures(next as ConstraintFeature[]);
345
420
  this.workingFeatures = this.cloneFeatures(next as any);
346
421
  this.emitWorkingChange();
347
422
  },
@@ -355,6 +430,7 @@ export class FeatureTool implements Extension {
355
430
  }
356
431
 
357
432
  this.hasWorkingChanges = false;
433
+ this.clearFeatureSessionState();
358
434
  // Keep feature markers above dieline overlay after config-driven redraw.
359
435
  this.redraw();
360
436
  return { ok: true };