@pooder/kit 6.2.2 → 6.3.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.
package/dist/index.mjs CHANGED
@@ -1271,30 +1271,35 @@ function createImageCommands(tool) {
1271
1271
  }
1272
1272
  },
1273
1273
  {
1274
- command: "getWorkingImages",
1275
- id: "getWorkingImages",
1276
- title: "Get Working Images",
1274
+ command: "applyImageOperation",
1275
+ id: "applyImageOperation",
1276
+ title: "Apply Image Operation",
1277
+ handler: async (id, operation, options = {}) => {
1278
+ await tool.applyImageOperation(id, operation, options);
1279
+ }
1280
+ },
1281
+ {
1282
+ command: "getImageViewState",
1283
+ id: "getImageViewState",
1284
+ title: "Get Image View State",
1277
1285
  handler: () => {
1278
- return tool.cloneItems(tool.workingItems);
1286
+ return tool.getImageViewState();
1279
1287
  }
1280
1288
  },
1281
1289
  {
1282
- command: "setWorkingImage",
1283
- id: "setWorkingImage",
1284
- title: "Set Working Image",
1285
- handler: (id, updates) => {
1286
- tool.updateImageInWorking(id, updates);
1290
+ command: "setImageTransform",
1291
+ id: "setImageTransform",
1292
+ title: "Set Image Transform",
1293
+ handler: async (id, updates, options = {}) => {
1294
+ await tool.setImageTransform(id, updates, options);
1287
1295
  }
1288
1296
  },
1289
1297
  {
1290
- command: "resetWorkingImages",
1291
- id: "resetWorkingImages",
1292
- title: "Reset Working Images",
1298
+ command: "imageSessionReset",
1299
+ id: "imageSessionReset",
1300
+ title: "Reset Image Session",
1293
1301
  handler: () => {
1294
- tool.workingItems = tool.cloneItems(tool.items);
1295
- tool.hasWorkingChanges = false;
1296
- tool.updateImages();
1297
- tool.emitWorkingChange();
1302
+ tool.resetImageSession();
1298
1303
  }
1299
1304
  },
1300
1305
  {
@@ -1313,22 +1318,6 @@ function createImageCommands(tool) {
1313
1318
  return await tool.exportUserCroppedImage(options);
1314
1319
  }
1315
1320
  },
1316
- {
1317
- command: "fitImageToArea",
1318
- id: "fitImageToArea",
1319
- title: "Fit Image to Area",
1320
- handler: async (id, area) => {
1321
- await tool.fitImageToArea(id, area);
1322
- }
1323
- },
1324
- {
1325
- command: "fitImageToDefaultArea",
1326
- id: "fitImageToDefaultArea",
1327
- title: "Fit Image to Default Area",
1328
- handler: async (id) => {
1329
- await tool.fitImageToDefaultArea(id);
1330
- }
1331
- },
1332
1321
  {
1333
1322
  command: "focusImage",
1334
1323
  id: "focusImage",
@@ -1342,9 +1331,10 @@ function createImageCommands(tool) {
1342
1331
  id: "removeImage",
1343
1332
  title: "Remove Image",
1344
1333
  handler: (id) => {
1345
- const removed = tool.items.find((item) => item.id === id);
1346
- const next = tool.items.filter((item) => item.id !== id);
1347
- if (next.length !== tool.items.length) {
1334
+ const sourceItems = tool.isToolActive ? tool.workingItems : tool.items;
1335
+ const removed = sourceItems.find((item) => item.id === id);
1336
+ const next = sourceItems.filter((item) => item.id !== id);
1337
+ if (next.length !== sourceItems.length) {
1348
1338
  tool.purgeSourceSizeCacheForItem(removed);
1349
1339
  if (tool.focusedImageId === id) {
1350
1340
  tool.setImageFocus(null, {
@@ -1352,6 +1342,13 @@ function createImageCommands(tool) {
1352
1342
  skipRender: true
1353
1343
  });
1354
1344
  }
1345
+ if (tool.isToolActive) {
1346
+ tool.workingItems = tool.cloneItems(next);
1347
+ tool.hasWorkingChanges = true;
1348
+ tool.updateImages();
1349
+ tool.emitWorkingChange(id);
1350
+ return;
1351
+ }
1355
1352
  tool.updateConfig(next);
1356
1353
  }
1357
1354
  }
@@ -1374,6 +1371,13 @@ function createImageCommands(tool) {
1374
1371
  syncCanvasSelection: true,
1375
1372
  skipRender: true
1376
1373
  });
1374
+ if (tool.isToolActive) {
1375
+ tool.workingItems = [];
1376
+ tool.hasWorkingChanges = true;
1377
+ tool.updateImages();
1378
+ tool.emitWorkingChange();
1379
+ return;
1380
+ }
1377
1381
  tool.updateConfig([]);
1378
1382
  }
1379
1383
  },
@@ -1382,11 +1386,19 @@ function createImageCommands(tool) {
1382
1386
  id: "bringToFront",
1383
1387
  title: "Bring Image to Front",
1384
1388
  handler: (id) => {
1385
- const index = tool.items.findIndex((item) => item.id === id);
1386
- if (index !== -1 && index < tool.items.length - 1) {
1387
- const next = [...tool.items];
1389
+ const sourceItems = tool.isToolActive ? tool.workingItems : tool.items;
1390
+ const index = sourceItems.findIndex((item) => item.id === id);
1391
+ if (index !== -1 && index < sourceItems.length - 1) {
1392
+ const next = [...sourceItems];
1388
1393
  const [item] = next.splice(index, 1);
1389
1394
  next.push(item);
1395
+ if (tool.isToolActive) {
1396
+ tool.workingItems = tool.cloneItems(next);
1397
+ tool.hasWorkingChanges = true;
1398
+ tool.updateImages();
1399
+ tool.emitWorkingChange(id);
1400
+ return;
1401
+ }
1390
1402
  tool.updateConfig(next);
1391
1403
  }
1392
1404
  }
@@ -1396,11 +1408,19 @@ function createImageCommands(tool) {
1396
1408
  id: "sendToBack",
1397
1409
  title: "Send Image to Back",
1398
1410
  handler: (id) => {
1399
- const index = tool.items.findIndex((item) => item.id === id);
1411
+ const sourceItems = tool.isToolActive ? tool.workingItems : tool.items;
1412
+ const index = sourceItems.findIndex((item) => item.id === id);
1400
1413
  if (index > 0) {
1401
- const next = [...tool.items];
1414
+ const next = [...sourceItems];
1402
1415
  const [item] = next.splice(index, 1);
1403
1416
  next.unshift(item);
1417
+ if (tool.isToolActive) {
1418
+ tool.workingItems = tool.cloneItems(next);
1419
+ tool.hasWorkingChanges = true;
1420
+ tool.updateImages();
1421
+ tool.emitWorkingChange(id);
1422
+ return;
1423
+ }
1404
1424
  tool.updateConfig(next);
1405
1425
  }
1406
1426
  }
@@ -1536,6 +1556,78 @@ function createImageConfigurations() {
1536
1556
  ];
1537
1557
  }
1538
1558
 
1559
+ // src/extensions/image/imageOperations.ts
1560
+ function clampNormalizedAnchor(value) {
1561
+ return Math.max(-1, Math.min(2, value));
1562
+ }
1563
+ function toNormalizedAnchor(center, start, size) {
1564
+ return clampNormalizedAnchor((center - start) / Math.max(1, size));
1565
+ }
1566
+ function resolveAbsoluteScale(operation, area, source) {
1567
+ const widthScale = Math.max(1, area.width) / Math.max(1, source.width);
1568
+ const heightScale = Math.max(1, area.height) / Math.max(1, source.height);
1569
+ switch (operation.type) {
1570
+ case "cover":
1571
+ return Math.max(widthScale, heightScale);
1572
+ case "contain":
1573
+ return Math.min(widthScale, heightScale);
1574
+ case "maximizeWidth":
1575
+ return widthScale;
1576
+ case "maximizeHeight":
1577
+ return heightScale;
1578
+ default:
1579
+ return null;
1580
+ }
1581
+ }
1582
+ function resolveImageOperationArea(args) {
1583
+ const spec = args.area || { type: "frame" };
1584
+ if (spec.type === "custom") {
1585
+ return {
1586
+ width: Math.max(1, spec.width),
1587
+ height: Math.max(1, spec.height),
1588
+ centerX: spec.centerX,
1589
+ centerY: spec.centerY
1590
+ };
1591
+ }
1592
+ if (spec.type === "viewport") {
1593
+ return {
1594
+ width: Math.max(1, args.viewport.width),
1595
+ height: Math.max(1, args.viewport.height),
1596
+ centerX: args.viewport.left + args.viewport.width / 2,
1597
+ centerY: args.viewport.top + args.viewport.height / 2
1598
+ };
1599
+ }
1600
+ return {
1601
+ width: Math.max(1, args.frame.width),
1602
+ height: Math.max(1, args.frame.height),
1603
+ centerX: args.frame.left + args.frame.width / 2,
1604
+ centerY: args.frame.top + args.frame.height / 2
1605
+ };
1606
+ }
1607
+ function computeImageOperationUpdates(args) {
1608
+ const { frame, source, operation, area } = args;
1609
+ if (operation.type === "resetTransform") {
1610
+ return {
1611
+ scale: 1,
1612
+ left: 0.5,
1613
+ top: 0.5,
1614
+ angle: 0
1615
+ };
1616
+ }
1617
+ const left = toNormalizedAnchor(area.centerX, frame.left, frame.width);
1618
+ const top = toNormalizedAnchor(area.centerY, frame.top, frame.height);
1619
+ if (operation.type === "center") {
1620
+ return { left, top };
1621
+ }
1622
+ const absoluteScale = resolveAbsoluteScale(operation, area, source);
1623
+ const coverScale = getCoverScale(frame, source);
1624
+ return {
1625
+ scale: Math.max(0.05, (absoluteScale || coverScale) / coverScale),
1626
+ left,
1627
+ top
1628
+ };
1629
+ }
1630
+
1539
1631
  // src/extensions/geometry.ts
1540
1632
  import paper from "paper";
1541
1633
 
@@ -2570,6 +2662,7 @@ var ImageTool = class {
2570
2662
  this.clearRenderedImages();
2571
2663
  (_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
2572
2664
  this.renderProducerDisposable = void 0;
2665
+ this.emitImageStateChange();
2573
2666
  if (this.canvasService) {
2574
2667
  void this.canvasService.flushRenderFromProducers();
2575
2668
  this.canvasService = void 0;
@@ -2979,9 +3072,9 @@ var ImageTool = class {
2979
3072
  name: "Image",
2980
3073
  interaction: "session",
2981
3074
  commands: {
2982
- begin: "resetWorkingImages",
3075
+ begin: "imageSessionReset",
2983
3076
  commit: "completeImages",
2984
- rollback: "resetWorkingImages"
3077
+ rollback: "imageSessionReset"
2985
3078
  },
2986
3079
  session: {
2987
3080
  autoBegin: true,
@@ -3015,6 +3108,28 @@ var ImageTool = class {
3015
3108
  cloneItems(items) {
3016
3109
  return this.normalizeItems((items || []).map((i) => ({ ...i })));
3017
3110
  }
3111
+ getViewItems() {
3112
+ return this.isToolActive ? this.workingItems : this.items;
3113
+ }
3114
+ getImageViewState() {
3115
+ this.syncToolActiveFromWorkbench();
3116
+ const items = this.cloneItems(this.getViewItems());
3117
+ const focusedItem = this.focusedImageId == null ? null : items.find((item) => item.id === this.focusedImageId) || null;
3118
+ return {
3119
+ items,
3120
+ hasAnyImage: items.length > 0,
3121
+ focusedId: this.focusedImageId,
3122
+ focusedItem,
3123
+ isToolActive: this.isToolActive,
3124
+ isImageSelectionActive: this.isImageSelectionActive,
3125
+ hasWorkingChanges: this.hasWorkingChanges,
3126
+ source: this.isToolActive ? "working" : "committed"
3127
+ };
3128
+ }
3129
+ emitImageStateChange() {
3130
+ var _a;
3131
+ (_a = this.context) == null ? void 0 : _a.eventBus.emit("image:state:change", this.getImageViewState());
3132
+ }
3018
3133
  emitWorkingChange(changedId = null) {
3019
3134
  var _a;
3020
3135
  (_a = this.context) == null ? void 0 : _a.eventBus.emit("image:working:change", {
@@ -3050,10 +3165,13 @@ var ImageTool = class {
3050
3165
  }
3051
3166
  if (!options.skipRender) {
3052
3167
  this.updateImages();
3168
+ } else {
3169
+ this.emitImageStateChange();
3053
3170
  }
3054
3171
  return { ok: true, id };
3055
3172
  }
3056
- async addImageEntry(url, options, fitOnAdd = true) {
3173
+ async addImageEntry(url, options, operation) {
3174
+ this.syncToolActiveFromWorkbench();
3057
3175
  const id = this.generateId();
3058
3176
  const newItem = this.normalizeItem({
3059
3177
  id,
@@ -3061,13 +3179,20 @@ var ImageTool = class {
3061
3179
  opacity: 1,
3062
3180
  ...options
3063
3181
  });
3064
- const sessionDirtyBeforeAdd = this.isToolActive && this.hasWorkingChanges;
3065
3182
  const waitLoaded = this.waitImageLoaded(id, true);
3066
- this.updateConfig([...this.items, newItem]);
3067
- this.addItemToWorkingSessionIfNeeded(newItem, sessionDirtyBeforeAdd);
3183
+ if (this.isToolActive) {
3184
+ this.workingItems = this.cloneItems([...this.workingItems, newItem]);
3185
+ this.hasWorkingChanges = true;
3186
+ this.updateImages();
3187
+ this.emitWorkingChange(id);
3188
+ } else {
3189
+ this.updateConfig([...this.items, newItem]);
3190
+ }
3068
3191
  const loaded = await waitLoaded;
3069
- if (loaded && fitOnAdd) {
3070
- await this.fitImageToDefaultArea(id);
3192
+ if (loaded && operation) {
3193
+ await this.applyImageOperation(id, operation, {
3194
+ target: this.isToolActive ? "working" : "config"
3195
+ });
3071
3196
  }
3072
3197
  if (loaded) {
3073
3198
  this.setImageFocus(id);
@@ -3075,8 +3200,8 @@ var ImageTool = class {
3075
3200
  return id;
3076
3201
  }
3077
3202
  async upsertImageEntry(url, options = {}) {
3203
+ this.syncToolActiveFromWorkbench();
3078
3204
  const mode = options.mode || (options.id ? "replace" : "add");
3079
- const fitOnAdd = options.fitOnAdd !== false;
3080
3205
  if (mode === "replace") {
3081
3206
  if (!options.id) {
3082
3207
  throw new Error("replace-target-id-required");
@@ -3085,19 +3210,31 @@ var ImageTool = class {
3085
3210
  if (!this.hasImageItem(targetId)) {
3086
3211
  throw new Error("replace-target-not-found");
3087
3212
  }
3088
- await this.updateImageInConfig(targetId, { url });
3213
+ if (this.isToolActive) {
3214
+ const current = this.workingItems.find((item) => item.id === targetId) || this.items.find((item) => item.id === targetId);
3215
+ this.purgeSourceSizeCacheForItem(current);
3216
+ this.updateImageInWorking(targetId, {
3217
+ url,
3218
+ sourceUrl: url,
3219
+ committedUrl: void 0
3220
+ });
3221
+ } else {
3222
+ await this.updateImageInConfig(targetId, { url });
3223
+ }
3224
+ const loaded = await this.waitImageLoaded(targetId, true);
3225
+ if (loaded && options.operation) {
3226
+ await this.applyImageOperation(targetId, options.operation, {
3227
+ target: this.isToolActive ? "working" : "config"
3228
+ });
3229
+ }
3230
+ if (loaded) {
3231
+ this.setImageFocus(targetId);
3232
+ }
3089
3233
  return { id: targetId, mode: "replace" };
3090
3234
  }
3091
- const id = await this.addImageEntry(url, options.addOptions, fitOnAdd);
3235
+ const id = await this.addImageEntry(url, options.addOptions, options.operation);
3092
3236
  return { id, mode: "add" };
3093
3237
  }
3094
- addItemToWorkingSessionIfNeeded(item, sessionDirtyBeforeAdd) {
3095
- if (!sessionDirtyBeforeAdd || !this.isToolActive) return;
3096
- if (this.workingItems.some((existing) => existing.id === item.id)) return;
3097
- this.workingItems = this.cloneItems([...this.workingItems, item]);
3098
- this.updateImages();
3099
- this.emitWorkingChange(item.id);
3100
- }
3101
3238
  async updateImage(id, updates, options = {}) {
3102
3239
  this.syncToolActiveFromWorkbench();
3103
3240
  const target = options.target || "auto";
@@ -3162,34 +3299,6 @@ var ImageTool = class {
3162
3299
  }
3163
3300
  return this.canvasService.toScreenRect(frame || this.getFrameRect());
3164
3301
  }
3165
- async resolveDefaultFitArea() {
3166
- if (!this.canvasService) return null;
3167
- const frame = this.getFrameRect();
3168
- if (frame.width <= 0 || frame.height <= 0) return null;
3169
- return {
3170
- width: Math.max(1, frame.width),
3171
- height: Math.max(1, frame.height),
3172
- left: frame.left + frame.width / 2,
3173
- top: frame.top + frame.height / 2
3174
- };
3175
- }
3176
- async fitImageToDefaultArea(id) {
3177
- if (!this.canvasService) return;
3178
- const area = await this.resolveDefaultFitArea();
3179
- if (area) {
3180
- await this.fitImageToArea(id, area);
3181
- return;
3182
- }
3183
- const viewport = this.canvasService.getSceneViewportRect();
3184
- const canvasW = Math.max(1, viewport.width || 0);
3185
- const canvasH = Math.max(1, viewport.height || 0);
3186
- await this.fitImageToArea(id, {
3187
- width: canvasW,
3188
- height: canvasH,
3189
- left: viewport.left + canvasW / 2,
3190
- top: viewport.top + canvasH / 2
3191
- });
3192
- }
3193
3302
  getImageObjects() {
3194
3303
  if (!this.canvasService) return [];
3195
3304
  return this.canvasService.canvas.getObjects().filter((obj) => {
@@ -3520,11 +3629,38 @@ var ImageTool = class {
3520
3629
  isImageSelectionActive: this.isImageSelectionActive,
3521
3630
  focusedImageId: this.focusedImageId
3522
3631
  });
3632
+ this.emitImageStateChange();
3523
3633
  this.canvasService.requestRenderAll();
3524
3634
  }
3525
3635
  clampNormalized(value) {
3526
3636
  return Math.max(-1, Math.min(2, value));
3527
3637
  }
3638
+ async setImageTransform(id, updates, options = {}) {
3639
+ const next = {};
3640
+ if (Number.isFinite(updates.scale)) {
3641
+ next.scale = Math.max(0.05, Number(updates.scale));
3642
+ }
3643
+ if (Number.isFinite(updates.angle)) {
3644
+ next.angle = Number(updates.angle);
3645
+ }
3646
+ if (Number.isFinite(updates.left)) {
3647
+ next.left = this.clampNormalized(Number(updates.left));
3648
+ }
3649
+ if (Number.isFinite(updates.top)) {
3650
+ next.top = this.clampNormalized(Number(updates.top));
3651
+ }
3652
+ if (Number.isFinite(updates.opacity)) {
3653
+ next.opacity = Math.max(0, Math.min(1, Number(updates.opacity)));
3654
+ }
3655
+ if (!Object.keys(next).length) return;
3656
+ await this.updateImage(id, next, options);
3657
+ }
3658
+ resetImageSession() {
3659
+ this.workingItems = this.cloneItems(this.items);
3660
+ this.hasWorkingChanges = false;
3661
+ this.updateImages();
3662
+ this.emitWorkingChange();
3663
+ }
3528
3664
  updateImageInWorking(id, updates) {
3529
3665
  const index = this.workingItems.findIndex((item) => item.id === id);
3530
3666
  if (index < 0) return;
@@ -3542,7 +3678,6 @@ var ImageTool = class {
3542
3678
  this.emitWorkingChange(id);
3543
3679
  }
3544
3680
  async updateImageInConfig(id, updates) {
3545
- var _a, _b, _c, _d;
3546
3681
  const index = this.items.findIndex((item) => item.id === id);
3547
3682
  if (index < 0) return;
3548
3683
  const replacingSource = typeof updates.url === "string" && updates.url.length > 0;
@@ -3555,23 +3690,12 @@ var ImageTool = class {
3555
3690
  ...replacingSource ? {
3556
3691
  url: replacingUrl,
3557
3692
  sourceUrl: replacingUrl,
3558
- committedUrl: void 0,
3559
- scale: (_a = updates.scale) != null ? _a : 1,
3560
- angle: (_b = updates.angle) != null ? _b : 0,
3561
- left: (_c = updates.left) != null ? _c : 0.5,
3562
- top: (_d = updates.top) != null ? _d : 0.5
3693
+ committedUrl: void 0
3563
3694
  } : {}
3564
3695
  });
3565
3696
  this.updateConfig(next);
3566
3697
  if (replacingSource) {
3567
- this.debug("replace:image:begin", { id, replacingUrl });
3568
3698
  this.purgeSourceSizeCacheForItem(base);
3569
- const loaded = await this.waitImageLoaded(id, true);
3570
- this.debug("replace:image:loaded", { id, loaded });
3571
- if (loaded) {
3572
- await this.refitImageToFrame(id);
3573
- this.setImageFocus(id);
3574
- }
3575
3699
  }
3576
3700
  }
3577
3701
  waitImageLoaded(id, forceWait = false) {
@@ -3589,70 +3713,43 @@ var ImageTool = class {
3589
3713
  });
3590
3714
  });
3591
3715
  }
3592
- async refitImageToFrame(id) {
3716
+ async resolveImageSourceSize(id, src) {
3593
3717
  const obj = this.getImageObject(id);
3594
- if (!obj || !this.canvasService) return;
3595
- const current = this.items.find((item) => item.id === id);
3596
- if (!current) return;
3597
- const render = this.resolveRenderImageState(current);
3598
- this.rememberSourceSize(render.src, obj);
3599
- const source = this.getSourceSize(render.src, obj);
3600
- const frame = this.getFrameRect();
3601
- const coverScale = this.getCoverScale(frame, source);
3602
- const currentScale = this.toSceneObjectScale(obj.scaleX || 1);
3603
- const zoom = Math.max(0.05, currentScale / coverScale);
3604
- const updated = {
3605
- scale: Number.isFinite(zoom) ? zoom : 1,
3606
- angle: 0,
3607
- left: 0.5,
3608
- top: 0.5
3609
- };
3610
- const index = this.items.findIndex((item) => item.id === id);
3611
- if (index < 0) return;
3612
- const next = [...this.items];
3613
- next[index] = this.normalizeItem({ ...next[index], ...updated });
3614
- this.updateConfig(next);
3615
- this.workingItems = this.cloneItems(next);
3616
- this.hasWorkingChanges = false;
3617
- this.updateImages();
3618
- this.emitWorkingChange(id);
3718
+ if (obj) {
3719
+ this.rememberSourceSize(src, obj);
3720
+ }
3721
+ const ensured = await this.ensureSourceSize(src);
3722
+ if (ensured) return ensured;
3723
+ if (!obj) return null;
3724
+ const width = Number((obj == null ? void 0 : obj.width) || 0);
3725
+ const height = Number((obj == null ? void 0 : obj.height) || 0);
3726
+ if (width <= 0 || height <= 0) return null;
3727
+ return { width, height };
3619
3728
  }
3620
- async fitImageToArea(id, area) {
3621
- var _a, _b;
3729
+ async applyImageOperation(id, operation, options = {}) {
3622
3730
  if (!this.canvasService) return;
3623
- const loaded = await this.waitImageLoaded(id, false);
3624
- if (!loaded) return;
3625
- const obj = this.getImageObject(id);
3626
- if (!obj) return;
3627
- const renderItems = this.isToolActive ? this.workingItems : this.items;
3731
+ this.syncToolActiveFromWorkbench();
3732
+ const target = options.target || "auto";
3733
+ const renderItems = target === "working" || target === "auto" && this.isToolActive ? this.workingItems : this.items;
3628
3734
  const current = renderItems.find((item) => item.id === id);
3629
3735
  if (!current) return;
3630
3736
  const render = this.resolveRenderImageState(current);
3631
- this.rememberSourceSize(render.src, obj);
3632
- const source = this.getSourceSize(render.src, obj);
3737
+ const source = await this.resolveImageSourceSize(id, render.src);
3738
+ if (!source) return;
3633
3739
  const frame = this.getFrameRect();
3634
- const baseCover = this.getCoverScale(frame, source);
3635
- const desiredScale = Math.max(
3636
- Math.max(1, area.width) / Math.max(1, source.width),
3637
- Math.max(1, area.height) / Math.max(1, source.height)
3638
- );
3639
3740
  const viewport = this.canvasService.getSceneViewportRect();
3640
- const canvasW = viewport.width || 1;
3641
- const canvasH = viewport.height || 1;
3642
- const areaLeftInput = (_a = area.left) != null ? _a : 0.5;
3643
- const areaTopInput = (_b = area.top) != null ? _b : 0.5;
3644
- const areaLeftPx = areaLeftInput <= 1.5 ? viewport.left + areaLeftInput * canvasW : areaLeftInput;
3645
- const areaTopPx = areaTopInput <= 1.5 ? viewport.top + areaTopInput * canvasH : areaTopInput;
3646
- const updates = {
3647
- scale: Math.max(0.05, desiredScale / baseCover),
3648
- left: this.clampNormalized(
3649
- (areaLeftPx - frame.left) / Math.max(1, frame.width)
3650
- ),
3651
- top: this.clampNormalized(
3652
- (areaTopPx - frame.top) / Math.max(1, frame.height)
3653
- )
3654
- };
3655
- if (this.isToolActive) {
3741
+ const area = operation.type === "resetTransform" ? resolveImageOperationArea({ frame, viewport }) : resolveImageOperationArea({
3742
+ frame,
3743
+ viewport,
3744
+ area: operation.area
3745
+ });
3746
+ const updates = computeImageOperationUpdates({
3747
+ frame,
3748
+ source,
3749
+ operation,
3750
+ area
3751
+ });
3752
+ if (target === "working" || target === "auto" && this.isToolActive) {
3656
3753
  this.updateImageInWorking(id, updates);
3657
3754
  return;
3658
3755
  }
@@ -3783,6 +3880,11 @@ var ImageTool = class {
3783
3880
  }
3784
3881
  };
3785
3882
 
3883
+ // src/extensions/image/model.ts
3884
+ function hasAnyImageInViewState(state) {
3885
+ return Boolean(state == null ? void 0 : state.hasAnyImage);
3886
+ }
3887
+
3786
3888
  // src/extensions/size/SizeTool.ts
3787
3889
  import {
3788
3890
  ContributionPointIds as ContributionPointIds3
@@ -9728,6 +9830,7 @@ export {
9728
9830
  ViewportSystem,
9729
9831
  WhiteInkTool,
9730
9832
  getCoverScale as computeImageCoverScale,
9833
+ computeImageOperationUpdates,
9731
9834
  getCoverScale as computeWhiteInkCoverScale,
9732
9835
  createDefaultDielineState,
9733
9836
  createDielineCommands,
@@ -9737,5 +9840,7 @@ export {
9737
9840
  createWhiteInkCommands,
9738
9841
  createWhiteInkConfigurations,
9739
9842
  evaluateVisibilityExpr,
9740
- readDielineState
9843
+ hasAnyImageInViewState,
9844
+ readDielineState,
9845
+ resolveImageOperationArea
9741
9846
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pooder/kit",
3
- "version": "6.2.2",
3
+ "version": "6.3.0",
4
4
  "description": "Standard plugins for Pooder editor",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",