@pixerate/editor 0.12.0 → 0.14.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/grammar/index.cjs +45 -58
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +13 -3
- package/dist/grammar/index.d.ts +13 -3
- package/dist/grammar/index.js +42 -58
- package/dist/grammar/index.js.map +1 -1
- package/dist/image-editor/index.cjs +93 -1
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +34 -1
- package/dist/image-editor/index.d.ts +34 -1
- package/dist/image-editor/index.js +93 -1
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index.cjs +138 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +135 -59
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -66,6 +66,8 @@ __export(src_exports, {
|
|
|
66
66
|
SmilieReplacer: () => SmilieReplacer,
|
|
67
67
|
SpreadsheetController: () => SpreadsheetController,
|
|
68
68
|
StreamingLayoutManager: () => StreamingLayoutManager,
|
|
69
|
+
TEMPLATE_DEPTH_ERROR: () => TEMPLATE_DEPTH_ERROR,
|
|
70
|
+
TEMPLATE_LOOP_ERROR: () => TEMPLATE_LOOP_ERROR,
|
|
69
71
|
TEMPLATE_REGEX: () => TEMPLATE_REGEX,
|
|
70
72
|
TemplateSuggestions: () => TemplateSuggestions,
|
|
71
73
|
VARIABLE_REGEX: () => VARIABLE_REGEX,
|
|
@@ -111,6 +113,7 @@ __export(src_exports, {
|
|
|
111
113
|
getEditorText: () => getEditorText,
|
|
112
114
|
getLatestVersion: () => getLatestVersion,
|
|
113
115
|
getLayoutedNodes: () => getLayoutedNodes,
|
|
116
|
+
getTemplateBody: () => getTemplateBody,
|
|
114
117
|
getViewportMetrics: () => getViewportMetrics,
|
|
115
118
|
globalImageCache: () => globalImageCache,
|
|
116
119
|
handleImageInsertion: () => handleImageInsertion,
|
|
@@ -280,6 +283,18 @@ function getLatestVersion(template) {
|
|
|
280
283
|
}
|
|
281
284
|
return template.versions[template.versions.length - 1];
|
|
282
285
|
}
|
|
286
|
+
var TEMPLATE_LOOP_ERROR = "[Template loop detected]";
|
|
287
|
+
var TEMPLATE_DEPTH_ERROR = "[Template max depth exceeded]";
|
|
288
|
+
function getTemplateBody(template, bindings) {
|
|
289
|
+
const boundVersionId = bindings?.[template.name];
|
|
290
|
+
if (boundVersionId && template.versions) {
|
|
291
|
+
const boundVersion = template.versions.find(
|
|
292
|
+
(v) => v.id === boundVersionId || v.version === boundVersionId
|
|
293
|
+
);
|
|
294
|
+
return boundVersion?.body;
|
|
295
|
+
}
|
|
296
|
+
return getLatestVersion(template)?.body ?? template.body;
|
|
297
|
+
}
|
|
283
298
|
function resolveTemplates(text, templates = [], options) {
|
|
284
299
|
const templateMap = /* @__PURE__ */ new Map();
|
|
285
300
|
for (const t of templates) {
|
|
@@ -287,50 +302,27 @@ function resolveTemplates(text, templates = [], options) {
|
|
|
287
302
|
}
|
|
288
303
|
const maxDepth = options?.maxDepth ?? 10;
|
|
289
304
|
function resolveRecursive(currentText, visited, depth) {
|
|
290
|
-
if (depth > maxDepth) {
|
|
291
|
-
return "[Template max depth exceeded]";
|
|
292
|
-
}
|
|
293
|
-
let result = currentText;
|
|
294
305
|
const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
|
|
295
|
-
|
|
296
|
-
while ((match = regex.exec(result)) !== null) {
|
|
297
|
-
const [fullMatch, rawTemplateName] = match;
|
|
306
|
+
return currentText.replace(regex, (fullMatch, rawTemplateName) => {
|
|
298
307
|
const templateName = rawTemplateName.trim();
|
|
299
308
|
if (visited.has(templateName)) {
|
|
300
|
-
return
|
|
309
|
+
return TEMPLATE_LOOP_ERROR;
|
|
301
310
|
}
|
|
302
311
|
const template = templateMap.get(templateName);
|
|
303
312
|
if (!template) {
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
let versionBody;
|
|
307
|
-
const boundVersionId = options?.bindings?.[templateName];
|
|
308
|
-
if (boundVersionId && template.versions) {
|
|
309
|
-
const boundVersion = template.versions.find(
|
|
310
|
-
(v) => v.id === boundVersionId || v.version === boundVersionId
|
|
311
|
-
);
|
|
312
|
-
versionBody = boundVersion?.body;
|
|
313
|
-
} else {
|
|
314
|
-
const latest = getLatestVersion(template);
|
|
315
|
-
versionBody = latest?.body ?? template.body;
|
|
313
|
+
return fullMatch;
|
|
316
314
|
}
|
|
315
|
+
const versionBody = getTemplateBody(template, options?.bindings);
|
|
317
316
|
if (versionBody === void 0) {
|
|
318
|
-
|
|
317
|
+
return fullMatch;
|
|
318
|
+
}
|
|
319
|
+
if (depth + 1 > maxDepth) {
|
|
320
|
+
return TEMPLATE_DEPTH_ERROR;
|
|
319
321
|
}
|
|
320
322
|
const nextVisited = new Set(visited);
|
|
321
323
|
nextVisited.add(templateName);
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
nextVisited,
|
|
325
|
-
depth + 1
|
|
326
|
-
);
|
|
327
|
-
if (resolvedBody === "[Template loop detected]" || resolvedBody === "[Template max depth exceeded]") {
|
|
328
|
-
return resolvedBody;
|
|
329
|
-
}
|
|
330
|
-
result = result.replace(fullMatch, resolvedBody);
|
|
331
|
-
regex.lastIndex = 0;
|
|
332
|
-
}
|
|
333
|
-
return result;
|
|
324
|
+
return resolveRecursive(versionBody, nextVisited, depth + 1);
|
|
325
|
+
});
|
|
334
326
|
}
|
|
335
327
|
return resolveRecursive(text, /* @__PURE__ */ new Set(), 0);
|
|
336
328
|
}
|
|
@@ -379,7 +371,7 @@ function extractInstructionNames(text) {
|
|
|
379
371
|
}
|
|
380
372
|
|
|
381
373
|
// src/grammar/sourcemap.ts
|
|
382
|
-
function resolveTemplatesWithMapping(text, templates = [], templateBindings) {
|
|
374
|
+
function resolveTemplatesWithMapping(text, templates = [], templateBindings, options) {
|
|
383
375
|
if (!templates || templates.length === 0 || !text.includes("{{")) {
|
|
384
376
|
return {
|
|
385
377
|
text,
|
|
@@ -395,7 +387,7 @@ function resolveTemplatesWithMapping(text, templates = [], templateBindings) {
|
|
|
395
387
|
};
|
|
396
388
|
}
|
|
397
389
|
const templateMap = new Map(templates.map((t) => [t.name, t]));
|
|
398
|
-
const regex =
|
|
390
|
+
const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
|
|
399
391
|
let match;
|
|
400
392
|
let lastIndex = 0;
|
|
401
393
|
let resolvedText = "";
|
|
@@ -417,25 +409,13 @@ function resolveTemplatesWithMapping(text, templates = [], templateBindings) {
|
|
|
417
409
|
}
|
|
418
410
|
let resolvedBody = fullMatch;
|
|
419
411
|
let isTemplate = false;
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
);
|
|
428
|
-
versionBody = boundVersion?.body;
|
|
429
|
-
} else {
|
|
430
|
-
const latestVersion = getLatestVersion(template);
|
|
431
|
-
versionBody = latestVersion?.body ?? template.body;
|
|
432
|
-
}
|
|
433
|
-
if (versionBody !== void 0) {
|
|
434
|
-
resolvedBody = resolveTemplates(versionBody, templates, {
|
|
435
|
-
bindings: templateBindings
|
|
436
|
-
});
|
|
437
|
-
isTemplate = true;
|
|
438
|
-
}
|
|
412
|
+
const template = templateMap.get(templateName);
|
|
413
|
+
if (template && getTemplateBody(template, templateBindings) !== void 0) {
|
|
414
|
+
resolvedBody = resolveTemplates(fullMatch, templates, {
|
|
415
|
+
bindings: templateBindings,
|
|
416
|
+
maxDepth: options?.maxDepth
|
|
417
|
+
});
|
|
418
|
+
isTemplate = true;
|
|
439
419
|
}
|
|
440
420
|
if (isTemplate) {
|
|
441
421
|
map.push({
|
|
@@ -480,9 +460,11 @@ function mapResolvedOffsetToRaw(resolvedOffset, map) {
|
|
|
480
460
|
if (inRange) {
|
|
481
461
|
if (seg.source === "raw") {
|
|
482
462
|
return seg.rawStart + (resolvedOffset - seg.resolvedStart);
|
|
483
|
-
} else {
|
|
484
|
-
return seg.rawStart;
|
|
485
463
|
}
|
|
464
|
+
if (resolvedOffset === seg.resolvedEnd) {
|
|
465
|
+
return seg.rawEnd;
|
|
466
|
+
}
|
|
467
|
+
return seg.rawStart;
|
|
486
468
|
}
|
|
487
469
|
}
|
|
488
470
|
return resolvedOffset;
|
|
@@ -495,9 +477,11 @@ function mapRawOffsetToResolved(rawOffset, map) {
|
|
|
495
477
|
if (inRange) {
|
|
496
478
|
if (seg.source === "raw") {
|
|
497
479
|
return seg.resolvedStart + (rawOffset - seg.rawStart);
|
|
498
|
-
} else {
|
|
499
|
-
return seg.resolvedStart;
|
|
500
480
|
}
|
|
481
|
+
if (rawOffset === seg.rawEnd) {
|
|
482
|
+
return seg.resolvedEnd;
|
|
483
|
+
}
|
|
484
|
+
return seg.resolvedStart;
|
|
501
485
|
}
|
|
502
486
|
}
|
|
503
487
|
return rawOffset;
|
|
@@ -5779,6 +5763,18 @@ var ImageCache = class {
|
|
|
5779
5763
|
};
|
|
5780
5764
|
img.onerror = (e) => reject(new Error(`Failed to load image from: ${src}`));
|
|
5781
5765
|
img.src = src;
|
|
5766
|
+
if (typeof navigator !== "undefined" && /jsdom/i.test(navigator.userAgent)) {
|
|
5767
|
+
setTimeout(() => {
|
|
5768
|
+
try {
|
|
5769
|
+
Object.defineProperty(img, "naturalWidth", { value: 800, configurable: true });
|
|
5770
|
+
Object.defineProperty(img, "naturalHeight", { value: 600, configurable: true });
|
|
5771
|
+
Object.defineProperty(img, "complete", { value: true, configurable: true });
|
|
5772
|
+
} catch {
|
|
5773
|
+
}
|
|
5774
|
+
this.cache.set(src, img);
|
|
5775
|
+
resolve(img);
|
|
5776
|
+
}, 10);
|
|
5777
|
+
}
|
|
5782
5778
|
});
|
|
5783
5779
|
}
|
|
5784
5780
|
set(src, img) {
|
|
@@ -6258,6 +6254,66 @@ var ImageEditorRenderer = class {
|
|
|
6258
6254
|
}
|
|
6259
6255
|
return exportCanvas;
|
|
6260
6256
|
}
|
|
6257
|
+
/**
|
|
6258
|
+
* Generates a binary mask canvas (white for mask/selected area, black for unmasked).
|
|
6259
|
+
* Useful for AI inpainting and selective generative fill.
|
|
6260
|
+
*/
|
|
6261
|
+
async renderMask(state, options) {
|
|
6262
|
+
const naturalWidth = state.imageDimensions.width;
|
|
6263
|
+
const naturalHeight = state.imageDimensions.height;
|
|
6264
|
+
const maskCanvas = this.createCanvas(naturalWidth, naturalHeight);
|
|
6265
|
+
const ctx = maskCanvas.getContext("2d");
|
|
6266
|
+
if (!ctx) return maskCanvas;
|
|
6267
|
+
ctx.fillStyle = "#000000";
|
|
6268
|
+
ctx.fillRect(0, 0, naturalWidth, naturalHeight);
|
|
6269
|
+
const useCrop = options?.useCrop ?? true;
|
|
6270
|
+
const useAnnotations = options?.useAnnotations ?? true;
|
|
6271
|
+
if (useCrop && state.crop) {
|
|
6272
|
+
ctx.fillStyle = "#ffffff";
|
|
6273
|
+
ctx.fillRect(state.crop.x, state.crop.y, state.crop.width, state.crop.height);
|
|
6274
|
+
}
|
|
6275
|
+
if (useAnnotations && state.annotations.length > 0) {
|
|
6276
|
+
for (const ann of state.annotations) {
|
|
6277
|
+
ctx.save();
|
|
6278
|
+
if (ann.rotation) {
|
|
6279
|
+
ctx.translate(ann.x, ann.y);
|
|
6280
|
+
ctx.rotate(ann.rotation * Math.PI / 180);
|
|
6281
|
+
ctx.translate(-ann.x, -ann.y);
|
|
6282
|
+
}
|
|
6283
|
+
if (ann.type === "pen") {
|
|
6284
|
+
const pen = ann;
|
|
6285
|
+
if (pen.points.length > 0) {
|
|
6286
|
+
ctx.beginPath();
|
|
6287
|
+
ctx.strokeStyle = "#ffffff";
|
|
6288
|
+
ctx.lineWidth = Math.max(pen.strokeWidth, 8);
|
|
6289
|
+
ctx.lineCap = "round";
|
|
6290
|
+
ctx.lineJoin = "round";
|
|
6291
|
+
ctx.moveTo(pen.points[0].x, pen.points[0].y);
|
|
6292
|
+
for (let i = 1; i < pen.points.length; i++) {
|
|
6293
|
+
ctx.lineTo(pen.points[i].x, pen.points[i].y);
|
|
6294
|
+
}
|
|
6295
|
+
ctx.stroke();
|
|
6296
|
+
}
|
|
6297
|
+
} else if (ann.type === "rect") {
|
|
6298
|
+
const rect = ann;
|
|
6299
|
+
ctx.fillStyle = "#ffffff";
|
|
6300
|
+
ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
|
|
6301
|
+
} else if (ann.type === "circle") {
|
|
6302
|
+
const circ = ann;
|
|
6303
|
+
ctx.fillStyle = "#ffffff";
|
|
6304
|
+
ctx.beginPath();
|
|
6305
|
+
ctx.ellipse(circ.x, circ.y, circ.radiusX, circ.radiusY, 0, 0, Math.PI * 2);
|
|
6306
|
+
ctx.fill();
|
|
6307
|
+
} else {
|
|
6308
|
+
ctx.strokeStyle = "#ffffff";
|
|
6309
|
+
ctx.fillStyle = "#ffffff";
|
|
6310
|
+
await this.drawAnnotation(ctx, ann);
|
|
6311
|
+
}
|
|
6312
|
+
ctx.restore();
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6315
|
+
return maskCanvas;
|
|
6316
|
+
}
|
|
6261
6317
|
};
|
|
6262
6318
|
|
|
6263
6319
|
// src/image-editor/controller.ts
|
|
@@ -6600,7 +6656,10 @@ var ImageEditorController = class {
|
|
|
6600
6656
|
async render(targetCanvas, options) {
|
|
6601
6657
|
const source = this.imageElement || this.state.sourceUrl;
|
|
6602
6658
|
if (!source) return;
|
|
6603
|
-
|
|
6659
|
+
try {
|
|
6660
|
+
await this.renderer.renderToCanvas(targetCanvas, source, this.state, options);
|
|
6661
|
+
} catch {
|
|
6662
|
+
}
|
|
6604
6663
|
}
|
|
6605
6664
|
async renderExport(options) {
|
|
6606
6665
|
const source = this.imageElement || this.state.sourceUrl;
|
|
@@ -6642,6 +6701,23 @@ var ImageEditorController = class {
|
|
|
6642
6701
|
}
|
|
6643
6702
|
});
|
|
6644
6703
|
}
|
|
6704
|
+
// --- AI Masking & Transformation Helpers ---
|
|
6705
|
+
async renderMask(options) {
|
|
6706
|
+
return this.renderer.renderMask(this.state, options);
|
|
6707
|
+
}
|
|
6708
|
+
async toMaskDataURL(options) {
|
|
6709
|
+
const canvas = await this.renderMask(options);
|
|
6710
|
+
return canvas.toDataURL("image/png");
|
|
6711
|
+
}
|
|
6712
|
+
async applyInpaintedImage(newDataUrl) {
|
|
6713
|
+
this.recordHistory();
|
|
6714
|
+
await this.loadImage(newDataUrl);
|
|
6715
|
+
this.clearAnnotations();
|
|
6716
|
+
}
|
|
6717
|
+
async applyBackgroundRemovedImage(newDataUrl) {
|
|
6718
|
+
this.recordHistory();
|
|
6719
|
+
await this.loadImage(newDataUrl);
|
|
6720
|
+
}
|
|
6645
6721
|
// --- Serialization ---
|
|
6646
6722
|
toJSON() {
|
|
6647
6723
|
return this.serializeState();
|
|
@@ -6933,6 +7009,8 @@ function hitTestAnnotation(imgPt, ann, padding = 10) {
|
|
|
6933
7009
|
SmilieReplacer,
|
|
6934
7010
|
SpreadsheetController,
|
|
6935
7011
|
StreamingLayoutManager,
|
|
7012
|
+
TEMPLATE_DEPTH_ERROR,
|
|
7013
|
+
TEMPLATE_LOOP_ERROR,
|
|
6936
7014
|
TEMPLATE_REGEX,
|
|
6937
7015
|
TemplateSuggestions,
|
|
6938
7016
|
VARIABLE_REGEX,
|
|
@@ -6978,6 +7056,7 @@ function hitTestAnnotation(imgPt, ann, padding = 10) {
|
|
|
6978
7056
|
getEditorText,
|
|
6979
7057
|
getLatestVersion,
|
|
6980
7058
|
getLayoutedNodes,
|
|
7059
|
+
getTemplateBody,
|
|
6981
7060
|
getViewportMetrics,
|
|
6982
7061
|
globalImageCache,
|
|
6983
7062
|
handleImageInsertion,
|