@nasser-sw/fabric 7.0.1-beta27 → 7.0.1-beta29

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 (45) hide show
  1. package/.history/package_20251227140750.json +164 -0
  2. package/.history/package_20251227152541.json +164 -0
  3. package/dist/index.js +96 -37
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.js +1 -1
  6. package/dist/index.min.js.map +1 -1
  7. package/dist/index.min.mjs +1 -1
  8. package/dist/index.min.mjs.map +1 -1
  9. package/dist/index.mjs +96 -37
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/index.node.cjs +96 -37
  12. package/dist/index.node.cjs.map +1 -1
  13. package/dist/index.node.mjs +96 -37
  14. package/dist/index.node.mjs.map +1 -1
  15. package/dist/package.json.min.mjs +1 -1
  16. package/dist/package.json.mjs +1 -1
  17. package/dist/src/controls/expandControl.d.ts +1 -1
  18. package/dist/src/controls/expandControl.d.ts.map +1 -1
  19. package/dist/src/controls/expandControl.min.mjs +1 -1
  20. package/dist/src/controls/expandControl.min.mjs.map +1 -1
  21. package/dist/src/controls/expandControl.mjs +26 -7
  22. package/dist/src/controls/expandControl.mjs.map +1 -1
  23. package/dist/src/shapes/Frame.d.ts +5 -1
  24. package/dist/src/shapes/Frame.d.ts.map +1 -1
  25. package/dist/src/shapes/Frame.min.mjs +1 -1
  26. package/dist/src/shapes/Frame.min.mjs.map +1 -1
  27. package/dist/src/shapes/Frame.mjs +37 -20
  28. package/dist/src/shapes/Frame.mjs.map +1 -1
  29. package/dist/src/shapes/Object/InteractiveObject.d.ts +4 -3
  30. package/dist/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  31. package/dist/src/shapes/Object/InteractiveObject.min.mjs +1 -1
  32. package/dist/src/shapes/Object/InteractiveObject.min.mjs.map +1 -1
  33. package/dist/src/shapes/Object/InteractiveObject.mjs +32 -9
  34. package/dist/src/shapes/Object/InteractiveObject.mjs.map +1 -1
  35. package/dist-extensions/src/controls/expandControl.d.ts +1 -1
  36. package/dist-extensions/src/controls/expandControl.d.ts.map +1 -1
  37. package/dist-extensions/src/shapes/Frame.d.ts +5 -1
  38. package/dist-extensions/src/shapes/Frame.d.ts.map +1 -1
  39. package/dist-extensions/src/shapes/Object/InteractiveObject.d.ts +4 -3
  40. package/dist-extensions/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/controls/expandControl.ts +29 -7
  43. package/src/shapes/Frame.ts +36 -17
  44. package/src/shapes/Object/InteractiveObject.ts +37 -9
  45. package/badd.png +0 -0
@@ -0,0 +1,164 @@
1
+ {
2
+ "name": "@nasser-sw/fabric",
3
+ "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
4
+ "homepage": "http://fabricjs.com/",
5
+ "version": "7.0.1-beta28",
6
+ "author": "Juriy Zaytsev <kangax@gmail.com>",
7
+ "contributors": [
8
+ {
9
+ "name": "Andrea Bogazzi",
10
+ "email": "andreabogazzi79@gmail.com",
11
+ "url": "https://github.com/asturur"
12
+ },
13
+ {
14
+ "name": "Shachar Nencel",
15
+ "email": "shacharnen@gmail.com",
16
+ "url": "https://github.com/ShaMan123"
17
+ },
18
+ {
19
+ "name": "Steve Eberhardt",
20
+ "email": "melchiar2@gmail.com",
21
+ "url": "https://github.com/melchiar"
22
+ }
23
+ ],
24
+ "keywords": [
25
+ "canvas",
26
+ "graphic",
27
+ "graphics",
28
+ "SVG",
29
+ "node-canvas",
30
+ "parser",
31
+ "HTML5",
32
+ "object model"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/fabricjs/fabric.js"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/fabricjs/fabric.js/issues"
43
+ },
44
+ "license": "MIT",
45
+ "scripts": {
46
+ "docs": "typedoc",
47
+ "cli": "node ./scripts/index.mjs",
48
+ "sandboxscript": "node ./scripts/sandbox.mjs",
49
+ "build": "npm run cli -- build",
50
+ "build:fast": "npm run build -- -f",
51
+ "dev": "npm run cli -- dev",
52
+ "start": "npm run sandboxscript -- start",
53
+ "export": "npm run cli -- website export",
54
+ "test:vitest": "vitest --run --project unit-node",
55
+ "test:vitest:chromium": "vitest --run --project unit-chromium",
56
+ "test:vitest:firefox": "vitest --run --project unit-firefox",
57
+ "test:vitest:all": "vitest --run",
58
+ "test:vitest:coverage": "vitest --run --coverage --project unit-node",
59
+ "test:vitest:coverage:watch": "npm run test:vitest --coverage=true",
60
+ "coverage:merge": "nyc merge coveragefiles .nyc_output/merged-coverage.json",
61
+ "coverage:report": "nyc report --skip-full=true --reporter=lcov --reporter=text --reporter=text-summary",
62
+ "coverage:report:ci": "nyc report --reporter=text-summary",
63
+ "test:e2e": "npm run playwright:typecheck && playwright test",
64
+ "playwright:typecheck": "tsc -p ./e2e/tsconfig.json --noEmit",
65
+ "sandbox": "npm run sandboxscript -- sandbox",
66
+ "local-server": "serve ./ -l tcp://localhost:8080",
67
+ "lint": "eslint src extensions",
68
+ "prettier:check": "prettier --check .",
69
+ "prettier:write": "prettier --write ."
70
+ },
71
+ "devDependencies": {
72
+ "@babel/cli": "^7.28.3",
73
+ "@babel/core": "^7.28.3",
74
+ "@babel/preset-env": "^7.28.3",
75
+ "@babel/preset-typescript": "^7.27.1",
76
+ "@eslint/js": "^9.31.0",
77
+ "@playwright/test": "^1.55.0",
78
+ "@rollup/plugin-babel": "^6.0.4",
79
+ "@rollup/plugin-json": "^6.1.0",
80
+ "@rollup/plugin-terser": "^0.4.4",
81
+ "@rollup/plugin-typescript": "^12.1.4",
82
+ "@types/fs-extra": "^11.0.4",
83
+ "@types/jsdom": "^21.1.7",
84
+ "@types/micromatch": "^4.0.9",
85
+ "@types/node": "^24.3.0",
86
+ "@vitest/browser": "^3.2.4",
87
+ "@vitest/coverage-v8": "^3.2.4",
88
+ "@vitest/ui": "^3.2.4",
89
+ "babel-plugin-transform-imports": "git+https://git@github.com/fabricjs/babel-plugin-transform-imports.git",
90
+ "chalk": "^5.6.0",
91
+ "commander": "^14.0.0",
92
+ "es-toolkit": "1.39.7",
93
+ "eslint-config-prettier": "^10.1.8",
94
+ "fs-extra": "^11.3.1",
95
+ "inquirer": "^12.9.4",
96
+ "micromatch": "^4.0.8",
97
+ "moment": "^2.30.1",
98
+ "nyc": "^17.1.0",
99
+ "prettier": "^3.6.2",
100
+ "ps-list": "^8.1.1",
101
+ "rollup": "^4.48.0",
102
+ "semver": "^7.7.2",
103
+ "serve": "^14.2.4",
104
+ "tslib": "^2.8.1",
105
+ "typescript": "^5.9.2",
106
+ "typescript-eslint": "^8.40.0",
107
+ "v8-to-istanbul": "^9.3.0",
108
+ "vite": "^6.3.5",
109
+ "vitest": "^3.2.4"
110
+ },
111
+ "engines": {
112
+ "node": ">=18.0.0"
113
+ },
114
+ "overrides": {
115
+ "canvas": {
116
+ "canvas": "3.2.0"
117
+ }
118
+ },
119
+ "module": "./dist/index.mjs",
120
+ "types": "./dist/index.d.ts",
121
+ "typesVersions": {
122
+ ">=4.2": {
123
+ "*": [
124
+ "dist/index.d.ts"
125
+ ],
126
+ "node": [
127
+ "dist/index.node.d.ts"
128
+ ]
129
+ }
130
+ },
131
+ "sideEffects": false,
132
+ "exports": {
133
+ ".": {
134
+ "types": "./dist/index.d.ts",
135
+ "import": "./dist/index.min.mjs",
136
+ "require": "./dist/index.min.js",
137
+ "default": "./dist/index.min.js"
138
+ },
139
+ "./es": {
140
+ "types": "./dist/index.d.ts",
141
+ "import": "./dist/fabric.min.mjs",
142
+ "require": null,
143
+ "default": null
144
+ },
145
+ "./node": {
146
+ "node": "./dist/index.node.cjs",
147
+ "types": "./dist/index.node.d.ts",
148
+ "import": "./dist/index.node.mjs",
149
+ "require": "./dist/index.node.cjs",
150
+ "default": "./dist/index.node.cjs"
151
+ },
152
+ "./extensions": {
153
+ "node": "./dist-extensions/index.mjs",
154
+ "types": "./dist-extensions/extensions/index.d.ts",
155
+ "import": "./dist-extensions/index.mjs",
156
+ "require": null,
157
+ "default": "./dist-extensions/fabric-extensions.min.js"
158
+ }
159
+ },
160
+ "optionalDependencies": {
161
+ "canvas": "^3.2.0",
162
+ "jsdom": "^26.1.0"
163
+ }
164
+ }
@@ -0,0 +1,164 @@
1
+ {
2
+ "name": "@nasser-sw/fabric",
3
+ "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
4
+ "homepage": "http://fabricjs.com/",
5
+ "version": "7.0.1-beta29",
6
+ "author": "Juriy Zaytsev <kangax@gmail.com>",
7
+ "contributors": [
8
+ {
9
+ "name": "Andrea Bogazzi",
10
+ "email": "andreabogazzi79@gmail.com",
11
+ "url": "https://github.com/asturur"
12
+ },
13
+ {
14
+ "name": "Shachar Nencel",
15
+ "email": "shacharnen@gmail.com",
16
+ "url": "https://github.com/ShaMan123"
17
+ },
18
+ {
19
+ "name": "Steve Eberhardt",
20
+ "email": "melchiar2@gmail.com",
21
+ "url": "https://github.com/melchiar"
22
+ }
23
+ ],
24
+ "keywords": [
25
+ "canvas",
26
+ "graphic",
27
+ "graphics",
28
+ "SVG",
29
+ "node-canvas",
30
+ "parser",
31
+ "HTML5",
32
+ "object model"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/fabricjs/fabric.js"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/fabricjs/fabric.js/issues"
43
+ },
44
+ "license": "MIT",
45
+ "scripts": {
46
+ "docs": "typedoc",
47
+ "cli": "node ./scripts/index.mjs",
48
+ "sandboxscript": "node ./scripts/sandbox.mjs",
49
+ "build": "npm run cli -- build",
50
+ "build:fast": "npm run build -- -f",
51
+ "dev": "npm run cli -- dev",
52
+ "start": "npm run sandboxscript -- start",
53
+ "export": "npm run cli -- website export",
54
+ "test:vitest": "vitest --run --project unit-node",
55
+ "test:vitest:chromium": "vitest --run --project unit-chromium",
56
+ "test:vitest:firefox": "vitest --run --project unit-firefox",
57
+ "test:vitest:all": "vitest --run",
58
+ "test:vitest:coverage": "vitest --run --coverage --project unit-node",
59
+ "test:vitest:coverage:watch": "npm run test:vitest --coverage=true",
60
+ "coverage:merge": "nyc merge coveragefiles .nyc_output/merged-coverage.json",
61
+ "coverage:report": "nyc report --skip-full=true --reporter=lcov --reporter=text --reporter=text-summary",
62
+ "coverage:report:ci": "nyc report --reporter=text-summary",
63
+ "test:e2e": "npm run playwright:typecheck && playwright test",
64
+ "playwright:typecheck": "tsc -p ./e2e/tsconfig.json --noEmit",
65
+ "sandbox": "npm run sandboxscript -- sandbox",
66
+ "local-server": "serve ./ -l tcp://localhost:8080",
67
+ "lint": "eslint src extensions",
68
+ "prettier:check": "prettier --check .",
69
+ "prettier:write": "prettier --write ."
70
+ },
71
+ "devDependencies": {
72
+ "@babel/cli": "^7.28.3",
73
+ "@babel/core": "^7.28.3",
74
+ "@babel/preset-env": "^7.28.3",
75
+ "@babel/preset-typescript": "^7.27.1",
76
+ "@eslint/js": "^9.31.0",
77
+ "@playwright/test": "^1.55.0",
78
+ "@rollup/plugin-babel": "^6.0.4",
79
+ "@rollup/plugin-json": "^6.1.0",
80
+ "@rollup/plugin-terser": "^0.4.4",
81
+ "@rollup/plugin-typescript": "^12.1.4",
82
+ "@types/fs-extra": "^11.0.4",
83
+ "@types/jsdom": "^21.1.7",
84
+ "@types/micromatch": "^4.0.9",
85
+ "@types/node": "^24.3.0",
86
+ "@vitest/browser": "^3.2.4",
87
+ "@vitest/coverage-v8": "^3.2.4",
88
+ "@vitest/ui": "^3.2.4",
89
+ "babel-plugin-transform-imports": "git+https://git@github.com/fabricjs/babel-plugin-transform-imports.git",
90
+ "chalk": "^5.6.0",
91
+ "commander": "^14.0.0",
92
+ "es-toolkit": "1.39.7",
93
+ "eslint-config-prettier": "^10.1.8",
94
+ "fs-extra": "^11.3.1",
95
+ "inquirer": "^12.9.4",
96
+ "micromatch": "^4.0.8",
97
+ "moment": "^2.30.1",
98
+ "nyc": "^17.1.0",
99
+ "prettier": "^3.6.2",
100
+ "ps-list": "^8.1.1",
101
+ "rollup": "^4.48.0",
102
+ "semver": "^7.7.2",
103
+ "serve": "^14.2.4",
104
+ "tslib": "^2.8.1",
105
+ "typescript": "^5.9.2",
106
+ "typescript-eslint": "^8.40.0",
107
+ "v8-to-istanbul": "^9.3.0",
108
+ "vite": "^6.3.5",
109
+ "vitest": "^3.2.4"
110
+ },
111
+ "engines": {
112
+ "node": ">=18.0.0"
113
+ },
114
+ "overrides": {
115
+ "canvas": {
116
+ "canvas": "3.2.0"
117
+ }
118
+ },
119
+ "module": "./dist/index.mjs",
120
+ "types": "./dist/index.d.ts",
121
+ "typesVersions": {
122
+ ">=4.2": {
123
+ "*": [
124
+ "dist/index.d.ts"
125
+ ],
126
+ "node": [
127
+ "dist/index.node.d.ts"
128
+ ]
129
+ }
130
+ },
131
+ "sideEffects": false,
132
+ "exports": {
133
+ ".": {
134
+ "types": "./dist/index.d.ts",
135
+ "import": "./dist/index.min.mjs",
136
+ "require": "./dist/index.min.js",
137
+ "default": "./dist/index.min.js"
138
+ },
139
+ "./es": {
140
+ "types": "./dist/index.d.ts",
141
+ "import": "./dist/fabric.min.mjs",
142
+ "require": null,
143
+ "default": null
144
+ },
145
+ "./node": {
146
+ "node": "./dist/index.node.cjs",
147
+ "types": "./dist/index.node.d.ts",
148
+ "import": "./dist/index.node.mjs",
149
+ "require": "./dist/index.node.cjs",
150
+ "default": "./dist/index.node.cjs"
151
+ },
152
+ "./extensions": {
153
+ "node": "./dist-extensions/index.mjs",
154
+ "types": "./dist-extensions/extensions/index.d.ts",
155
+ "import": "./dist-extensions/index.mjs",
156
+ "require": null,
157
+ "default": "./dist-extensions/fabric-extensions.min.js"
158
+ }
159
+ },
160
+ "optionalDependencies": {
161
+ "canvas": "^3.2.0",
162
+ "jsdom": "^26.1.0"
163
+ }
164
+ }
package/dist/index.js CHANGED
@@ -360,7 +360,7 @@
360
360
  }
361
361
  const cache = new Cache();
362
362
 
363
- var version = "7.0.1-beta26";
363
+ var version = "7.0.1-beta28";
364
364
 
365
365
  // use this syntax so babel plugin see this import here
366
366
  const VERSION = version;
@@ -9337,7 +9337,7 @@
9337
9337
  /**
9338
9338
  * Position handler for expand controls
9339
9339
  * Positions controls at the expansion boundary, not the object boundary
9340
- * Note: expansion values are stored in screen pixels (already scaled)
9340
+ * Note: expansion values are stored in local object coordinates
9341
9341
  */
9342
9342
  positionHandler(dim, finalMatrix, fabricObject, currentControl) {
9343
9343
  const expansion = getExpansion(fabricObject);
@@ -9348,18 +9348,37 @@
9348
9348
  expandBottom
9349
9349
  } = expansion;
9350
9350
 
9351
- // dim already includes scale, so use it directly for base size
9352
- // expansion values are also in screen pixels, so use directly
9351
+ // dim already includes object's own scale
9353
9352
  const halfWidth = dim.x / 2;
9354
9353
  const halfHeight = dim.y / 2;
9355
9354
 
9355
+ // When object is in a group (like Frame), we need to scale expansion values
9356
+ // to match the coordinate space of dim
9357
+ let scaleFactorX = 1;
9358
+ let scaleFactorY = 1;
9359
+ if (fabricObject.group) {
9360
+ // dim is in object's scaled local space
9361
+ // expansion values are also in local space
9362
+ // But we need to account for the object's scale since dim includes it
9363
+ const objectScaleX = fabricObject.scaleX || 1;
9364
+ const objectScaleY = fabricObject.scaleY || 1;
9365
+ scaleFactorX = objectScaleX;
9366
+ scaleFactorY = objectScaleY;
9367
+ }
9368
+
9369
+ // Scale expansion values to match dim's coordinate space
9370
+ const scaledExpandLeft = expandLeft * scaleFactorX;
9371
+ const scaledExpandRight = expandRight * scaleFactorX;
9372
+ const scaledExpandTop = expandTop * scaleFactorY;
9373
+ const scaledExpandBottom = expandBottom * scaleFactorY;
9374
+
9356
9375
  // Calculate the expanded half dimensions
9357
- const expandedHalfWidth = halfWidth + (expandLeft + expandRight) / 2;
9358
- const expandedHalfHeight = halfHeight + (expandTop + expandBottom) / 2;
9376
+ const expandedHalfWidth = halfWidth + (scaledExpandLeft + scaledExpandRight) / 2;
9377
+ const expandedHalfHeight = halfHeight + (scaledExpandTop + scaledExpandBottom) / 2;
9359
9378
 
9360
9379
  // Calculate offset from center based on asymmetric expansion
9361
- const centerOffsetX = (expandRight - expandLeft) / 2;
9362
- const centerOffsetY = (expandBottom - expandTop) / 2;
9380
+ const centerOffsetX = (scaledExpandRight - scaledExpandLeft) / 2;
9381
+ const centerOffsetY = (scaledExpandBottom - scaledExpandTop) / 2;
9363
9382
  let posX;
9364
9383
  let posY;
9365
9384
 
@@ -9973,7 +9992,7 @@
9973
9992
 
9974
9993
  // Draw expansion preview if in expand mode or has expansion
9975
9994
  if (this.expandMode || this.hasExpansion()) {
9976
- this.drawExpandPreview(ctx, size);
9995
+ this.drawExpandPreview(ctx, size, options);
9977
9996
  }
9978
9997
  this._drawBorders(ctx, size, styleOverride);
9979
9998
  }
@@ -10381,10 +10400,11 @@
10381
10400
  * Draw the expansion preview area
10382
10401
  * Called during border rendering when in expand mode
10383
10402
  * @param ctx Canvas rendering context
10384
- * @param size Object dimensions (already includes scale)
10385
- * Note: expansion values are stored in screen pixels (already scaled)
10403
+ * @param size Object dimensions (already includes scale and parent transforms)
10404
+ * @param options Decomposed transform options (contains scaleX, scaleY from full transform)
10405
+ * Note: expansion values are stored in local object coordinates
10386
10406
  */
10387
- drawExpandPreview(ctx, size) {
10407
+ drawExpandPreview(ctx, size, options) {
10388
10408
  if (!this.expandMode && !this.hasExpansion()) return;
10389
10409
  const {
10390
10410
  expandLeft,
@@ -10393,13 +10413,35 @@
10393
10413
  expandBottom
10394
10414
  } = this.expansion;
10395
10415
 
10396
- // Expansion values are already in screen pixels, use directly
10397
- const expandedWidth = size.x + expandLeft + expandRight;
10398
- const expandedHeight = size.y + expandTop + expandBottom;
10416
+ // When object is in a group (like Frame), expansion values are in local coords
10417
+ // but context is transformed. We need to scale expansion by the transform.
10418
+ // For standalone objects, options.scaleX/Y will be just the object's own scale.
10419
+ // For objects in groups, it includes parent scale too.
10420
+ let scaleFactorX = 1;
10421
+ let scaleFactorY = 1;
10422
+ if (this.group && options) {
10423
+ // Get the group's contribution to the scale
10424
+ // options.scaleX includes both object scale and parent scale
10425
+ // We want just the parent's scale contribution
10426
+ const objectScaleX = this.scaleX || 1;
10427
+ const objectScaleY = this.scaleY || 1;
10428
+ scaleFactorX = (options.scaleX || 1) / objectScaleX;
10429
+ scaleFactorY = (options.scaleY || 1) / objectScaleY;
10430
+ }
10431
+
10432
+ // Scale expansion values by the parent's scale factor
10433
+ const scaledExpandLeft = expandLeft * scaleFactorX;
10434
+ const scaledExpandRight = expandRight * scaleFactorX;
10435
+ const scaledExpandTop = expandTop * scaleFactorY;
10436
+ const scaledExpandBottom = expandBottom * scaleFactorY;
10437
+
10438
+ // size already accounts for full transform, add scaled expansion
10439
+ const expandedWidth = size.x + scaledExpandLeft + scaledExpandRight;
10440
+ const expandedHeight = size.y + scaledExpandTop + scaledExpandBottom;
10399
10441
 
10400
10442
  // Offset to account for asymmetric expansion
10401
- const offsetX = (expandRight - expandLeft) / 2;
10402
- const offsetY = (expandBottom - expandTop) / 2;
10443
+ const offsetX = (scaledExpandRight - scaledExpandLeft) / 2;
10444
+ const offsetY = (scaledExpandBottom - scaledExpandTop) / 2;
10403
10445
  ctx.save();
10404
10446
 
10405
10447
  // Draw expansion area fill
@@ -31623,6 +31665,8 @@
31623
31665
  hasBorders: true,
31624
31666
  minScaleLimit: minScale,
31625
31667
  lockScalingFlip: true,
31668
+ lockUniScaling: false,
31669
+ // Allow non-uniform stretching
31626
31670
  objectCaching: false
31627
31671
  });
31628
31672
  this._contentImage.dirty = true;
@@ -31639,11 +31683,15 @@
31639
31683
  this._setupEditModeConstraints();
31640
31684
  this.set('dirty', true);
31641
31685
 
31642
- // Just render - don't call setActiveObject() on the content image
31643
- // because it causes position miscalculation with viewport transforms.
31644
- // The content image is still interactive via subTargetCheck = true
31686
+ // Select the content image so its controls are active
31645
31687
  if (this.canvas) {
31646
- this.canvas.renderAll();
31688
+ // Use requestAnimationFrame to ensure rendering is complete before selecting
31689
+ requestAnimationFrame(() => {
31690
+ if (this._contentImage && this.canvas) {
31691
+ this.canvas.setActiveObject(this._contentImage);
31692
+ this.canvas.requestRenderAll();
31693
+ }
31694
+ });
31647
31695
  }
31648
31696
 
31649
31697
  // Fire custom event
@@ -31662,13 +31710,14 @@
31662
31710
 
31663
31711
  // Constrain movement to prevent gaps
31664
31712
  this._boundConstrainMove = e => {
31665
- var _ref5, _frame$frameMeta$orig, _ref6, _frame$frameMeta$orig2, _img$scaleX2, _img$left2, _img$top2;
31713
+ var _ref5, _frame$frameMeta$orig, _ref6, _frame$frameMeta$orig2, _img$scaleX2, _img$scaleY, _img$left2, _img$top2;
31666
31714
  if (e.target !== img || !frame.isEditMode) return;
31667
31715
  const originalWidth = (_ref5 = (_frame$frameMeta$orig = frame.frameMeta.originalWidth) !== null && _frame$frameMeta$orig !== void 0 ? _frame$frameMeta$orig : img.width) !== null && _ref5 !== void 0 ? _ref5 : 100;
31668
31716
  const originalHeight = (_ref6 = (_frame$frameMeta$orig2 = frame.frameMeta.originalHeight) !== null && _frame$frameMeta$orig2 !== void 0 ? _frame$frameMeta$orig2 : img.height) !== null && _ref6 !== void 0 ? _ref6 : 100;
31669
- const currentScale = (_img$scaleX2 = img.scaleX) !== null && _img$scaleX2 !== void 0 ? _img$scaleX2 : 1;
31670
- const scaledImgHalfW = originalWidth * currentScale / 2;
31671
- const scaledImgHalfH = originalHeight * currentScale / 2;
31717
+ const scaleX = (_img$scaleX2 = img.scaleX) !== null && _img$scaleX2 !== void 0 ? _img$scaleX2 : 1;
31718
+ const scaleY = (_img$scaleY = img.scaleY) !== null && _img$scaleY !== void 0 ? _img$scaleY : 1;
31719
+ const scaledImgHalfW = originalWidth * scaleX / 2;
31720
+ const scaledImgHalfH = originalHeight * scaleY / 2;
31672
31721
  const frameHalfW = frame.frameWidth / 2;
31673
31722
  const frameHalfH = frame.frameHeight / 2;
31674
31723
  const maxOffsetX = Math.max(0, scaledImgHalfW - frameHalfW);
@@ -31687,19 +31736,23 @@
31687
31736
 
31688
31737
  // Constrain scaling to prevent gaps
31689
31738
  this._boundConstrainScale = e => {
31690
- var _ref7, _frame$frameMeta$orig3, _ref8, _frame$frameMeta$orig4, _img$scaleX3, _img$scaleY, _frame$_boundConstrai;
31739
+ var _ref7, _frame$frameMeta$orig3, _ref8, _frame$frameMeta$orig4, _img$scaleX3, _img$scaleY2, _frame$_boundConstrai;
31691
31740
  if (e.target !== img || !frame.isEditMode) return;
31692
31741
  const originalWidth = (_ref7 = (_frame$frameMeta$orig3 = frame.frameMeta.originalWidth) !== null && _frame$frameMeta$orig3 !== void 0 ? _frame$frameMeta$orig3 : img.width) !== null && _ref7 !== void 0 ? _ref7 : 100;
31693
31742
  const originalHeight = (_ref8 = (_frame$frameMeta$orig4 = frame.frameMeta.originalHeight) !== null && _frame$frameMeta$orig4 !== void 0 ? _frame$frameMeta$orig4 : img.height) !== null && _ref8 !== void 0 ? _ref8 : 100;
31694
- const minScale = frame._calculateCoverScale(originalWidth, originalHeight);
31743
+
31744
+ // Calculate minimum scale for each axis independently
31745
+ const minScaleX = frame.frameWidth / originalWidth;
31746
+ const minScaleY = frame.frameHeight / originalHeight;
31695
31747
  let scaleX = (_img$scaleX3 = img.scaleX) !== null && _img$scaleX3 !== void 0 ? _img$scaleX3 : 1;
31696
- let scaleY = (_img$scaleY = img.scaleY) !== null && _img$scaleY !== void 0 ? _img$scaleY : 1;
31748
+ let scaleY = (_img$scaleY2 = img.scaleY) !== null && _img$scaleY2 !== void 0 ? _img$scaleY2 : 1;
31697
31749
 
31698
- // Ensure uniform scaling and minimum scale
31699
- const scale = Math.max(minScale, Math.max(scaleX, scaleY));
31750
+ // Ensure each axis meets minimum scale (allows non-uniform stretching)
31751
+ scaleX = Math.max(minScaleX, scaleX);
31752
+ scaleY = Math.max(minScaleY, scaleY);
31700
31753
  img.set({
31701
- scaleX: scale,
31702
- scaleY: scale
31754
+ scaleX,
31755
+ scaleY
31703
31756
  });
31704
31757
 
31705
31758
  // Also constrain position after scale
@@ -31890,9 +31943,10 @@
31890
31943
  // Constrain position so image always covers the frame
31891
31944
  const originalWidth = (_ref9 = (_this$frameMeta$origi5 = this.frameMeta.originalWidth) !== null && _this$frameMeta$origi5 !== void 0 ? _this$frameMeta$origi5 : this._contentImage.width) !== null && _ref9 !== void 0 ? _ref9 : 100;
31892
31945
  const originalHeight = (_ref0 = (_this$frameMeta$origi6 = this.frameMeta.originalHeight) !== null && _this$frameMeta$origi6 !== void 0 ? _this$frameMeta$origi6 : this._contentImage.height) !== null && _ref0 !== void 0 ? _ref0 : 100;
31893
- const currentScale = Math.max(contentScaleX, contentScaleY);
31894
- const scaledImgHalfW = originalWidth * currentScale / 2;
31895
- const scaledImgHalfH = originalHeight * currentScale / 2;
31946
+
31947
+ // Use actual scaleX/scaleY for non-uniform scaling support
31948
+ const scaledImgHalfW = originalWidth * contentScaleX / 2;
31949
+ const scaledImgHalfH = originalHeight * contentScaleY / 2;
31896
31950
  const frameHalfW = this.frameWidth / 2;
31897
31951
  const frameHalfH = this.frameHeight / 2;
31898
31952
 
@@ -31908,12 +31962,13 @@
31908
31962
  top: constrainedTop
31909
31963
  });
31910
31964
 
31911
- // Update metadata with new offsets and scale
31965
+ // Update metadata with new offsets and scale (store both scaleX and scaleY)
31912
31966
  this.frameMeta = {
31913
31967
  ...this.frameMeta,
31914
31968
  contentOffsetX: constrainedLeft,
31915
31969
  contentOffsetY: constrainedTop,
31916
- contentScale: currentScale
31970
+ contentScaleX: contentScaleX,
31971
+ contentScaleY: contentScaleY
31917
31972
  };
31918
31973
 
31919
31974
  // Make content non-interactive again and restore caching
@@ -31922,6 +31977,10 @@
31922
31977
  evented: false,
31923
31978
  hasControls: false,
31924
31979
  hasBorders: false,
31980
+ lockUniScaling: false,
31981
+ // Reset to default
31982
+ centeredScaling: false,
31983
+ // Reset to default
31925
31984
  objectCaching: true
31926
31985
  });
31927
31986