@overtone-art/canvas-editor-core 0.6.4 → 0.8.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/chunk-XNGPX7FG.mjs +641 -0
- package/dist/chunk-XNGPX7FG.mjs.map +1 -0
- package/dist/index.d.mts +182 -4
- package/dist/index.d.ts +182 -4
- package/dist/index.global.js +55 -54
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +668 -129
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +320 -141
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +146 -0
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +3 -1
- package/dist/node.mjs.map +1 -1
- package/dist/{types-DSu2jbiV.d.mts → types-DmintAiu.d.mts} +56 -2
- package/dist/{types-DSu2jbiV.d.ts → types-DmintAiu.d.ts} +56 -2
- package/package.json +1 -1
- package/dist/chunk-MCBRZQ4M.mjs +0 -261
- package/dist/chunk-MCBRZQ4M.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -21,10 +21,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AnnotationOverlay: () => AnnotationOverlay,
|
|
24
|
+
BLEND_GROUPS: () => BLEND_GROUPS,
|
|
25
|
+
BLEND_MODES: () => BLEND_MODES,
|
|
24
26
|
CANVAS_MASK_TARGET: () => CANVAS_MASK_TARGET,
|
|
25
27
|
CANVAS_SIZE_PRESETS: () => CANVAS_SIZE_PRESETS,
|
|
26
28
|
CanvasEditor: () => CanvasEditor,
|
|
27
29
|
CropController: () => CropController,
|
|
30
|
+
DEFAULT_GRADIENT_CONFIG: () => DEFAULT_GRADIENT_CONFIG,
|
|
28
31
|
DEFAULT_LAYER_SHADOW: () => DEFAULT_LAYER_SHADOW,
|
|
29
32
|
DEFAULT_PATTERN_CONFIG: () => DEFAULT_PATTERN_CONFIG,
|
|
30
33
|
DEFAULT_SELECTION_STYLE: () => DEFAULT_SELECTION_STYLE,
|
|
@@ -47,12 +50,18 @@ __export(index_exports, {
|
|
|
47
50
|
TEXTURE_MASK_IDS: () => TEXTURE_MASK_IDS,
|
|
48
51
|
TEXTURE_MASK_SIZE: () => TEXTURE_MASK_SIZE,
|
|
49
52
|
TextCurveManager: () => TextCurveManager,
|
|
53
|
+
TextWrapManager: () => TextWrapManager,
|
|
50
54
|
TiledPatternObject: () => TiledPatternObject,
|
|
51
55
|
UnitConverter: () => UnitConverter,
|
|
56
|
+
angleFromCoords: () => angleFromCoords,
|
|
52
57
|
applyAspectLock: () => applyAspectLock,
|
|
53
58
|
applyLayerShadow: () => applyLayerShadow,
|
|
54
59
|
applyObjectSelectionStyle: () => applyObjectSelectionStyle,
|
|
55
60
|
applySelectionStyle: () => applySelectionStyle,
|
|
61
|
+
applyTextWrapToObject: () => applyTextWrapToObject,
|
|
62
|
+
blendModeLabel: () => blendModeLabel,
|
|
63
|
+
blendModeOf: () => blendModeOf,
|
|
64
|
+
blendOperation: () => blendOperation,
|
|
56
65
|
buildCurveLinePaths: () => buildCurveLinePaths,
|
|
57
66
|
buildCurvePathData: () => buildCurvePathData,
|
|
58
67
|
clamp: () => clamp,
|
|
@@ -78,9 +87,13 @@ __export(index_exports, {
|
|
|
78
87
|
isMaskPresetId: () => isMaskPresetId,
|
|
79
88
|
isShapeMaskId: () => isShapeMaskId,
|
|
80
89
|
isTextureMaskId: () => isTextureMaskId,
|
|
90
|
+
linearCoords: () => linearCoords,
|
|
81
91
|
needsAbsoluteSpace: () => needsAbsoluteSpace,
|
|
82
92
|
normalizeTextCurve: () => normalizeTextCurve,
|
|
93
|
+
preWrapWordSplit: () => preWrapWordSplit,
|
|
94
|
+
readGradientConfig: () => readGradientConfig,
|
|
83
95
|
readLayerShadow: () => readLayerShadow,
|
|
96
|
+
readTextWrap: () => readTextWrap,
|
|
84
97
|
renderTextureMask: () => renderTextureMask,
|
|
85
98
|
resetTransform: () => resetTransform,
|
|
86
99
|
restoreLocks: () => restoreLocks,
|
|
@@ -91,13 +104,14 @@ __export(index_exports, {
|
|
|
91
104
|
textPathCurve: () => textPathCurve,
|
|
92
105
|
textPathSpec: () => textPathSpec,
|
|
93
106
|
toCanvasSpace: () => toCanvasSpace,
|
|
107
|
+
toFabricGradient: () => toFabricGradient,
|
|
94
108
|
toHostSpace: () => toHostSpace,
|
|
95
109
|
unwrapGroup: () => unwrapGroup
|
|
96
110
|
});
|
|
97
111
|
module.exports = __toCommonJS(index_exports);
|
|
98
112
|
|
|
99
113
|
// src/editor.ts
|
|
100
|
-
var
|
|
114
|
+
var import_fabric22 = require("fabric");
|
|
101
115
|
|
|
102
116
|
// src/events.ts
|
|
103
117
|
var EventEmitter = class {
|
|
@@ -141,6 +155,53 @@ var import_fabric = require("fabric");
|
|
|
141
155
|
var import_nanoid = require("nanoid");
|
|
142
156
|
var generateId = () => (0, import_nanoid.nanoid)(12);
|
|
143
157
|
|
|
158
|
+
// src/blend.ts
|
|
159
|
+
var BLEND_MODES = [
|
|
160
|
+
"normal",
|
|
161
|
+
"darken",
|
|
162
|
+
"multiply",
|
|
163
|
+
"color-burn",
|
|
164
|
+
"lighten",
|
|
165
|
+
"screen",
|
|
166
|
+
"color-dodge",
|
|
167
|
+
"linear-dodge",
|
|
168
|
+
"overlay",
|
|
169
|
+
"soft-light",
|
|
170
|
+
"hard-light",
|
|
171
|
+
"difference",
|
|
172
|
+
"exclusion",
|
|
173
|
+
"hue",
|
|
174
|
+
"saturation",
|
|
175
|
+
"color",
|
|
176
|
+
"luminosity"
|
|
177
|
+
];
|
|
178
|
+
var OPERATION_EXCEPTIONS = {
|
|
179
|
+
normal: "source-over",
|
|
180
|
+
"linear-dodge": "lighter"
|
|
181
|
+
};
|
|
182
|
+
function blendOperation(mode) {
|
|
183
|
+
return OPERATION_EXCEPTIONS[mode] ?? mode;
|
|
184
|
+
}
|
|
185
|
+
function blendModeOf(operation) {
|
|
186
|
+
if (!operation) return "normal";
|
|
187
|
+
for (const mode of BLEND_MODES) {
|
|
188
|
+
if (blendOperation(mode) === operation) return mode;
|
|
189
|
+
}
|
|
190
|
+
return "normal";
|
|
191
|
+
}
|
|
192
|
+
var BLEND_GROUPS = [
|
|
193
|
+
{ label: "Normal", modes: ["normal"] },
|
|
194
|
+
{ label: "Darken", modes: ["darken", "multiply", "color-burn"] },
|
|
195
|
+
{ label: "Lighten", modes: ["lighten", "screen", "color-dodge", "linear-dodge"] },
|
|
196
|
+
{ label: "Contrast", modes: ["overlay", "soft-light", "hard-light"] },
|
|
197
|
+
{ label: "Comparative", modes: ["difference", "exclusion"] },
|
|
198
|
+
{ label: "Composite", modes: ["hue", "saturation", "color", "luminosity"] }
|
|
199
|
+
];
|
|
200
|
+
function blendModeLabel(mode) {
|
|
201
|
+
if (mode === "linear-dodge") return "Linear Dodge (Add)";
|
|
202
|
+
return mode.split("-").map((word) => (word[0] ?? "").toUpperCase() + word.slice(1)).join(" ");
|
|
203
|
+
}
|
|
204
|
+
|
|
144
205
|
// src/layer.ts
|
|
145
206
|
var Layer = class {
|
|
146
207
|
id;
|
|
@@ -184,6 +245,7 @@ var Layer = class {
|
|
|
184
245
|
return Object.keys(this.meta).length > 0;
|
|
185
246
|
}
|
|
186
247
|
toData() {
|
|
248
|
+
const blend = blendModeOf(this.fabricObject.globalCompositeOperation);
|
|
187
249
|
return {
|
|
188
250
|
id: this.id,
|
|
189
251
|
type: this.type,
|
|
@@ -191,6 +253,7 @@ var Layer = class {
|
|
|
191
253
|
visible: this.visible,
|
|
192
254
|
locked: this.locked,
|
|
193
255
|
opacity: this.opacity,
|
|
256
|
+
...blend !== "normal" ? { blend } : {},
|
|
194
257
|
...this.hasMeta() ? { meta: this.meta } : {},
|
|
195
258
|
...this.children.length > 0 ? { children: this.children.map((c) => c.toData()) } : {}
|
|
196
259
|
};
|
|
@@ -352,7 +415,11 @@ var LayerManager = class {
|
|
|
352
415
|
visible: layer.visible,
|
|
353
416
|
opacity: layer.opacity,
|
|
354
417
|
selectable: !layer.locked,
|
|
355
|
-
evented: !layer.locked
|
|
418
|
+
evented: !layer.locked,
|
|
419
|
+
// Compositing lives only on the fabric object (see `blendModeOf`); carry
|
|
420
|
+
// it from the object being replaced or a blend set before this call
|
|
421
|
+
// silently reverts to normal.
|
|
422
|
+
globalCompositeOperation: previous.globalCompositeOperation
|
|
356
423
|
});
|
|
357
424
|
this.canvas.insertAt(Math.max(0, stackIndex), fabricObject);
|
|
358
425
|
if (layer.renderProxy) {
|
|
@@ -382,7 +449,12 @@ var LayerManager = class {
|
|
|
382
449
|
visible: layer.visible,
|
|
383
450
|
opacity: layer.opacity,
|
|
384
451
|
selectable: !layer.locked,
|
|
385
|
-
evented: !layer.locked
|
|
452
|
+
evented: !layer.locked,
|
|
453
|
+
// The proxy is what actually draws once a layer has one (see
|
|
454
|
+
// `LayerManager`'s class doc); a blend set before the proxy existed
|
|
455
|
+
// must not silently stop applying. Read off the layer's own object —
|
|
456
|
+
// that stays the single source of truth (see `blendModeOf`).
|
|
457
|
+
globalCompositeOperation: layer.fabricObject.globalCompositeOperation
|
|
386
458
|
});
|
|
387
459
|
this.canvas.add(proxy);
|
|
388
460
|
this.syncZOrder();
|
|
@@ -1235,6 +1307,9 @@ var import_fabric5 = require("fabric");
|
|
|
1235
1307
|
var import_fabric4 = require("fabric");
|
|
1236
1308
|
var TEXT_FIT_SLACK = 0.5;
|
|
1237
1309
|
var MEASURE_WIDTH = 1e5;
|
|
1310
|
+
var GROWTH_FACTOR = 1.1;
|
|
1311
|
+
var GROWTH_TRIES = 8;
|
|
1312
|
+
var SEARCH_TRIES = 24;
|
|
1238
1313
|
function unwrappedWidth(text) {
|
|
1239
1314
|
const authored = text.width;
|
|
1240
1315
|
try {
|
|
@@ -1262,26 +1337,74 @@ function textInk(text) {
|
|
|
1262
1337
|
const flip = text.flipX ? -1 : 1;
|
|
1263
1338
|
return { width, dx: flip * (align.includes("right") ? slack : -slack) };
|
|
1264
1339
|
}
|
|
1340
|
+
function wrapsAt(text, width) {
|
|
1341
|
+
text.set({ width });
|
|
1342
|
+
text.initDimensions?.();
|
|
1343
|
+
const authored = text.text.split("\n").length;
|
|
1344
|
+
return (text._textLines?.length ?? 0) > authored;
|
|
1345
|
+
}
|
|
1346
|
+
function widenPastSoftWrap(text, fitted) {
|
|
1347
|
+
if (!wrapsAt(text, fitted)) return fitted;
|
|
1348
|
+
let low = fitted;
|
|
1349
|
+
let high = fitted;
|
|
1350
|
+
let bracketed = false;
|
|
1351
|
+
for (let tries = 0; tries < GROWTH_TRIES; tries += 1) {
|
|
1352
|
+
low = high;
|
|
1353
|
+
high = high * GROWTH_FACTOR + 1;
|
|
1354
|
+
if (!wrapsAt(text, high)) {
|
|
1355
|
+
bracketed = true;
|
|
1356
|
+
break;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
if (!bracketed) return high;
|
|
1360
|
+
for (let tries = 0; tries < SEARCH_TRIES && high - low > TEXT_FIT_SLACK; tries += 1) {
|
|
1361
|
+
const mid = (low + high) / 2;
|
|
1362
|
+
if (wrapsAt(text, mid)) low = mid;
|
|
1363
|
+
else high = mid;
|
|
1364
|
+
}
|
|
1365
|
+
if (text.width !== high) wrapsAt(text, high);
|
|
1366
|
+
return high;
|
|
1367
|
+
}
|
|
1368
|
+
function restoreWidth(text, width) {
|
|
1369
|
+
try {
|
|
1370
|
+
text.set({ width });
|
|
1371
|
+
text.initDimensions?.();
|
|
1372
|
+
} catch {
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
function isSettled(text, width) {
|
|
1376
|
+
if (wrapsAt(text, width)) return false;
|
|
1377
|
+
const tight = wrapsAt(text, width - TEXT_FIT_SLACK);
|
|
1378
|
+
wrapsAt(text, width);
|
|
1379
|
+
return tight;
|
|
1380
|
+
}
|
|
1265
1381
|
function fitTextWidth(object) {
|
|
1266
1382
|
const text = asText(object);
|
|
1267
1383
|
if (!text || text.path) return false;
|
|
1268
|
-
const
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1384
|
+
const authored = text.width;
|
|
1385
|
+
try {
|
|
1386
|
+
const before = textInk(text);
|
|
1387
|
+
const fitted = unwrappedWidth(text) + TEXT_FIT_SLACK;
|
|
1388
|
+
if (Math.abs(fitted - authored) < TEXT_FIT_SLACK) return false;
|
|
1389
|
+
const nearFit = authored > fitted && authored <= fitted * GROWTH_FACTOR + 1;
|
|
1390
|
+
if (nearFit && isSettled(text, authored)) return false;
|
|
1391
|
+
const centre = text.getCenterPoint();
|
|
1392
|
+
const settled = widenPastSoftWrap(text, fitted);
|
|
1393
|
+
const after = textInk(text);
|
|
1394
|
+
const shift = (before.dx - after.dx) * (text.scaleX ?? 1);
|
|
1395
|
+
const radians = (text.angle ?? 0) * Math.PI / 180;
|
|
1396
|
+
const moved = new import_fabric4.Point(
|
|
1397
|
+
centre.x + shift * Math.cos(radians),
|
|
1398
|
+
centre.y + shift * Math.sin(radians)
|
|
1399
|
+
);
|
|
1400
|
+
text.setPositionByOrigin(moved, "center", "center");
|
|
1401
|
+
text.setCoords();
|
|
1402
|
+
text.dirty = true;
|
|
1403
|
+
return Math.abs(settled - authored) >= TEXT_FIT_SLACK;
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
restoreWidth(text, authored);
|
|
1406
|
+
throw error;
|
|
1407
|
+
}
|
|
1285
1408
|
}
|
|
1286
1409
|
|
|
1287
1410
|
// src/pattern/tile-geometry.ts
|
|
@@ -2339,8 +2462,268 @@ var TextCurveManager = class {
|
|
|
2339
2462
|
}
|
|
2340
2463
|
};
|
|
2341
2464
|
|
|
2342
|
-
// src/
|
|
2465
|
+
// src/text-wrap.ts
|
|
2466
|
+
var import_fabric9 = require("fabric");
|
|
2467
|
+
|
|
2468
|
+
// src/text-wrap-split.ts
|
|
2469
|
+
var WHITESPACE = /[ \t\r]/;
|
|
2470
|
+
function preWrapWordSplit(value) {
|
|
2471
|
+
const tokens = [];
|
|
2472
|
+
let index = 0;
|
|
2473
|
+
let first = true;
|
|
2474
|
+
while (index < value.length) {
|
|
2475
|
+
let space = "";
|
|
2476
|
+
while (index < value.length && WHITESPACE.test(value[index])) {
|
|
2477
|
+
space += value[index];
|
|
2478
|
+
index += 1;
|
|
2479
|
+
}
|
|
2480
|
+
let word = "";
|
|
2481
|
+
while (index < value.length && !WHITESPACE.test(value[index])) {
|
|
2482
|
+
word += value[index];
|
|
2483
|
+
index += 1;
|
|
2484
|
+
}
|
|
2485
|
+
tokens.push((first ? space : space.slice(1)) + word);
|
|
2486
|
+
first = false;
|
|
2487
|
+
}
|
|
2488
|
+
return tokens.length > 0 ? tokens : [""];
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
// src/masks/space.ts
|
|
2343
2492
|
var import_fabric8 = require("fabric");
|
|
2493
|
+
function matrixOf(object) {
|
|
2494
|
+
return object.calcTransformMatrix();
|
|
2495
|
+
}
|
|
2496
|
+
function applyMatrix(object, matrix) {
|
|
2497
|
+
const decomposed = import_fabric8.util.qrDecompose(matrix);
|
|
2498
|
+
object.set({
|
|
2499
|
+
flipX: false,
|
|
2500
|
+
flipY: false,
|
|
2501
|
+
originX: "center",
|
|
2502
|
+
originY: "center",
|
|
2503
|
+
left: decomposed.translateX,
|
|
2504
|
+
top: decomposed.translateY,
|
|
2505
|
+
scaleX: decomposed.scaleX,
|
|
2506
|
+
scaleY: decomposed.scaleY,
|
|
2507
|
+
angle: decomposed.angle,
|
|
2508
|
+
skewX: decomposed.skewX,
|
|
2509
|
+
skewY: 0
|
|
2510
|
+
});
|
|
2511
|
+
object.setCoords();
|
|
2512
|
+
}
|
|
2513
|
+
function toCanvasSpace(object, host) {
|
|
2514
|
+
applyMatrix(object, import_fabric8.util.multiplyTransformMatrices(matrixOf(host), matrixOf(object)));
|
|
2515
|
+
}
|
|
2516
|
+
function toHostSpace(object, host) {
|
|
2517
|
+
applyMatrix(
|
|
2518
|
+
object,
|
|
2519
|
+
import_fabric8.util.multiplyTransformMatrices(import_fabric8.util.invertTransform(matrixOf(host)), matrixOf(object))
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
function relativeMatrix(object, host) {
|
|
2523
|
+
return import_fabric8.util.multiplyTransformMatrices(import_fabric8.util.invertTransform(matrixOf(host)), matrixOf(object));
|
|
2524
|
+
}
|
|
2525
|
+
function applyRelativeMatrix(object, host, rel) {
|
|
2526
|
+
applyMatrix(object, import_fabric8.util.multiplyTransformMatrices(matrixOf(host), rel));
|
|
2527
|
+
}
|
|
2528
|
+
function asObject(clip) {
|
|
2529
|
+
return clip;
|
|
2530
|
+
}
|
|
2531
|
+
function toMatrix(values) {
|
|
2532
|
+
if (!values || values.length !== 6 || values.some((value) => !Number.isFinite(value)))
|
|
2533
|
+
return null;
|
|
2534
|
+
return [values[0], values[1], values[2], values[3], values[4], values[5]];
|
|
2535
|
+
}
|
|
2536
|
+
function fitToBox(object, box, zoom = 1) {
|
|
2537
|
+
const width = Math.max(1, box.width) * zoom;
|
|
2538
|
+
const height = Math.max(1, box.height) * zoom;
|
|
2539
|
+
object.set({
|
|
2540
|
+
originX: "center",
|
|
2541
|
+
originY: "center",
|
|
2542
|
+
angle: 0,
|
|
2543
|
+
skewX: 0,
|
|
2544
|
+
skewY: 0,
|
|
2545
|
+
left: box.left + box.width / 2,
|
|
2546
|
+
top: box.top + box.height / 2,
|
|
2547
|
+
scaleX: width / Math.max(1, object.width ?? 1),
|
|
2548
|
+
scaleY: height / Math.max(1, object.height ?? 1)
|
|
2549
|
+
});
|
|
2550
|
+
object.setCoords();
|
|
2551
|
+
}
|
|
2552
|
+
function unwrapGroup(group) {
|
|
2553
|
+
const children = group.removeAll();
|
|
2554
|
+
for (const child of children) child.setCoords();
|
|
2555
|
+
return children;
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
// src/text-wrap.ts
|
|
2559
|
+
function patchWordSplit(text) {
|
|
2560
|
+
if (Object.prototype.hasOwnProperty.call(text, "wordSplit")) return;
|
|
2561
|
+
Object.defineProperty(text, "wordSplit", {
|
|
2562
|
+
value: preWrapWordSplit,
|
|
2563
|
+
configurable: true,
|
|
2564
|
+
writable: true
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
function unpatchWordSplit(text) {
|
|
2568
|
+
if (Object.prototype.hasOwnProperty.call(text, "wordSplit")) {
|
|
2569
|
+
delete text.wordSplit;
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
function readTextWrap(meta) {
|
|
2573
|
+
return { wrap: meta?.wrap ?? "none", overflow: meta?.overflow ?? "visible" };
|
|
2574
|
+
}
|
|
2575
|
+
function boxClip(text, makeRect) {
|
|
2576
|
+
return makeRect({
|
|
2577
|
+
width: Math.max(1, text.width ?? 1),
|
|
2578
|
+
height: Math.max(1, text.height ?? 1),
|
|
2579
|
+
originX: "center",
|
|
2580
|
+
originY: "center",
|
|
2581
|
+
left: 0,
|
|
2582
|
+
top: 0,
|
|
2583
|
+
objectCaching: false
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
function hasMask(meta) {
|
|
2587
|
+
return !!meta.maskPreset || (meta.maskStack?.length ?? 0) > 0;
|
|
2588
|
+
}
|
|
2589
|
+
function applyTextWrapToObject(object, meta, makeRect = (options) => new import_fabric9.Rect(options)) {
|
|
2590
|
+
const text = asText(object);
|
|
2591
|
+
if (!text) return;
|
|
2592
|
+
const state = readTextWrap(meta);
|
|
2593
|
+
if (!text.path) {
|
|
2594
|
+
text.set({ splitByGrapheme: state.wrap === "break-all" });
|
|
2595
|
+
if (state.wrap === "pre-wrap") patchWordSplit(text);
|
|
2596
|
+
else unpatchWordSplit(text);
|
|
2597
|
+
text.initDimensions?.();
|
|
2598
|
+
}
|
|
2599
|
+
const clip = state.overflow === "hidden" ? boxClip(text, makeRect) : void 0;
|
|
2600
|
+
if (meta && hasMask(meta)) {
|
|
2601
|
+
const host = text.clipPath;
|
|
2602
|
+
if (host) {
|
|
2603
|
+
if (clip) toHostSpace(clip, asObject(host));
|
|
2604
|
+
host.clipPath = clip;
|
|
2605
|
+
}
|
|
2606
|
+
} else {
|
|
2607
|
+
text.clipPath = clip;
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
var TextWrapManager = class {
|
|
2611
|
+
constructor(canvas, layers, history, events) {
|
|
2612
|
+
this.canvas = canvas;
|
|
2613
|
+
this.layers = layers;
|
|
2614
|
+
this.history = history;
|
|
2615
|
+
this.events = events;
|
|
2616
|
+
this.canvas.on("text:changed", this.onTextChanged);
|
|
2617
|
+
this.events.on("masks:changed", this.onMasksChanged);
|
|
2618
|
+
}
|
|
2619
|
+
canvas;
|
|
2620
|
+
layers;
|
|
2621
|
+
history;
|
|
2622
|
+
events;
|
|
2623
|
+
/**
|
|
2624
|
+
* Typing changes the run the box was fitted to, so an auto-width layer has to
|
|
2625
|
+
* re-fit. No history entry: fabric records the edit when editing exits, and a
|
|
2626
|
+
* save per keystroke would bury every earlier step.
|
|
2627
|
+
*/
|
|
2628
|
+
onTextChanged = (event) => {
|
|
2629
|
+
const layer = event.target ? this.layers.findByObject(event.target) : void 0;
|
|
2630
|
+
if (!layer) return;
|
|
2631
|
+
this.refresh(layer.id, false);
|
|
2632
|
+
};
|
|
2633
|
+
/**
|
|
2634
|
+
* Both mask owners — the preset manager and every mask-stack mutation —
|
|
2635
|
+
* install their clip straight onto `clipPath`, dropping whatever was there,
|
|
2636
|
+
* and neither knows this layer had a box clip. Re-deriving on the one event
|
|
2637
|
+
* they both announce puts it back where it now belongs: nested under the new
|
|
2638
|
+
* mask, or at the top level when the last mask leaves. Waiting for the next
|
|
2639
|
+
* keystroke instead would leave a layer that should clip inside its box
|
|
2640
|
+
* serialized unclipped — which is what the print renderer reads.
|
|
2641
|
+
*/
|
|
2642
|
+
onMasksChanged = ({ target }) => {
|
|
2643
|
+
this.refresh(target);
|
|
2644
|
+
};
|
|
2645
|
+
dispose() {
|
|
2646
|
+
this.canvas.off("text:changed", this.onTextChanged);
|
|
2647
|
+
this.events.off("masks:changed", this.onMasksChanged);
|
|
2648
|
+
}
|
|
2649
|
+
/** Both properties for a text layer, or null when it is not text. */
|
|
2650
|
+
get(layerId) {
|
|
2651
|
+
const layer = this.layers.get(layerId);
|
|
2652
|
+
if (!layer || !asText(layer.fabricObject)) return null;
|
|
2653
|
+
return readTextWrap(layer.meta);
|
|
2654
|
+
}
|
|
2655
|
+
apply(layerId, wrap, save = true) {
|
|
2656
|
+
const layer = this.layers.get(layerId);
|
|
2657
|
+
const text = layer ? asText(layer.fabricObject) : null;
|
|
2658
|
+
if (!layer || !text) return false;
|
|
2659
|
+
if (wrap === "none") {
|
|
2660
|
+
const curved = !!text.path;
|
|
2661
|
+
if (layer.meta.wrapWidth === void 0 && !curved) {
|
|
2662
|
+
layer.meta.wrapWidth = text.width ?? 0;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
layer.meta.wrap = wrap;
|
|
2666
|
+
return this.derive(layerId, save);
|
|
2667
|
+
}
|
|
2668
|
+
setOverflow(layerId, overflow, save = true) {
|
|
2669
|
+
const layer = this.layers.get(layerId);
|
|
2670
|
+
if (!layer || !asText(layer.fabricObject)) return false;
|
|
2671
|
+
layer.meta.overflow = overflow;
|
|
2672
|
+
return this.derive(layerId, save);
|
|
2673
|
+
}
|
|
2674
|
+
/** Back to the defaults: auto-width, unclipped. */
|
|
2675
|
+
clear(layerId, save = true) {
|
|
2676
|
+
const layer = this.layers.get(layerId);
|
|
2677
|
+
if (!layer || !asText(layer.fabricObject)) return false;
|
|
2678
|
+
delete layer.meta.overflow;
|
|
2679
|
+
return this.apply(layerId, "none", save);
|
|
2680
|
+
}
|
|
2681
|
+
/** Re-derive from the stored mode — after a text, font or size change. */
|
|
2682
|
+
refresh(layerId, save = false) {
|
|
2683
|
+
const layer = this.layers.get(layerId);
|
|
2684
|
+
if (!layer || !asText(layer.fabricObject)) return false;
|
|
2685
|
+
return this.derive(layerId, save);
|
|
2686
|
+
}
|
|
2687
|
+
/**
|
|
2688
|
+
* Re-derive every text layer — used after a state restore.
|
|
2689
|
+
*
|
|
2690
|
+
* Recursive because a template inserts as a group of real child layers, and
|
|
2691
|
+
* text inside one would otherwise keep whatever box it was restored with.
|
|
2692
|
+
*/
|
|
2693
|
+
refreshAll() {
|
|
2694
|
+
const visit = (layers) => {
|
|
2695
|
+
for (const layer of layers) {
|
|
2696
|
+
if (asText(layer.fabricObject)) this.refresh(layer.id);
|
|
2697
|
+
if (layer.children.length > 0) visit(layer.children);
|
|
2698
|
+
}
|
|
2699
|
+
};
|
|
2700
|
+
visit(this.layers.getAll());
|
|
2701
|
+
}
|
|
2702
|
+
derive(layerId, save) {
|
|
2703
|
+
const layer = this.layers.get(layerId);
|
|
2704
|
+
const text = layer ? asText(layer.fabricObject) : null;
|
|
2705
|
+
if (!layer || !text) return false;
|
|
2706
|
+
const state = readTextWrap(layer.meta);
|
|
2707
|
+
if (!text.path) {
|
|
2708
|
+
if (state.wrap === "none") {
|
|
2709
|
+
fitTextWidth(text);
|
|
2710
|
+
} else if (layer.meta.wrapWidth !== void 0) {
|
|
2711
|
+
text.set({ width: layer.meta.wrapWidth });
|
|
2712
|
+
delete layer.meta.wrapWidth;
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
applyTextWrapToObject(text, layer.meta);
|
|
2716
|
+
text.dirty = true;
|
|
2717
|
+
text.setCoords();
|
|
2718
|
+
this.canvas.requestRenderAll();
|
|
2719
|
+
this.events.emit("layer:modified", { layerId });
|
|
2720
|
+
if (save) this.history.save();
|
|
2721
|
+
return true;
|
|
2722
|
+
}
|
|
2723
|
+
};
|
|
2724
|
+
|
|
2725
|
+
// src/mask-presets/manager.ts
|
|
2726
|
+
var import_fabric10 = require("fabric");
|
|
2344
2727
|
|
|
2345
2728
|
// src/mask-presets/shapes.ts
|
|
2346
2729
|
var SHAPE_MASK_IDS = [
|
|
@@ -2573,6 +2956,7 @@ var MaskPresetManager = class {
|
|
|
2573
2956
|
object.dirty = true;
|
|
2574
2957
|
object.setCoords();
|
|
2575
2958
|
this.canvas.requestRenderAll();
|
|
2959
|
+
this.events.emit("masks:changed", { target: layerId });
|
|
2576
2960
|
this.events.emit("layer:modified", { layerId });
|
|
2577
2961
|
if (save) this.history.save();
|
|
2578
2962
|
return true;
|
|
@@ -2607,13 +2991,13 @@ var MaskPresetManager = class {
|
|
|
2607
2991
|
objectCaching: false
|
|
2608
2992
|
};
|
|
2609
2993
|
if (isShapeMaskId(id)) {
|
|
2610
|
-
return new
|
|
2994
|
+
return new import_fabric10.Path(shapeMaskPathData(id), {
|
|
2611
2995
|
...shared,
|
|
2612
2996
|
scaleX: width / SHAPE_MASK_BOX,
|
|
2613
2997
|
scaleY: height / SHAPE_MASK_BOX
|
|
2614
2998
|
});
|
|
2615
2999
|
}
|
|
2616
|
-
return new
|
|
3000
|
+
return new import_fabric10.FabricImage(renderTextureMask(id), {
|
|
2617
3001
|
...shared,
|
|
2618
3002
|
scaleX: width / TEXTURE_MASK_SIZE,
|
|
2619
3003
|
scaleY: height / TEXTURE_MASK_SIZE
|
|
@@ -2622,7 +3006,7 @@ var MaskPresetManager = class {
|
|
|
2622
3006
|
};
|
|
2623
3007
|
|
|
2624
3008
|
// src/shadow.ts
|
|
2625
|
-
var
|
|
3009
|
+
var import_fabric11 = require("fabric");
|
|
2626
3010
|
|
|
2627
3011
|
// src/utils/color.ts
|
|
2628
3012
|
var CSS_COLOR = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\([\d.%+\-\s,/]+\)|[a-z]+)$/i;
|
|
@@ -2660,7 +3044,7 @@ function applyLayerShadow(object, config) {
|
|
|
2660
3044
|
}
|
|
2661
3045
|
const color = isCssColor(next.color) ? next.color : DEFAULT_LAYER_SHADOW.color;
|
|
2662
3046
|
object.set({
|
|
2663
|
-
shadow: new
|
|
3047
|
+
shadow: new import_fabric11.Shadow({
|
|
2664
3048
|
color,
|
|
2665
3049
|
blur: Math.max(0, next.blur),
|
|
2666
3050
|
offsetX: next.offsetX,
|
|
@@ -2774,7 +3158,7 @@ var UnitConverter = class {
|
|
|
2774
3158
|
};
|
|
2775
3159
|
|
|
2776
3160
|
// src/serialization.ts
|
|
2777
|
-
var
|
|
3161
|
+
var import_fabric12 = require("fabric");
|
|
2778
3162
|
var VERSION = "2.0.0";
|
|
2779
3163
|
function serializeEditor(editor) {
|
|
2780
3164
|
return {
|
|
@@ -2810,7 +3194,7 @@ async function deserializeEditor(editor, state) {
|
|
|
2810
3194
|
}
|
|
2811
3195
|
const staged = await Promise.all(
|
|
2812
3196
|
state.layers.map(async (serialized) => {
|
|
2813
|
-
const fabricObject = (await
|
|
3197
|
+
const fabricObject = (await import_fabric12.util.enlivenObjects([serialized.fabricObject]))[0];
|
|
2814
3198
|
if (!fabricObject) {
|
|
2815
3199
|
const source = serialized.fabricObject.src;
|
|
2816
3200
|
if (typeof source === "string" && source.startsWith("blob:")) {
|
|
@@ -2821,7 +3205,7 @@ async function deserializeEditor(editor, state) {
|
|
|
2821
3205
|
return { serialized, fabricObject };
|
|
2822
3206
|
})
|
|
2823
3207
|
);
|
|
2824
|
-
const stagedBackground = state.backgroundImage ? (await
|
|
3208
|
+
const stagedBackground = state.backgroundImage ? (await import_fabric12.util.enlivenObjects([state.backgroundImage]))[0] : null;
|
|
2825
3209
|
if (state.backgroundImage && !stagedBackground) {
|
|
2826
3210
|
const source = state.backgroundImage.src;
|
|
2827
3211
|
if (typeof source === "string" && source.startsWith("blob:")) {
|
|
@@ -2847,6 +3231,7 @@ async function deserializeEditor(editor, state) {
|
|
|
2847
3231
|
for (const item of staged) {
|
|
2848
3232
|
restoreLayer(editor, item.serialized, item.fabricObject);
|
|
2849
3233
|
}
|
|
3234
|
+
editor.wrap.refreshAll();
|
|
2850
3235
|
editor.canvas.requestRenderAll();
|
|
2851
3236
|
}
|
|
2852
3237
|
function restoreLayer(editor, serialized, fabricObject) {
|
|
@@ -2873,7 +3258,7 @@ function restoreLayer(editor, serialized, fabricObject) {
|
|
|
2873
3258
|
}
|
|
2874
3259
|
|
|
2875
3260
|
// src/export.ts
|
|
2876
|
-
var
|
|
3261
|
+
var import_fabric13 = require("fabric");
|
|
2877
3262
|
|
|
2878
3263
|
// src/displacement.ts
|
|
2879
3264
|
var CHANNEL_INDEX = {
|
|
@@ -2967,7 +3352,7 @@ async function exportPNG(canvas, options = {}) {
|
|
|
2967
3352
|
}
|
|
2968
3353
|
async function exportIsolatedPNG(source, objects, options = {}) {
|
|
2969
3354
|
const element = source.lowerCanvasEl.ownerDocument.createElement("canvas");
|
|
2970
|
-
const canvas = new
|
|
3355
|
+
const canvas = new import_fabric13.StaticCanvas(element, {
|
|
2971
3356
|
width: options.width ?? source.getWidth(),
|
|
2972
3357
|
height: options.height ?? source.getHeight(),
|
|
2973
3358
|
backgroundColor: options.backgroundColor || void 0
|
|
@@ -2997,7 +3382,7 @@ async function exportPrintArea(source, area, options = {}) {
|
|
|
2997
3382
|
throw new Error("Print area does not overlap the canvas");
|
|
2998
3383
|
}
|
|
2999
3384
|
const element = source.lowerCanvasEl.ownerDocument.createElement("canvas");
|
|
3000
|
-
const canvas = new
|
|
3385
|
+
const canvas = new import_fabric13.StaticCanvas(element, { width, height });
|
|
3001
3386
|
try {
|
|
3002
3387
|
const clones = await Promise.all(source.getObjects().map((object) => object.clone()));
|
|
3003
3388
|
if (clones.length) canvas.add(...clones);
|
|
@@ -3437,7 +3822,7 @@ var ProjectManager = class {
|
|
|
3437
3822
|
};
|
|
3438
3823
|
|
|
3439
3824
|
// src/mask.ts
|
|
3440
|
-
var
|
|
3825
|
+
var import_fabric14 = require("fabric");
|
|
3441
3826
|
var MaskRefinementError = class extends Error {
|
|
3442
3827
|
constructor(code, message, cause) {
|
|
3443
3828
|
super(message);
|
|
@@ -3469,7 +3854,7 @@ var MaskController = class {
|
|
|
3469
3854
|
throw new Error("Mask dimensions must be positive integers");
|
|
3470
3855
|
}
|
|
3471
3856
|
const backing = this.makeCanvas(width, height);
|
|
3472
|
-
const image = new
|
|
3857
|
+
const image = new import_fabric14.FabricImage(backing, {
|
|
3473
3858
|
left: 0,
|
|
3474
3859
|
top: 0,
|
|
3475
3860
|
originX: "left",
|
|
@@ -3695,10 +4080,10 @@ var MaskController = class {
|
|
|
3695
4080
|
};
|
|
3696
4081
|
|
|
3697
4082
|
// src/masks/manager.ts
|
|
3698
|
-
var
|
|
4083
|
+
var import_fabric20 = require("fabric");
|
|
3699
4084
|
|
|
3700
4085
|
// src/masks/compose.ts
|
|
3701
|
-
var
|
|
4086
|
+
var import_fabric15 = require("fabric");
|
|
3702
4087
|
var MODE_OPERATION = {
|
|
3703
4088
|
add: "source-over",
|
|
3704
4089
|
subtract: "destination-out",
|
|
@@ -3708,7 +4093,7 @@ function neutralize(child) {
|
|
|
3708
4093
|
child.set({ opacity: 0, globalCompositeOperation: "source-over" });
|
|
3709
4094
|
}
|
|
3710
4095
|
function baseRect(box) {
|
|
3711
|
-
return new
|
|
4096
|
+
return new import_fabric15.Rect({
|
|
3712
4097
|
left: box.left,
|
|
3713
4098
|
top: box.top,
|
|
3714
4099
|
width: Math.max(1, box.width),
|
|
@@ -3735,7 +4120,7 @@ function composeMaskGroup(children, entries, options) {
|
|
|
3735
4120
|
});
|
|
3736
4121
|
const first = entries.find((entry) => entry.visible);
|
|
3737
4122
|
const withBase = first && first.mode !== "add" ? [baseRect(options.box), ...children] : [...children];
|
|
3738
|
-
return new
|
|
4123
|
+
return new import_fabric15.Group(withBase, {
|
|
3739
4124
|
absolutePositioned: options.absolute,
|
|
3740
4125
|
// Cached, so the children's compositing operations resolve against each
|
|
3741
4126
|
// other instead of against the page underneath the mask.
|
|
@@ -3749,76 +4134,7 @@ function needsAbsoluteSpace(entries) {
|
|
|
3749
4134
|
}
|
|
3750
4135
|
|
|
3751
4136
|
// src/masks/edit.ts
|
|
3752
|
-
var
|
|
3753
|
-
|
|
3754
|
-
// src/masks/space.ts
|
|
3755
|
-
var import_fabric14 = require("fabric");
|
|
3756
|
-
function matrixOf(object) {
|
|
3757
|
-
return object.calcTransformMatrix();
|
|
3758
|
-
}
|
|
3759
|
-
function applyMatrix(object, matrix) {
|
|
3760
|
-
const decomposed = import_fabric14.util.qrDecompose(matrix);
|
|
3761
|
-
object.set({
|
|
3762
|
-
flipX: false,
|
|
3763
|
-
flipY: false,
|
|
3764
|
-
originX: "center",
|
|
3765
|
-
originY: "center",
|
|
3766
|
-
left: decomposed.translateX,
|
|
3767
|
-
top: decomposed.translateY,
|
|
3768
|
-
scaleX: decomposed.scaleX,
|
|
3769
|
-
scaleY: decomposed.scaleY,
|
|
3770
|
-
angle: decomposed.angle,
|
|
3771
|
-
skewX: decomposed.skewX,
|
|
3772
|
-
skewY: 0
|
|
3773
|
-
});
|
|
3774
|
-
object.setCoords();
|
|
3775
|
-
}
|
|
3776
|
-
function toCanvasSpace(object, host) {
|
|
3777
|
-
applyMatrix(object, import_fabric14.util.multiplyTransformMatrices(matrixOf(host), matrixOf(object)));
|
|
3778
|
-
}
|
|
3779
|
-
function toHostSpace(object, host) {
|
|
3780
|
-
applyMatrix(
|
|
3781
|
-
object,
|
|
3782
|
-
import_fabric14.util.multiplyTransformMatrices(import_fabric14.util.invertTransform(matrixOf(host)), matrixOf(object))
|
|
3783
|
-
);
|
|
3784
|
-
}
|
|
3785
|
-
function relativeMatrix(object, host) {
|
|
3786
|
-
return import_fabric14.util.multiplyTransformMatrices(import_fabric14.util.invertTransform(matrixOf(host)), matrixOf(object));
|
|
3787
|
-
}
|
|
3788
|
-
function applyRelativeMatrix(object, host, rel) {
|
|
3789
|
-
applyMatrix(object, import_fabric14.util.multiplyTransformMatrices(matrixOf(host), rel));
|
|
3790
|
-
}
|
|
3791
|
-
function asObject(clip) {
|
|
3792
|
-
return clip;
|
|
3793
|
-
}
|
|
3794
|
-
function toMatrix(values) {
|
|
3795
|
-
if (!values || values.length !== 6 || values.some((value) => !Number.isFinite(value)))
|
|
3796
|
-
return null;
|
|
3797
|
-
return [values[0], values[1], values[2], values[3], values[4], values[5]];
|
|
3798
|
-
}
|
|
3799
|
-
function fitToBox(object, box, zoom = 1) {
|
|
3800
|
-
const width = Math.max(1, box.width) * zoom;
|
|
3801
|
-
const height = Math.max(1, box.height) * zoom;
|
|
3802
|
-
object.set({
|
|
3803
|
-
originX: "center",
|
|
3804
|
-
originY: "center",
|
|
3805
|
-
angle: 0,
|
|
3806
|
-
skewX: 0,
|
|
3807
|
-
skewY: 0,
|
|
3808
|
-
left: box.left + box.width / 2,
|
|
3809
|
-
top: box.top + box.height / 2,
|
|
3810
|
-
scaleX: width / Math.max(1, object.width ?? 1),
|
|
3811
|
-
scaleY: height / Math.max(1, object.height ?? 1)
|
|
3812
|
-
});
|
|
3813
|
-
object.setCoords();
|
|
3814
|
-
}
|
|
3815
|
-
function unwrapGroup(group) {
|
|
3816
|
-
const children = group.removeAll();
|
|
3817
|
-
for (const child of children) child.setCoords();
|
|
3818
|
-
return children;
|
|
3819
|
-
}
|
|
3820
|
-
|
|
3821
|
-
// src/masks/edit.ts
|
|
4137
|
+
var import_fabric16 = require("fabric");
|
|
3822
4138
|
var MaskEditController = class {
|
|
3823
4139
|
constructor(canvas, onCommit) {
|
|
3824
4140
|
this.canvas = canvas;
|
|
@@ -3899,8 +4215,8 @@ var MaskEditController = class {
|
|
|
3899
4215
|
if (!this.handle || !this.child || !this.group) return;
|
|
3900
4216
|
applyMatrix(
|
|
3901
4217
|
this.child,
|
|
3902
|
-
|
|
3903
|
-
|
|
4218
|
+
import_fabric16.util.multiplyTransformMatrices(
|
|
4219
|
+
import_fabric16.util.invertTransform(matrixOf(this.group)),
|
|
3904
4220
|
matrixOf(this.handle)
|
|
3905
4221
|
)
|
|
3906
4222
|
);
|
|
@@ -3911,15 +4227,15 @@ var MaskEditController = class {
|
|
|
3911
4227
|
};
|
|
3912
4228
|
|
|
3913
4229
|
// src/masks/store.ts
|
|
3914
|
-
var
|
|
4230
|
+
var import_fabric19 = require("fabric");
|
|
3915
4231
|
|
|
3916
4232
|
// src/masks/host.ts
|
|
3917
|
-
var
|
|
4233
|
+
var import_fabric17 = require("fabric");
|
|
3918
4234
|
function findCanvasHost(layers) {
|
|
3919
4235
|
return layers.getAll().find((layer) => layer.meta.canvasMask);
|
|
3920
4236
|
}
|
|
3921
4237
|
function createCanvasHost(canvas, layers) {
|
|
3922
|
-
const rect = new
|
|
4238
|
+
const rect = new import_fabric17.Rect({
|
|
3923
4239
|
left: 0,
|
|
3924
4240
|
top: 0,
|
|
3925
4241
|
width: canvas.getWidth(),
|
|
@@ -3968,9 +4284,9 @@ function hostBoxOf(canvas, host, absolute) {
|
|
|
3968
4284
|
}
|
|
3969
4285
|
|
|
3970
4286
|
// src/masks/install.ts
|
|
3971
|
-
var
|
|
4287
|
+
var import_fabric18 = require("fabric");
|
|
3972
4288
|
function convertSpace(host, sources, absolute) {
|
|
3973
|
-
const wasAbsolute = host.clipPath instanceof
|
|
4289
|
+
const wasAbsolute = host.clipPath instanceof import_fabric18.Group ? host.clipPath.absolutePositioned : absolute;
|
|
3974
4290
|
if (absolute === wasAbsolute) return;
|
|
3975
4291
|
for (const source of sources) {
|
|
3976
4292
|
if (absolute) toCanvasSpace(source, host);
|
|
@@ -4050,6 +4366,24 @@ var MaskStackStore = class {
|
|
|
4050
4366
|
this.pinning = false;
|
|
4051
4367
|
}
|
|
4052
4368
|
}
|
|
4369
|
+
/**
|
|
4370
|
+
* Is the host's own `clipPath` the wrap manager's box clip rather than a mask?
|
|
4371
|
+
*
|
|
4372
|
+
* Adoption rescues a clip whose provenance is UNKNOWN — a mask preset, or a
|
|
4373
|
+
* hand-set `clipPath` from before stacks existed — so the first add() cannot
|
|
4374
|
+
* silently throw it away. A text layer's box clip is the opposite case: its
|
|
4375
|
+
* provenance is known exactly (the wrap manager derives it from
|
|
4376
|
+
* `meta.overflow` on every pass and re-installs it under whatever owns the
|
|
4377
|
+
* property next), and it is not a mask. Adopted, it becomes a stack row the
|
|
4378
|
+
* user never made whose 'add' union covers the whole box — swallowing the mask
|
|
4379
|
+
* they actually added.
|
|
4380
|
+
*
|
|
4381
|
+
* Only meaningful with an empty stack: once there are entries the top-level
|
|
4382
|
+
* clip is the composed group and the box clip is nested underneath it.
|
|
4383
|
+
*/
|
|
4384
|
+
holdsBoxClip(meta) {
|
|
4385
|
+
return meta?.overflow === "hidden" && !meta.maskPreset;
|
|
4386
|
+
}
|
|
4053
4387
|
/**
|
|
4054
4388
|
* Take the current geometry back out of the composed clip, entry-aligned.
|
|
4055
4389
|
*
|
|
@@ -4062,7 +4396,13 @@ var MaskStackStore = class {
|
|
|
4062
4396
|
const clip = host.clipPath;
|
|
4063
4397
|
if (!clip) return [];
|
|
4064
4398
|
const entries = this.list(target);
|
|
4065
|
-
|
|
4399
|
+
const meta = this.hostLayer(target)?.meta;
|
|
4400
|
+
if (entries.length === 0 && this.holdsBoxClip(meta)) return [];
|
|
4401
|
+
if (entries.length === 0 || !(clip instanceof import_fabric19.Group)) {
|
|
4402
|
+
const source = asObject(clip);
|
|
4403
|
+
if (meta?.overflow === "hidden") source.clipPath = void 0;
|
|
4404
|
+
return [source];
|
|
4405
|
+
}
|
|
4066
4406
|
const children = unwrapGroup(clip);
|
|
4067
4407
|
const extra = children.length - entries.length;
|
|
4068
4408
|
return extra > 0 ? children.slice(extra) : children;
|
|
@@ -4162,7 +4502,7 @@ var LayerMaskManager = class extends MaskStackStore {
|
|
|
4162
4502
|
if (index === -1) return false;
|
|
4163
4503
|
this.endEdit(false);
|
|
4164
4504
|
this.commit(target, host, [...entries], this.unwrap(target, host), false, true);
|
|
4165
|
-
const group = host.clipPath instanceof
|
|
4505
|
+
const group = host.clipPath instanceof import_fabric20.Group ? host.clipPath : null;
|
|
4166
4506
|
if (!group) return false;
|
|
4167
4507
|
const children = group.getObjects();
|
|
4168
4508
|
const child = children[children.length - entries.length + index];
|
|
@@ -4393,6 +4733,7 @@ var LayerMaskManager = class extends MaskStackStore {
|
|
|
4393
4733
|
const clip = layer?.fabricObject.clipPath;
|
|
4394
4734
|
if (!layer || !clip || layer.meta.pattern) return null;
|
|
4395
4735
|
if ((layer.meta.maskStack ?? []).length > 0) return null;
|
|
4736
|
+
if (this.holdsBoxClip(layer.meta)) return null;
|
|
4396
4737
|
const entry = {
|
|
4397
4738
|
...DEFAULT_ENTRY,
|
|
4398
4739
|
id: generateId(),
|
|
@@ -4429,6 +4770,109 @@ var LayerMaskManager = class extends MaskStackStore {
|
|
|
4429
4770
|
}
|
|
4430
4771
|
};
|
|
4431
4772
|
|
|
4773
|
+
// src/gradient.ts
|
|
4774
|
+
var import_fabric21 = require("fabric");
|
|
4775
|
+
var DEFAULT_GRADIENT_CONFIG = {
|
|
4776
|
+
kind: "linear",
|
|
4777
|
+
angle: 90,
|
|
4778
|
+
center: { x: 0.5, y: 0.5 },
|
|
4779
|
+
radius: 0.5,
|
|
4780
|
+
stops: [
|
|
4781
|
+
{ color: "#ffffff", opacity: 1, position: 0 },
|
|
4782
|
+
{ color: "#000000", opacity: 1, position: 1 }
|
|
4783
|
+
]
|
|
4784
|
+
};
|
|
4785
|
+
var MIN_RADIUS = 1e-3;
|
|
4786
|
+
var FALLBACK_STOP_COLOR = DEFAULT_GRADIENT_CONFIG.stops[0].color;
|
|
4787
|
+
function linearCoords(angle, box) {
|
|
4788
|
+
const radians = angle * Math.PI / 180;
|
|
4789
|
+
const sin = Math.sin(radians);
|
|
4790
|
+
const cos = Math.cos(radians);
|
|
4791
|
+
const vx = box.width * sin;
|
|
4792
|
+
const vy = -box.height * cos;
|
|
4793
|
+
const length = Math.abs(box.width * sin) + Math.abs(box.height * cos);
|
|
4794
|
+
const scale = length / (vx * vx + vy * vy || 1);
|
|
4795
|
+
return {
|
|
4796
|
+
x1: 0.5 - scale * vx / 2,
|
|
4797
|
+
y1: 0.5 - scale * vy / 2,
|
|
4798
|
+
x2: 0.5 + scale * vx / 2,
|
|
4799
|
+
y2: 0.5 + scale * vy / 2
|
|
4800
|
+
};
|
|
4801
|
+
}
|
|
4802
|
+
function angleFromCoords(coords, box) {
|
|
4803
|
+
const dx = (coords.x2 - coords.x1) / (box.width || 1);
|
|
4804
|
+
const dy = (coords.y2 - coords.y1) / (box.height || 1);
|
|
4805
|
+
const degrees = Math.atan2(dx, -dy) * 180 / Math.PI;
|
|
4806
|
+
return (degrees + 360) % 360;
|
|
4807
|
+
}
|
|
4808
|
+
function stopColor(stop) {
|
|
4809
|
+
const source = isCssColor(stop.color) ? stop.color : FALLBACK_STOP_COLOR;
|
|
4810
|
+
const color = new import_fabric21.Color(source);
|
|
4811
|
+
const opacity = Number.isFinite(stop.opacity) ? stop.opacity : 1;
|
|
4812
|
+
color.setAlpha(clamp(opacity, 0, 1));
|
|
4813
|
+
return color.toRgba();
|
|
4814
|
+
}
|
|
4815
|
+
function toFabricGradient(config, box) {
|
|
4816
|
+
const colorStops = [...config.stops].sort((a, b) => a.position - b.position).map((stop) => {
|
|
4817
|
+
const position = Number.isFinite(stop.position) ? stop.position : 0;
|
|
4818
|
+
return { offset: clamp(position, 0, 1), color: stopColor(stop) };
|
|
4819
|
+
});
|
|
4820
|
+
if (config.kind === "radial") {
|
|
4821
|
+
const radius = Math.max(MIN_RADIUS, config.radius);
|
|
4822
|
+
return new import_fabric21.Gradient({
|
|
4823
|
+
type: "radial",
|
|
4824
|
+
gradientUnits: "percentage",
|
|
4825
|
+
coords: {
|
|
4826
|
+
x1: config.center.x,
|
|
4827
|
+
y1: config.center.y,
|
|
4828
|
+
r1: 0,
|
|
4829
|
+
x2: config.center.x,
|
|
4830
|
+
y2: config.center.y,
|
|
4831
|
+
r2: radius
|
|
4832
|
+
},
|
|
4833
|
+
colorStops
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
4836
|
+
return new import_fabric21.Gradient({
|
|
4837
|
+
type: "linear",
|
|
4838
|
+
gradientUnits: "percentage",
|
|
4839
|
+
coords: linearCoords(config.angle, box),
|
|
4840
|
+
colorStops
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
function readGradientConfig(object) {
|
|
4844
|
+
const fill = object.fill;
|
|
4845
|
+
if (!fill || typeof fill === "string" || !(fill instanceof import_fabric21.Gradient)) return null;
|
|
4846
|
+
const stops = fill.colorStops.map((stop) => {
|
|
4847
|
+
const source = isCssColor(stop.color) ? stop.color : FALLBACK_STOP_COLOR;
|
|
4848
|
+
const color = new import_fabric21.Color(source);
|
|
4849
|
+
const offset = Number.isFinite(stop.offset) ? stop.offset : 0;
|
|
4850
|
+
return {
|
|
4851
|
+
color: `#${color.toHex().toLowerCase()}`,
|
|
4852
|
+
opacity: color.getAlpha(),
|
|
4853
|
+
position: clamp(offset, 0, 1)
|
|
4854
|
+
};
|
|
4855
|
+
});
|
|
4856
|
+
if (fill.type === "radial") {
|
|
4857
|
+
const { x1, y1, r2 } = fill.coords;
|
|
4858
|
+
return {
|
|
4859
|
+
kind: "radial",
|
|
4860
|
+
angle: DEFAULT_GRADIENT_CONFIG.angle,
|
|
4861
|
+
center: { x: x1, y: y1 },
|
|
4862
|
+
radius: r2,
|
|
4863
|
+
stops
|
|
4864
|
+
};
|
|
4865
|
+
}
|
|
4866
|
+
const box = { width: object.width || 1, height: object.height || 1 };
|
|
4867
|
+
return {
|
|
4868
|
+
kind: "linear",
|
|
4869
|
+
angle: angleFromCoords(fill.coords, box),
|
|
4870
|
+
center: { ...DEFAULT_GRADIENT_CONFIG.center },
|
|
4871
|
+
radius: DEFAULT_GRADIENT_CONFIG.radius,
|
|
4872
|
+
stops
|
|
4873
|
+
};
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4432
4876
|
// src/editor.ts
|
|
4433
4877
|
var MIN_ZOOM = 0.1;
|
|
4434
4878
|
var MAX_ZOOM = 8;
|
|
@@ -4445,6 +4889,7 @@ var CanvasEditor = class {
|
|
|
4445
4889
|
crop;
|
|
4446
4890
|
patterns;
|
|
4447
4891
|
curves;
|
|
4892
|
+
wrap;
|
|
4448
4893
|
maskPresets;
|
|
4449
4894
|
/** Stacked boolean masks, per layer and for the design as a whole. */
|
|
4450
4895
|
layerMasks;
|
|
@@ -4472,7 +4917,7 @@ var CanvasEditor = class {
|
|
|
4472
4917
|
const widthPx = this.units.toPixels(config.width);
|
|
4473
4918
|
const heightPx = this.units.toPixels(config.height);
|
|
4474
4919
|
this.designBackground = config.backgroundColor ?? "#ffffff";
|
|
4475
|
-
this.canvas = new
|
|
4920
|
+
this.canvas = new import_fabric22.Canvas(canvasElement, {
|
|
4476
4921
|
width: widthPx,
|
|
4477
4922
|
height: heightPx,
|
|
4478
4923
|
backgroundColor: this.designBackground,
|
|
@@ -4495,6 +4940,7 @@ var CanvasEditor = class {
|
|
|
4495
4940
|
this.crop = new CropController(this.canvas, this.history, this.events);
|
|
4496
4941
|
this.patterns = new PatternManager(this.canvas, this.layers, this.history, this.events);
|
|
4497
4942
|
this.curves = new TextCurveManager(this.canvas, this.layers, this.history, this.events);
|
|
4943
|
+
this.wrap = new TextWrapManager(this.canvas, this.layers, this.history, this.events);
|
|
4498
4944
|
this.maskPresets = new MaskPresetManager(this.canvas, this.layers, this.history, this.events);
|
|
4499
4945
|
this.layerMasks = new LayerMaskManager(this.canvas, this.layers, this.history, this.events);
|
|
4500
4946
|
this.setupCanvasEvents();
|
|
@@ -4506,7 +4952,7 @@ var CanvasEditor = class {
|
|
|
4506
4952
|
// ─── Layer Operations ────────────────────────────────
|
|
4507
4953
|
async addImage(url, options) {
|
|
4508
4954
|
try {
|
|
4509
|
-
const img = await
|
|
4955
|
+
const img = await import_fabric22.FabricImage.fromURL(
|
|
4510
4956
|
url,
|
|
4511
4957
|
{},
|
|
4512
4958
|
{ originX: "left", originY: "top", ...options }
|
|
@@ -4532,7 +4978,7 @@ var CanvasEditor = class {
|
|
|
4532
4978
|
if (this.crop.activeLayerId() === layerId) this.crop.cancel();
|
|
4533
4979
|
const previous = layer.fabricObject;
|
|
4534
4980
|
try {
|
|
4535
|
-
const replacement = await
|
|
4981
|
+
const replacement = await import_fabric22.FabricImage.fromURL(url, {}, { originX: "left", originY: "top" });
|
|
4536
4982
|
replacement.set({
|
|
4537
4983
|
left: previous.left,
|
|
4538
4984
|
top: previous.top,
|
|
@@ -4561,7 +5007,7 @@ var CanvasEditor = class {
|
|
|
4561
5007
|
}
|
|
4562
5008
|
}
|
|
4563
5009
|
addText(text, options) {
|
|
4564
|
-
const textbox = new
|
|
5010
|
+
const textbox = new import_fabric22.Textbox(text, {
|
|
4565
5011
|
fontSize: 32,
|
|
4566
5012
|
fontFamily: "Arial",
|
|
4567
5013
|
fill: "#000000",
|
|
@@ -4583,6 +5029,65 @@ var CanvasEditor = class {
|
|
|
4583
5029
|
this.history.save();
|
|
4584
5030
|
return layer;
|
|
4585
5031
|
}
|
|
5032
|
+
/**
|
|
5033
|
+
* Insert a gradient layer. It is an ordinary `Rect` with a gradient fill —
|
|
5034
|
+
* which is exactly why the Node print compositor needs no code for it.
|
|
5035
|
+
*/
|
|
5036
|
+
addGradient(config = DEFAULT_GRADIENT_CONFIG, box) {
|
|
5037
|
+
const width = box?.width ?? this.canvas.getWidth();
|
|
5038
|
+
const height = box?.height ?? this.canvas.getHeight();
|
|
5039
|
+
const object = new import_fabric22.Rect({
|
|
5040
|
+
left: box?.left ?? 0,
|
|
5041
|
+
top: box?.top ?? 0,
|
|
5042
|
+
originX: "left",
|
|
5043
|
+
originY: "top",
|
|
5044
|
+
width,
|
|
5045
|
+
height,
|
|
5046
|
+
// A gradient fill IS the artwork; an outline is not part of this
|
|
5047
|
+
// layer's design, only its own gradient (unlike a plain shape, where a
|
|
5048
|
+
// stroke is a legitimate look).
|
|
5049
|
+
strokeWidth: 0,
|
|
5050
|
+
fill: toFabricGradient(config, { width, height })
|
|
5051
|
+
});
|
|
5052
|
+
const layer = this.layers.add("gradient", object, "Gradient");
|
|
5053
|
+
this.layers.select(layer.id);
|
|
5054
|
+
this.history.save();
|
|
5055
|
+
return layer;
|
|
5056
|
+
}
|
|
5057
|
+
/**
|
|
5058
|
+
* Repaint a layer's gradient. `save: false` while a slider is being dragged —
|
|
5059
|
+
* the settled value is the one worth an undo step.
|
|
5060
|
+
*/
|
|
5061
|
+
setGradient(layerId, config, save = true) {
|
|
5062
|
+
const layer = this.layers.get(layerId);
|
|
5063
|
+
if (!layer) return;
|
|
5064
|
+
const object = layer.fabricObject;
|
|
5065
|
+
object.set({
|
|
5066
|
+
fill: toFabricGradient(config, {
|
|
5067
|
+
width: object.width || 1,
|
|
5068
|
+
height: object.height || 1
|
|
5069
|
+
})
|
|
5070
|
+
});
|
|
5071
|
+
object.dirty = true;
|
|
5072
|
+
this.canvas.requestRenderAll();
|
|
5073
|
+
this.events.emit("layer:modified", { layerId });
|
|
5074
|
+
if (save) this.history.save();
|
|
5075
|
+
}
|
|
5076
|
+
/** Set a layer's blend mode. Applied to the render proxy too, like opacity. */
|
|
5077
|
+
setBlend(layerId, mode) {
|
|
5078
|
+
const layer = this.layers.get(layerId);
|
|
5079
|
+
if (!layer) return;
|
|
5080
|
+
const operation = blendOperation(mode);
|
|
5081
|
+
layer.fabricObject.set({ globalCompositeOperation: operation });
|
|
5082
|
+
layer.fabricObject.dirty = true;
|
|
5083
|
+
if (layer.renderProxy) {
|
|
5084
|
+
layer.renderProxy.set({ globalCompositeOperation: operation });
|
|
5085
|
+
layer.renderProxy.dirty = true;
|
|
5086
|
+
}
|
|
5087
|
+
this.canvas.requestRenderAll();
|
|
5088
|
+
this.events.emit("layer:modified", { layerId });
|
|
5089
|
+
this.history.save();
|
|
5090
|
+
}
|
|
4586
5091
|
async addTemplate(template, params) {
|
|
4587
5092
|
const values = {};
|
|
4588
5093
|
for (const parameter of template.parameters) {
|
|
@@ -4692,10 +5197,10 @@ var CanvasEditor = class {
|
|
|
4692
5197
|
const next = { ...previous, ...adjustments };
|
|
4693
5198
|
const clampAdjustment = (value, min = -1) => clamp(value ?? 0, min, 1);
|
|
4694
5199
|
image.filters = [
|
|
4695
|
-
new
|
|
4696
|
-
new
|
|
4697
|
-
new
|
|
4698
|
-
new
|
|
5200
|
+
new import_fabric22.filters.Brightness({ brightness: clampAdjustment(next.brightness) }),
|
|
5201
|
+
new import_fabric22.filters.Contrast({ contrast: clampAdjustment(next.contrast) }),
|
|
5202
|
+
new import_fabric22.filters.Saturation({ saturation: clampAdjustment(next.saturation) }),
|
|
5203
|
+
new import_fabric22.filters.Blur({ blur: clampAdjustment(next.blur, 0) })
|
|
4699
5204
|
];
|
|
4700
5205
|
layer.meta.imageAdjustments = next;
|
|
4701
5206
|
image.applyFilters();
|
|
@@ -4736,7 +5241,7 @@ var CanvasEditor = class {
|
|
|
4736
5241
|
this.layers.detach(layer.id);
|
|
4737
5242
|
}
|
|
4738
5243
|
}
|
|
4739
|
-
const group = new
|
|
5244
|
+
const group = new import_fabric22.Group(objects);
|
|
4740
5245
|
const grouped = this.layers.add("group", group, name);
|
|
4741
5246
|
this.layers.adoptChildren(grouped, children);
|
|
4742
5247
|
this.layers.reorder(grouped.id, insertIndex);
|
|
@@ -4798,7 +5303,7 @@ var CanvasEditor = class {
|
|
|
4798
5303
|
const layer = this.layers.get(id);
|
|
4799
5304
|
if (!layer) throw new Error(`Layer not found: ${id}`);
|
|
4800
5305
|
try {
|
|
4801
|
-
if (options.resolution === "source" && layer.fabricObject instanceof
|
|
5306
|
+
if (options.resolution === "source" && layer.fabricObject instanceof import_fabric22.FabricImage) {
|
|
4802
5307
|
const image = await layer.fabricObject.clone();
|
|
4803
5308
|
image.set({
|
|
4804
5309
|
left: 0,
|
|
@@ -5074,7 +5579,7 @@ var CanvasEditor = class {
|
|
|
5074
5579
|
return;
|
|
5075
5580
|
}
|
|
5076
5581
|
try {
|
|
5077
|
-
const image = await
|
|
5582
|
+
const image = await import_fabric22.FabricImage.fromURL(
|
|
5078
5583
|
url,
|
|
5079
5584
|
{ crossOrigin: options.crossOrigin ?? null, signal: options.signal },
|
|
5080
5585
|
{ originX: "left", originY: "top" }
|
|
@@ -5251,15 +5756,34 @@ var CanvasEditor = class {
|
|
|
5251
5756
|
}
|
|
5252
5757
|
// ─── Text curve ─────────────────────────────────────
|
|
5253
5758
|
applyTextCurve(layerId, config) {
|
|
5254
|
-
|
|
5759
|
+
const applied = this.curves.apply(layerId, config);
|
|
5760
|
+
if (applied) this.wrap.refresh(layerId);
|
|
5761
|
+
return applied;
|
|
5255
5762
|
}
|
|
5256
5763
|
clearTextCurve(layerId) {
|
|
5257
|
-
|
|
5764
|
+
const cleared = this.curves.clear(layerId);
|
|
5765
|
+
if (cleared) this.wrap.refresh(layerId);
|
|
5766
|
+
return cleared;
|
|
5258
5767
|
}
|
|
5259
5768
|
getTextCurve(layerId) {
|
|
5260
5769
|
return this.curves.get(layerId);
|
|
5261
5770
|
}
|
|
5771
|
+
// ─── Text wrap ──────────────────────────────────────
|
|
5772
|
+
applyTextWrap(layerId, wrap) {
|
|
5773
|
+
return this.wrap.apply(layerId, wrap);
|
|
5774
|
+
}
|
|
5775
|
+
setTextOverflow(layerId, overflow) {
|
|
5776
|
+
return this.wrap.setOverflow(layerId, overflow);
|
|
5777
|
+
}
|
|
5778
|
+
getTextWrap(layerId) {
|
|
5779
|
+
return this.wrap.get(layerId);
|
|
5780
|
+
}
|
|
5262
5781
|
// ─── Mask presets ───────────────────────────────────
|
|
5782
|
+
// A preset assigns `clipPath` wholesale, so a text layer clipping to its box
|
|
5783
|
+
// loses that clip the moment a mask lands on it. Putting it back is NOT wired
|
|
5784
|
+
// here: the preset manager announces `masks:changed` and the wrap manager
|
|
5785
|
+
// re-derives from that, which covers this facade, the manager called directly,
|
|
5786
|
+
// and `refreshAll()` on a restore — all with one mechanism.
|
|
5263
5787
|
applyMaskPreset(layerId, id) {
|
|
5264
5788
|
return this.maskPresets.apply(layerId, id);
|
|
5265
5789
|
}
|
|
@@ -5348,6 +5872,7 @@ var CanvasEditor = class {
|
|
|
5348
5872
|
this.history.dispose();
|
|
5349
5873
|
this.patterns.dispose();
|
|
5350
5874
|
this.curves.dispose();
|
|
5875
|
+
this.wrap.dispose();
|
|
5351
5876
|
this.events.removeAllListeners();
|
|
5352
5877
|
this.canvas.dispose();
|
|
5353
5878
|
}
|
|
@@ -5471,10 +5996,13 @@ var AnnotationOverlay = class {
|
|
|
5471
5996
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5472
5997
|
0 && (module.exports = {
|
|
5473
5998
|
AnnotationOverlay,
|
|
5999
|
+
BLEND_GROUPS,
|
|
6000
|
+
BLEND_MODES,
|
|
5474
6001
|
CANVAS_MASK_TARGET,
|
|
5475
6002
|
CANVAS_SIZE_PRESETS,
|
|
5476
6003
|
CanvasEditor,
|
|
5477
6004
|
CropController,
|
|
6005
|
+
DEFAULT_GRADIENT_CONFIG,
|
|
5478
6006
|
DEFAULT_LAYER_SHADOW,
|
|
5479
6007
|
DEFAULT_PATTERN_CONFIG,
|
|
5480
6008
|
DEFAULT_SELECTION_STYLE,
|
|
@@ -5497,12 +6025,18 @@ var AnnotationOverlay = class {
|
|
|
5497
6025
|
TEXTURE_MASK_IDS,
|
|
5498
6026
|
TEXTURE_MASK_SIZE,
|
|
5499
6027
|
TextCurveManager,
|
|
6028
|
+
TextWrapManager,
|
|
5500
6029
|
TiledPatternObject,
|
|
5501
6030
|
UnitConverter,
|
|
6031
|
+
angleFromCoords,
|
|
5502
6032
|
applyAspectLock,
|
|
5503
6033
|
applyLayerShadow,
|
|
5504
6034
|
applyObjectSelectionStyle,
|
|
5505
6035
|
applySelectionStyle,
|
|
6036
|
+
applyTextWrapToObject,
|
|
6037
|
+
blendModeLabel,
|
|
6038
|
+
blendModeOf,
|
|
6039
|
+
blendOperation,
|
|
5506
6040
|
buildCurveLinePaths,
|
|
5507
6041
|
buildCurvePathData,
|
|
5508
6042
|
clamp,
|
|
@@ -5528,9 +6062,13 @@ var AnnotationOverlay = class {
|
|
|
5528
6062
|
isMaskPresetId,
|
|
5529
6063
|
isShapeMaskId,
|
|
5530
6064
|
isTextureMaskId,
|
|
6065
|
+
linearCoords,
|
|
5531
6066
|
needsAbsoluteSpace,
|
|
5532
6067
|
normalizeTextCurve,
|
|
6068
|
+
preWrapWordSplit,
|
|
6069
|
+
readGradientConfig,
|
|
5533
6070
|
readLayerShadow,
|
|
6071
|
+
readTextWrap,
|
|
5534
6072
|
renderTextureMask,
|
|
5535
6073
|
resetTransform,
|
|
5536
6074
|
restoreLocks,
|
|
@@ -5541,6 +6079,7 @@ var AnnotationOverlay = class {
|
|
|
5541
6079
|
textPathCurve,
|
|
5542
6080
|
textPathSpec,
|
|
5543
6081
|
toCanvasSpace,
|
|
6082
|
+
toFabricGradient,
|
|
5544
6083
|
toHostSpace,
|
|
5545
6084
|
unwrapGroup
|
|
5546
6085
|
});
|