@printine/designer 0.1.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/README.md +146 -0
- package/dist/DesignerRuntimeContext.d.ts +3 -0
- package/dist/PrintineDesigner.d.ts +9 -0
- package/dist/api/client.d.ts +8 -0
- package/dist/api/client.js +82 -0
- package/dist/api/common-endpoints.d.ts +12 -0
- package/dist/api/design-endpoints.d.ts +18 -0
- package/dist/api/endpoints.d.ts +33 -0
- package/dist/api/endpoints.js +46 -0
- package/dist/api/files-endpoints.d.ts +1 -0
- package/dist/assets/icons/aspect_ratio.d.ts +3 -0
- package/dist/assets/icons/delete.d.ts +3 -0
- package/dist/assets/icons/fit_screen.d.ts +3 -0
- package/dist/assets/icons/index.d.ts +11 -0
- package/dist/assets/icons/loading_1.d.ts +3 -0
- package/dist/assets/icons/loading_2.d.ts +3 -0
- package/dist/assets/icons/loading_3.d.ts +3 -0
- package/dist/assets/icons/pan.d.ts +3 -0
- package/dist/assets/icons/setting.d.ts +3 -0
- package/dist/assets/icons/text_color.d.ts +3 -0
- package/dist/assets/icons/text_h.d.ts +3 -0
- package/dist/assets/icons/text_v.d.ts +3 -0
- package/dist/bundled-assets.d.ts +4 -0
- package/dist/components/add-design.d.ts +8 -0
- package/dist/components/assets-dialog.d.ts +21 -0
- package/dist/components/canvas-context-menu.d.ts +6 -0
- package/dist/components/color-picker/index.d.ts +10 -0
- package/dist/components/context.d.ts +24 -0
- package/dist/components/design.d.ts +9 -0
- package/dist/components/fonts.d.ts +26 -0
- package/dist/components/image-crop.d.ts +4 -0
- package/dist/components/image-edit.d.ts +1 -0
- package/dist/components/layout/aside.d.ts +3 -0
- package/dist/components/layout/bottom-nav/element-menu-sheet.d.ts +11 -0
- package/dist/components/layout/bottom-nav/element-sheet.d.ts +11 -0
- package/dist/components/layout/bottom-nav/index.d.ts +1 -0
- package/dist/components/layout/header.d.ts +5 -0
- package/dist/components/loading.d.ts +3 -0
- package/dist/components/menus/ai.d.ts +5 -0
- package/dist/components/menus/background.d.ts +6 -0
- package/dist/components/menus/clipart.d.ts +6 -0
- package/dist/components/menus/files.d.ts +7 -0
- package/dist/components/menus/image.d.ts +8 -0
- package/dist/components/menus/index.d.ts +13 -0
- package/dist/components/menus/layer.d.ts +5 -0
- package/dist/components/menus/product.d.ts +3 -0
- package/dist/components/menus/sca.d.ts +5 -0
- package/dist/components/menus/shapes.d.ts +6 -0
- package/dist/components/menus/templates.d.ts +6 -0
- package/dist/components/menus/text-effects.d.ts +5 -0
- package/dist/components/menus/text.d.ts +6 -0
- package/dist/components/placement-tab.d.ts +7 -0
- package/dist/components/preview/3d.d.ts +7 -0
- package/dist/components/preview/graphic.d.ts +7 -0
- package/dist/components/preview/index.d.ts +18 -0
- package/dist/components/preview/open.d.ts +7 -0
- package/dist/components/preview/real-time/3d.d.ts +12 -0
- package/dist/components/preview/real-time/graphic.d.ts +18 -0
- package/dist/components/preview/real-time/index.d.ts +11 -0
- package/dist/components/scale-tools.d.ts +7 -0
- package/dist/components/semi-deisgn-config.d.ts +13 -0
- package/dist/components/semi-design-link.d.ts +9 -0
- package/dist/components/store.d.ts +1 -0
- package/dist/components/toolbar.d.ts +2 -0
- package/dist/config-D2qm60gf.js +16 -0
- package/dist/contracts/api-design.d.ts +176 -0
- package/dist/contracts/design.d.ts +86 -0
- package/dist/design-7zRpRtv9.js +20331 -0
- package/dist/engine/canvas-designer.d.ts +101 -0
- package/dist/engine/canvas-designer.js +313 -0
- package/dist/engine/constants.d.ts +27 -0
- package/dist/engine/constants.js +148 -0
- package/dist/engine/editor.d.ts +186 -0
- package/dist/engine/editor.js +734 -0
- package/dist/engine/events.d.ts +34 -0
- package/dist/engine/events.js +7 -0
- package/dist/engine/extensions/curved-text.d.ts +59 -0
- package/dist/engine/fabric.d.ts +4 -0
- package/dist/engine/fabric.js +187 -0
- package/dist/engine/history.d.ts +27 -0
- package/dist/engine/history.js +56 -0
- package/dist/engine/managers/event.d.ts +101 -0
- package/dist/engine/managers/event.js +410 -0
- package/dist/engine/managers/resize.d.ts +24 -0
- package/dist/engine/managers/resize.js +63 -0
- package/dist/engine/managers/snapline.d.ts +70 -0
- package/dist/engine/managers/snapline.js +124 -0
- package/dist/engine/managers/workspace.d.ts +26 -0
- package/dist/engine/managers/workspace.js +53 -0
- package/dist/engine/processors/image.d.ts +88 -0
- package/dist/engine/processors/image.js +473 -0
- package/dist/engine/processors/template.d.ts +45 -0
- package/dist/engine/processors/template.js +314 -0
- package/dist/engine/processors/text.d.ts +74 -0
- package/dist/engine/processors/text.js +215 -0
- package/dist/engine/semi-export-editor.d.ts +199 -0
- package/dist/engine/types.d.ts +28 -0
- package/dist/engine/utils/common.d.ts +25 -0
- package/dist/engine/utils/common.js +68 -0
- package/dist/engine/utils/dialog.d.ts +25 -0
- package/dist/engine/utils/font.d.ts +5 -0
- package/dist/engine/utils/font.js +39 -0
- package/dist/engine/utils/image.d.ts +8 -0
- package/dist/engine/utils/image.js +50 -0
- package/dist/engine/utils/loading.d.ts +17 -0
- package/dist/engine/utils/loading.js +71 -0
- package/dist/engine/utils/measure.d.ts +6 -0
- package/dist/engine/utils/measure.js +6 -0
- package/dist/engine/utils/mockup.d.ts +59 -0
- package/dist/engine/utils/setting.d.ts +4 -0
- package/dist/engine/utils/setting.js +73 -0
- package/dist/fabric-types.d.ts +59 -0
- package/dist/full-designer.js +14 -0
- package/dist/hooks/pagination.d.ts +19 -0
- package/dist/hooks/use-adobe-express.d.ts +50 -0
- package/dist/hooks/use-before-unload.d.ts +1 -0
- package/dist/hooks/use-image-drop.d.ts +18 -0
- package/dist/hooks/use-oss-upload.d.ts +34 -0
- package/dist/hooks/use-screen.d.ts +1 -0
- package/dist/i18n/index.d.ts +12 -0
- package/dist/images/design/asset_empty.png +0 -0
- package/dist/images/design/design/background.svg +3 -0
- package/dist/images/design/design/color-picker.svg +15 -0
- package/dist/images/design/design/computer.svg +1 -0
- package/dist/images/design/design/copy.svg +1 -0
- package/dist/images/design/design/image.svg +10 -0
- package/dist/images/design/design/line.svg +1 -0
- package/dist/images/design/design/text.svg +1 -0
- package/dist/images/design/design/title.svg +1 -0
- package/dist/images/design/empty.png +0 -0
- package/dist/images/design/layer_empty.png +0 -0
- package/dist/images/design/menu/ai.svg +1 -0
- package/dist/images/design/menu/back.svg +4 -0
- package/dist/images/design/menu/background.svg +6 -0
- package/dist/images/design/menu/clipart.svg +6 -0
- package/dist/images/design/menu/file.svg +4 -0
- package/dist/images/design/menu/fill.svg +1 -0
- package/dist/images/design/menu/image.svg +7 -0
- package/dist/images/design/menu/layer.svg +6 -0
- package/dist/images/design/menu/product.svg +3 -0
- package/dist/images/design/menu/sca.svg +5 -0
- package/dist/images/design/menu/shapes.svg +5 -0
- package/dist/images/design/menu/templates.svg +6 -0
- package/dist/images/design/menu/text.svg +6 -0
- package/dist/images/design/menu/uploads.svg +7 -0
- package/dist/images/design/spinner.svg +3 -0
- package/dist/images/design/spinners.svg +17 -0
- package/dist/images/design/transparent_pattern.svg +5 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +127 -0
- package/dist/lib/analytics.d.ts +17 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/common.d.ts +16 -0
- package/dist/lib/config.d.ts +14 -0
- package/dist/lib/navigation.d.ts +2 -0
- package/dist/renderer/ThreeDPreview.d.ts +14 -0
- package/dist/renderer/sticker.js +1731 -0
- package/dist/renderer/three-d-preview.js +32 -0
- package/dist/state/designer-store.d.ts +43 -0
- package/dist/state/designer-store.js +85 -0
- package/dist/style.css +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/ui/accordion.d.ts +7 -0
- package/dist/ui/button-group.d.ts +11 -0
- package/dist/ui/button.d.ts +10 -0
- package/dist/ui/checkbox.d.ts +4 -0
- package/dist/ui/command.d.ts +18 -0
- package/dist/ui/confirm-dialog.d.ts +15 -0
- package/dist/ui/context-menu.d.ts +25 -0
- package/dist/ui/dialog.d.ts +15 -0
- package/dist/ui/drawer.d.ts +15 -0
- package/dist/ui/editable-combobox.d.ts +10 -0
- package/dist/ui/hint.d.ts +8 -0
- package/dist/ui/image.d.ts +24 -0
- package/dist/ui/input-group.d.ts +16 -0
- package/dist/ui/input-with-addon.d.ts +17 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/label.d.ts +4 -0
- package/dist/ui/loading-button.d.ts +15 -0
- package/dist/ui/popover.d.ts +9 -0
- package/dist/ui/scroll-area.d.ts +5 -0
- package/dist/ui/select.d.ts +22 -0
- package/dist/ui/separator.d.ts +4 -0
- package/dist/ui/shared-loading-button.d.ts +20 -0
- package/dist/ui/simple-dialog.d.ts +19 -0
- package/dist/ui/simple-popover.d.ts +13 -0
- package/dist/ui/simple-select.d.ts +20 -0
- package/dist/ui/skeleton.d.ts +2 -0
- package/dist/ui/slider.d.ts +4 -0
- package/dist/ui/spinner-box.d.ts +12 -0
- package/dist/ui/spinner.d.ts +2 -0
- package/dist/ui/switch.d.ts +6 -0
- package/dist/ui/tab/index.d.ts +15 -0
- package/dist/ui/textarea.d.ts +3 -0
- package/dist/ui/tooltip.d.ts +7 -0
- package/dist/workers/image-resize.worker.d.ts +1 -0
- package/dist/workers/mockup.worker.d.ts +5 -0
- package/dist/workers/render.worker.d.ts +1 -0
- package/package.json +201 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { fabric } from 'fabric';
|
|
2
|
+
import '../fabric-types';
|
|
3
|
+
import type { Mockup, TemplateBaseInfo } from '../contracts/api-design';
|
|
4
|
+
import type { FontStyle } from '../contracts/design';
|
|
5
|
+
export type CanvasDesignState = Record<string, unknown> & {
|
|
6
|
+
objects?: unknown[];
|
|
7
|
+
background?: string;
|
|
8
|
+
};
|
|
9
|
+
export interface CanvasDesignerOptions {
|
|
10
|
+
canvas: HTMLCanvasElement;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
overlayScale?: number;
|
|
14
|
+
onChange?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export interface PlacementPreviewOptions {
|
|
17
|
+
placements: Mockup[];
|
|
18
|
+
designData: Record<string, CanvasDesignState>;
|
|
19
|
+
backgroundColor?: string;
|
|
20
|
+
width?: number;
|
|
21
|
+
height?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Framework-independent Fabric runtime used by `PrintineDesigner`.
|
|
25
|
+
*
|
|
26
|
+
* It deliberately stores the same Fabric JSON shape that the existing
|
|
27
|
+
* `products/design-save` endpoint already receives, so a host never needs to
|
|
28
|
+
* translate editor data before saving it.
|
|
29
|
+
*/
|
|
30
|
+
export declare class CanvasDesigner {
|
|
31
|
+
readonly canvas: fabric.Canvas;
|
|
32
|
+
private readonly onChange?;
|
|
33
|
+
private readonly overlayScale;
|
|
34
|
+
private placement?;
|
|
35
|
+
private placementStates;
|
|
36
|
+
private history;
|
|
37
|
+
private future;
|
|
38
|
+
private isRestoring;
|
|
39
|
+
private cropTarget?;
|
|
40
|
+
private cropRect?;
|
|
41
|
+
constructor({ canvas, width, height, overlayScale, onChange }: CanvasDesignerOptions);
|
|
42
|
+
get activeObject(): fabric.Object | null;
|
|
43
|
+
get currentPlacement(): Mockup | undefined;
|
|
44
|
+
get isCropping(): boolean;
|
|
45
|
+
resize(width: number, height: number): void;
|
|
46
|
+
switchPlacement(placement: Mockup, color?: string, state?: CanvasDesignState): Promise<void>;
|
|
47
|
+
setBackground(color: string): Promise<void>;
|
|
48
|
+
addText(config?: {
|
|
49
|
+
text?: string;
|
|
50
|
+
fontFamily?: string;
|
|
51
|
+
fontSize?: number;
|
|
52
|
+
fill?: string;
|
|
53
|
+
fontPath?: string;
|
|
54
|
+
fontWeight?: number;
|
|
55
|
+
fontStyle?: FontStyle;
|
|
56
|
+
}): Promise<fabric.AdvancedIText>;
|
|
57
|
+
addImage(url: string, name?: string): Promise<fabric.Image>;
|
|
58
|
+
addSvg(url: string, name?: string): Promise<fabric.Group>;
|
|
59
|
+
addFile(file: File): Promise<fabric.Image | fabric.Group>;
|
|
60
|
+
/** Adds a saved Printine template without converting its existing JSON contract. */
|
|
61
|
+
addTemplate(template: TemplateBaseInfo): Promise<void>;
|
|
62
|
+
deleteActive(): void;
|
|
63
|
+
/** Starts a non-destructive Fabric clip-path crop for the selected bitmap image. */
|
|
64
|
+
beginCrop(): boolean;
|
|
65
|
+
applyCrop(): boolean;
|
|
66
|
+
cancelCrop(): boolean;
|
|
67
|
+
duplicateActive(): void;
|
|
68
|
+
bringForward(): void;
|
|
69
|
+
sendBackwards(): void;
|
|
70
|
+
setActiveFill(fill: string): void;
|
|
71
|
+
setActiveTextStyle(config: {
|
|
72
|
+
fontFamily: string;
|
|
73
|
+
fontPath?: string;
|
|
74
|
+
fontWeight?: number;
|
|
75
|
+
fontStyle?: FontStyle;
|
|
76
|
+
}): Promise<boolean>;
|
|
77
|
+
setActiveTextCurve(radius: number, spacing?: number): boolean;
|
|
78
|
+
getDesignData(): {
|
|
79
|
+
[k: string]: CanvasDesignState;
|
|
80
|
+
};
|
|
81
|
+
setDesignData(data: Record<string, CanvasDesignState>): void;
|
|
82
|
+
exportPreview(): string;
|
|
83
|
+
undo(): Promise<void>;
|
|
84
|
+
redo(): Promise<void>;
|
|
85
|
+
destroy(): void;
|
|
86
|
+
private renderOverlay;
|
|
87
|
+
private placeImage;
|
|
88
|
+
private persistCurrentPlacement;
|
|
89
|
+
private readState;
|
|
90
|
+
private serializeCanvas;
|
|
91
|
+
private recordChange;
|
|
92
|
+
private restoreSerialized;
|
|
93
|
+
private loadState;
|
|
94
|
+
private removeCropRect;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Renders every printable placement in an offscreen Fabric canvas. The result
|
|
98
|
+
* is keyed by both placement name and id so it can feed existing 2D and 3D
|
|
99
|
+
* render area contracts without a host-side translation layer.
|
|
100
|
+
*/
|
|
101
|
+
export declare function renderPlacementPreviews({ placements, designData, backgroundColor, width, height, }: PlacementPreviewOptions): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { fabric as h } from "fabric";
|
|
2
|
+
import { loadImage as d, loadSvgImage as f, loadOverlaySvgImage as p } from "./utils/image.js";
|
|
3
|
+
import { setDefaultControls as m } from "./utils/setting.js";
|
|
4
|
+
import { loadFontface as u } from "./utils/font.js";
|
|
5
|
+
class y {
|
|
6
|
+
constructor({ canvas: t, width: e, height: s, overlayScale: i = 0.85, onChange: n }) {
|
|
7
|
+
this.placementStates = /* @__PURE__ */ new Map(), this.history = [], this.future = [], this.isRestoring = !1, m(), this.canvas = new h.Canvas(t, {
|
|
8
|
+
enableRetinaScaling: !0,
|
|
9
|
+
width: e,
|
|
10
|
+
height: s,
|
|
11
|
+
preserveObjectStacking: !0,
|
|
12
|
+
centeredRotation: !0,
|
|
13
|
+
hoverCursor: "grab",
|
|
14
|
+
moveCursor: "grabbing",
|
|
15
|
+
selection: !0,
|
|
16
|
+
controlsAboveOverlay: !0,
|
|
17
|
+
fireRightClick: !0
|
|
18
|
+
}), this.onChange = n, this.overlayScale = i;
|
|
19
|
+
const a = () => this.recordChange();
|
|
20
|
+
this.canvas.on("object:added", a), this.canvas.on("object:modified", a), this.canvas.on("object:removed", a), this.canvas.on("text:changed", a), this.recordChange();
|
|
21
|
+
}
|
|
22
|
+
get activeObject() {
|
|
23
|
+
return this.canvas.getActiveObject();
|
|
24
|
+
}
|
|
25
|
+
get currentPlacement() {
|
|
26
|
+
return this.placement;
|
|
27
|
+
}
|
|
28
|
+
get isCropping() {
|
|
29
|
+
return !!this.cropRect;
|
|
30
|
+
}
|
|
31
|
+
resize(t, e) {
|
|
32
|
+
this.canvas.setDimensions({ width: t, height: e }), this.placement && this.renderOverlay(this.placement);
|
|
33
|
+
}
|
|
34
|
+
async switchPlacement(t, e = "", s) {
|
|
35
|
+
this.cropRect && this.applyCrop(), this.persistCurrentPlacement(), this.placement = t, this.isRestoring = !0, this.canvas.clear(), await this.setBackground(e), await this.renderOverlay(t);
|
|
36
|
+
const i = s ?? this.placementStates.get(t.name);
|
|
37
|
+
i && await this.loadState(i, !1), this.history = [this.serializeCanvas()], this.future = [], this.isRestoring = !1, this.onChange?.();
|
|
38
|
+
}
|
|
39
|
+
async setBackground(t) {
|
|
40
|
+
await new Promise((e) => this.canvas.setBackgroundColor(t || "transparent", () => e())), this.canvas.requestRenderAll();
|
|
41
|
+
}
|
|
42
|
+
async addText(t = {}) {
|
|
43
|
+
t.fontPath && t.fontFamily && await u({
|
|
44
|
+
family: t.fontFamily,
|
|
45
|
+
url: t.fontPath,
|
|
46
|
+
weight: t.fontWeight || 400,
|
|
47
|
+
style: t.fontStyle || "normal"
|
|
48
|
+
});
|
|
49
|
+
const e = new h.AdvancedIText(t.text || "Entry Text", {
|
|
50
|
+
left: this.canvas.getWidth() / 2,
|
|
51
|
+
top: this.canvas.getHeight() / 2,
|
|
52
|
+
originX: "center",
|
|
53
|
+
originY: "center",
|
|
54
|
+
fontFamily: t.fontFamily || "Arial",
|
|
55
|
+
fontWeight: t.fontWeight || 400,
|
|
56
|
+
fontStyle: t.fontStyle || "normal",
|
|
57
|
+
fontPath: t.fontPath || "",
|
|
58
|
+
fontSize: t.fontSize || 32,
|
|
59
|
+
fill: t.fill || "#111827",
|
|
60
|
+
editable: !0
|
|
61
|
+
});
|
|
62
|
+
return this.canvas.add(e), this.canvas.setActiveObject(e), this.canvas.requestRenderAll(), e.enterEditing().selectAll(), e;
|
|
63
|
+
}
|
|
64
|
+
async addImage(t, e) {
|
|
65
|
+
const s = await d(t);
|
|
66
|
+
return this.placeImage(s, t, e), s;
|
|
67
|
+
}
|
|
68
|
+
async addSvg(t, e) {
|
|
69
|
+
const s = await f(t);
|
|
70
|
+
return this.placeImage(s, t, e), s;
|
|
71
|
+
}
|
|
72
|
+
async addFile(t) {
|
|
73
|
+
const e = await new Promise((s, i) => {
|
|
74
|
+
const n = new FileReader();
|
|
75
|
+
n.onload = () => s(String(n.result)), n.onerror = () => i(n.error || new Error("Unable to read image file")), n.readAsDataURL(t);
|
|
76
|
+
});
|
|
77
|
+
return t.type === "image/svg+xml" || t.name.toLowerCase().endsWith(".svg") ? this.addSvg(e, t.name) : this.addImage(e, t.name);
|
|
78
|
+
}
|
|
79
|
+
/** Adds a saved Printine template without converting its existing JSON contract. */
|
|
80
|
+
async addTemplate(t) {
|
|
81
|
+
if (!t.areaWidth || !t.areaHeight) return;
|
|
82
|
+
const e = Math.min(
|
|
83
|
+
1,
|
|
84
|
+
this.canvas.getWidth() * 0.7 / t.areaWidth,
|
|
85
|
+
this.canvas.getHeight() * 0.7 / t.areaHeight
|
|
86
|
+
), s = (this.canvas.getWidth() - t.areaWidth * e) / 2, i = (this.canvas.getHeight() - t.areaHeight * e) / 2, n = [];
|
|
87
|
+
for (const a of t.elements) {
|
|
88
|
+
const r = a.position;
|
|
89
|
+
if (a.text) {
|
|
90
|
+
const l = await this.addText({
|
|
91
|
+
text: a.text.text,
|
|
92
|
+
fontFamily: a.text.fontFamily,
|
|
93
|
+
fontPath: a.text.fontPath,
|
|
94
|
+
fontWeight: typeof a.text.fontWeight == "number" ? a.text.fontWeight : Number(a.text.fontWeight) || 400,
|
|
95
|
+
fontStyle: a.text.fontStyle,
|
|
96
|
+
fontSize: Math.max(8, a.text.fontSize * e),
|
|
97
|
+
fill: a.text.color
|
|
98
|
+
});
|
|
99
|
+
l.set({
|
|
100
|
+
left: s + r.left * e,
|
|
101
|
+
top: i + r.top * e,
|
|
102
|
+
originX: "left",
|
|
103
|
+
originY: "top",
|
|
104
|
+
angle: r.rotation || 0,
|
|
105
|
+
scaleX: e,
|
|
106
|
+
scaleY: e
|
|
107
|
+
}), n.push(l);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!a.image?.url) continue;
|
|
111
|
+
const c = a.image.url, o = c.toLowerCase().includes(".svg") || c.startsWith("data:image/svg") ? await f(c) : await d(c);
|
|
112
|
+
o.set({
|
|
113
|
+
left: s + r.left * e,
|
|
114
|
+
top: i + r.top * e,
|
|
115
|
+
originX: "left",
|
|
116
|
+
originY: "top",
|
|
117
|
+
angle: r.rotation || 0,
|
|
118
|
+
scaleX: e,
|
|
119
|
+
scaleY: e,
|
|
120
|
+
flipX: a.image.flipX || !1,
|
|
121
|
+
flipY: a.image.flipY || !1,
|
|
122
|
+
originSrc: c
|
|
123
|
+
}), this.canvas.add(o), n.push(o);
|
|
124
|
+
}
|
|
125
|
+
n.length > 1 ? this.canvas.setActiveObject(new h.ActiveSelection(n, { canvas: this.canvas })) : n[0] && this.canvas.setActiveObject(n[0]), this.canvas.requestRenderAll();
|
|
126
|
+
}
|
|
127
|
+
deleteActive() {
|
|
128
|
+
const t = this.canvas.getActiveObjects();
|
|
129
|
+
t.length && (t.forEach((e) => this.canvas.remove(e)), this.canvas.discardActiveObject(), this.canvas.requestRenderAll());
|
|
130
|
+
}
|
|
131
|
+
/** Starts a non-destructive Fabric clip-path crop for the selected bitmap image. */
|
|
132
|
+
beginCrop() {
|
|
133
|
+
const t = this.canvas.getActiveObject();
|
|
134
|
+
if (!t || t.type !== "image" || this.cropRect) return !1;
|
|
135
|
+
const e = t, s = e.getBoundingRect(!0, !0), i = new h.Rect({
|
|
136
|
+
left: s.left,
|
|
137
|
+
top: s.top,
|
|
138
|
+
width: s.width,
|
|
139
|
+
height: s.height,
|
|
140
|
+
fill: "rgba(53, 64, 165, 0.08)",
|
|
141
|
+
stroke: "#3540a5",
|
|
142
|
+
strokeWidth: 2,
|
|
143
|
+
strokeDashArray: [6, 4],
|
|
144
|
+
originX: "left",
|
|
145
|
+
originY: "top",
|
|
146
|
+
lockRotation: !0,
|
|
147
|
+
name: "__printine_crop__",
|
|
148
|
+
excludeFromExport: !0
|
|
149
|
+
});
|
|
150
|
+
return e.set({ selectable: !1, evented: !1 }), this.cropTarget = e, this.cropRect = i, this.canvas.add(i), this.canvas.setActiveObject(i), this.canvas.requestRenderAll(), !0;
|
|
151
|
+
}
|
|
152
|
+
applyCrop() {
|
|
153
|
+
const t = this.cropTarget, e = this.cropRect;
|
|
154
|
+
if (!t || !e) return !1;
|
|
155
|
+
const s = new h.Rect({
|
|
156
|
+
left: e.left,
|
|
157
|
+
top: e.top,
|
|
158
|
+
width: e.width,
|
|
159
|
+
height: e.height,
|
|
160
|
+
scaleX: e.scaleX,
|
|
161
|
+
scaleY: e.scaleY,
|
|
162
|
+
angle: e.angle,
|
|
163
|
+
originX: e.originX,
|
|
164
|
+
originY: e.originY,
|
|
165
|
+
selectable: !1,
|
|
166
|
+
evented: !1,
|
|
167
|
+
fill: "#000",
|
|
168
|
+
absolutePositioned: !0
|
|
169
|
+
});
|
|
170
|
+
return t.set({ clipPath: s, selectable: !0, evented: !0 }), this.removeCropRect(), this.canvas.setActiveObject(t), this.canvas.requestRenderAll(), this.recordChange(), !0;
|
|
171
|
+
}
|
|
172
|
+
cancelCrop() {
|
|
173
|
+
const t = this.cropTarget;
|
|
174
|
+
return !this.cropRect || !t ? !1 : (t.set({ selectable: !0, evented: !0 }), this.removeCropRect(), this.canvas.setActiveObject(t), this.canvas.requestRenderAll(), !0);
|
|
175
|
+
}
|
|
176
|
+
duplicateActive() {
|
|
177
|
+
const t = this.canvas.getActiveObject();
|
|
178
|
+
t && t.clone((e) => {
|
|
179
|
+
e.set({ left: (e.left || 0) + 16, top: (e.top || 0) + 16 }), this.canvas.add(e), this.canvas.setActiveObject(e), this.canvas.requestRenderAll();
|
|
180
|
+
}, ["id", "originSrc", "fontPath", "radius", "spacing"]);
|
|
181
|
+
}
|
|
182
|
+
bringForward() {
|
|
183
|
+
const t = this.canvas.getActiveObject();
|
|
184
|
+
t && this.canvas.bringForward(t), this.canvas.requestRenderAll();
|
|
185
|
+
}
|
|
186
|
+
sendBackwards() {
|
|
187
|
+
const t = this.canvas.getActiveObject();
|
|
188
|
+
t && this.canvas.sendBackwards(t), this.canvas.requestRenderAll();
|
|
189
|
+
}
|
|
190
|
+
setActiveFill(t) {
|
|
191
|
+
const e = this.canvas.getActiveObject();
|
|
192
|
+
e && (e.set("fill", t), this.canvas.requestRenderAll(), this.recordChange());
|
|
193
|
+
}
|
|
194
|
+
async setActiveTextStyle(t) {
|
|
195
|
+
const e = this.canvas.getActiveObject();
|
|
196
|
+
return !e || !e.type?.includes("text") ? !1 : (t.fontPath && await u({
|
|
197
|
+
family: t.fontFamily,
|
|
198
|
+
url: t.fontPath,
|
|
199
|
+
weight: t.fontWeight || 400,
|
|
200
|
+
style: t.fontStyle || "normal"
|
|
201
|
+
}), e.set({
|
|
202
|
+
fontFamily: t.fontFamily,
|
|
203
|
+
fontPath: t.fontPath || "",
|
|
204
|
+
fontWeight: t.fontWeight || 400,
|
|
205
|
+
fontStyle: t.fontStyle || "normal"
|
|
206
|
+
}), this.canvas.requestRenderAll(), this.recordChange(), !0);
|
|
207
|
+
}
|
|
208
|
+
setActiveTextCurve(t, e = 0) {
|
|
209
|
+
const s = this.canvas.getActiveObject();
|
|
210
|
+
return !s || s.type !== "advanced-i-text" ? !1 : (s.set({ radius: t, spacing: e }), s.setCoords(), this.canvas.requestRenderAll(), this.recordChange(), !0);
|
|
211
|
+
}
|
|
212
|
+
getDesignData() {
|
|
213
|
+
return this.cropRect && this.applyCrop(), this.persistCurrentPlacement(), Object.fromEntries(this.placementStates.entries());
|
|
214
|
+
}
|
|
215
|
+
setDesignData(t) {
|
|
216
|
+
this.placementStates = new Map(Object.entries(t));
|
|
217
|
+
}
|
|
218
|
+
exportPreview() {
|
|
219
|
+
return this.canvas.toDataURL({ format: "png", multiplier: 2, enableRetinaScaling: !0 });
|
|
220
|
+
}
|
|
221
|
+
async undo() {
|
|
222
|
+
if (this.history.length < 2) return;
|
|
223
|
+
const t = this.history.pop();
|
|
224
|
+
t && this.future.push(t);
|
|
225
|
+
const e = this.history[this.history.length - 1];
|
|
226
|
+
e && await this.restoreSerialized(e);
|
|
227
|
+
}
|
|
228
|
+
async redo() {
|
|
229
|
+
const t = this.future.pop();
|
|
230
|
+
t && (this.history.push(t), await this.restoreSerialized(t));
|
|
231
|
+
}
|
|
232
|
+
destroy() {
|
|
233
|
+
this.cancelCrop(), this.placementStates.clear(), this.history = [], this.future = [], this.canvas.dispose();
|
|
234
|
+
}
|
|
235
|
+
async renderOverlay(t) {
|
|
236
|
+
const { image: e } = await p(t.image), s = Math.min(this.canvas.getWidth(), this.canvas.getHeight()) * this.overlayScale, i = Math.min(s / (e.width || 1), s / (e.height || 1));
|
|
237
|
+
e.set({
|
|
238
|
+
scaleX: i,
|
|
239
|
+
scaleY: i,
|
|
240
|
+
left: (this.canvas.getWidth() - (e.width || 0) * i) / 2,
|
|
241
|
+
top: (this.canvas.getHeight() - (e.height || 0) * i) / 2,
|
|
242
|
+
selectable: !1,
|
|
243
|
+
evented: !1
|
|
244
|
+
}), await new Promise((n) => this.canvas.setOverlayImage(e, () => n())), this.canvas.requestRenderAll();
|
|
245
|
+
}
|
|
246
|
+
placeImage(t, e, s) {
|
|
247
|
+
const i = Math.min(this.canvas.getWidth(), this.canvas.getHeight()) * 0.55, n = t.width || i, a = t.height || i, r = Math.min(1, i / Math.max(n, a));
|
|
248
|
+
t.set({
|
|
249
|
+
left: this.canvas.getWidth() / 2,
|
|
250
|
+
top: this.canvas.getHeight() / 2,
|
|
251
|
+
originX: "center",
|
|
252
|
+
originY: "center",
|
|
253
|
+
scaleX: r,
|
|
254
|
+
scaleY: r,
|
|
255
|
+
name: s || e.split("/").pop() || "image",
|
|
256
|
+
originSrc: e
|
|
257
|
+
}), this.canvas.add(t), this.canvas.setActiveObject(t), this.canvas.requestRenderAll();
|
|
258
|
+
}
|
|
259
|
+
persistCurrentPlacement() {
|
|
260
|
+
this.placement && this.placementStates.set(this.placement.name, this.readState());
|
|
261
|
+
}
|
|
262
|
+
readState() {
|
|
263
|
+
return {
|
|
264
|
+
...this.canvas.toJSON(["id", "name", "originSrc", "fontPath", "radius", "spacing"]),
|
|
265
|
+
color: typeof this.canvas.backgroundColor == "string" ? this.canvas.backgroundColor : ""
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
serializeCanvas() {
|
|
269
|
+
return JSON.stringify(this.readState());
|
|
270
|
+
}
|
|
271
|
+
recordChange() {
|
|
272
|
+
if (this.isRestoring || this.cropRect) return;
|
|
273
|
+
const t = this.serializeCanvas();
|
|
274
|
+
this.history[this.history.length - 1] !== t && (this.history.push(t), this.history.length > 50 && this.history.shift(), this.future = []), this.persistCurrentPlacement(), this.onChange?.();
|
|
275
|
+
}
|
|
276
|
+
async restoreSerialized(t) {
|
|
277
|
+
await this.loadState(JSON.parse(t), !0), this.persistCurrentPlacement(), this.onChange?.();
|
|
278
|
+
}
|
|
279
|
+
async loadState(t, e) {
|
|
280
|
+
this.isRestoring = !0;
|
|
281
|
+
const s = e ? this.canvas.overlayImage : void 0;
|
|
282
|
+
await new Promise((i) => this.canvas.loadFromJSON(t, () => i())), s && this.canvas.setOverlayImage(s, () => {
|
|
283
|
+
}), await this.setBackground(typeof t.color == "string" ? t.color : ""), this.canvas.requestRenderAll(), this.isRestoring = !1;
|
|
284
|
+
}
|
|
285
|
+
removeCropRect() {
|
|
286
|
+
this.cropRect && this.canvas.remove(this.cropRect), this.cropRect = void 0, this.cropTarget = void 0;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function A({
|
|
290
|
+
placements: v,
|
|
291
|
+
designData: t,
|
|
292
|
+
backgroundColor: e = "",
|
|
293
|
+
width: s = 900,
|
|
294
|
+
height: i = 900
|
|
295
|
+
}) {
|
|
296
|
+
const n = document.createElement("canvas"), a = new y({ canvas: n, width: s, height: i, overlayScale: 0.85 }), r = {};
|
|
297
|
+
try {
|
|
298
|
+
a.setDesignData(t);
|
|
299
|
+
for (const c of v) {
|
|
300
|
+
const o = t[c.name], l = typeof o?.color == "string" ? o.color : e;
|
|
301
|
+
await a.switchPlacement(c, l, o);
|
|
302
|
+
const g = a.exportPreview();
|
|
303
|
+
r[c.name] = g, r[String(c.id)] = g;
|
|
304
|
+
}
|
|
305
|
+
return r;
|
|
306
|
+
} finally {
|
|
307
|
+
a.destroy();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
export {
|
|
311
|
+
y as CanvasDesigner,
|
|
312
|
+
A as renderPlacementPreviews
|
|
313
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DesignerElementType } from './types';
|
|
2
|
+
import { BLEND_MODES } from 'pixi.js';
|
|
3
|
+
/** Fabric helper objects that must never be exposed as editable design layers. */
|
|
4
|
+
export declare const LAYER_BLACK_LIST: string[];
|
|
5
|
+
/** Text sizes offered by the toolbar, expressed as a fraction of the print area. */
|
|
6
|
+
export declare const DEFAULT_FONT_SIZE: number[];
|
|
7
|
+
export declare const ALIGN_TYPES: ('left' | 'center' | 'right')[];
|
|
8
|
+
/** Human labels for the font weight/style variants returned by the fonts endpoint. */
|
|
9
|
+
export declare const FONT_WEIGHT: Record<string, string>;
|
|
10
|
+
export declare const DEFAULT_FILL_COLOR_LIST: string[];
|
|
11
|
+
/** Pixi blend modes accepted by mockup render-area configuration. */
|
|
12
|
+
export declare const BLEND_MODES_MAP: {
|
|
13
|
+
normal: BLEND_MODES;
|
|
14
|
+
multiply: BLEND_MODES;
|
|
15
|
+
screen: BLEND_MODES;
|
|
16
|
+
overlay: BLEND_MODES;
|
|
17
|
+
'soft-light': BLEND_MODES;
|
|
18
|
+
'hard-light': BLEND_MODES;
|
|
19
|
+
'color-dodge': BLEND_MODES;
|
|
20
|
+
'color-burn': BLEND_MODES;
|
|
21
|
+
darken: BLEND_MODES;
|
|
22
|
+
lighten: BLEND_MODES;
|
|
23
|
+
difference: BLEND_MODES;
|
|
24
|
+
exclusion: BLEND_MODES;
|
|
25
|
+
};
|
|
26
|
+
/** Panel titles for each editor tool. */
|
|
27
|
+
export declare const ELEMENT_TITLE_MAP: Record<DesignerElementType, string>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { BLEND_MODES as E } from "pixi.js";
|
|
2
|
+
const t = ["cropRect", "cropOverlay", "workspace", "loading", "bg"], i = [0.01, 0.02, 0.03, 0.04, 0.05, 0.07, 0.09, 0.1, 0.12], a = ["left", "center", "right"], l = {
|
|
3
|
+
100: "Thin",
|
|
4
|
+
200: "Extra Light",
|
|
5
|
+
300: "Light",
|
|
6
|
+
400: "Regular",
|
|
7
|
+
500: "Medium",
|
|
8
|
+
600: "Semi Bold",
|
|
9
|
+
700: "Bold",
|
|
10
|
+
800: "Extra Bold",
|
|
11
|
+
900: "Black",
|
|
12
|
+
"100italic": "Thin Italic",
|
|
13
|
+
"200italic": "Extra Light Italic",
|
|
14
|
+
"300italic": "Light Italic",
|
|
15
|
+
"400italic": "Italic",
|
|
16
|
+
"500italic": "Medium Italic",
|
|
17
|
+
"600italic": "Semi Bold Italic",
|
|
18
|
+
"700italic": "Bold Italic",
|
|
19
|
+
"800italic": "Extra Bold Italic",
|
|
20
|
+
"900italic": "Black Italic"
|
|
21
|
+
}, B = [
|
|
22
|
+
"#000000",
|
|
23
|
+
"#FFFFFF",
|
|
24
|
+
"#FAFAFA",
|
|
25
|
+
"#F5F5F5",
|
|
26
|
+
"#EEEEEE",
|
|
27
|
+
"#E0E0E0",
|
|
28
|
+
"#BDBDBD",
|
|
29
|
+
"#9E9E9E",
|
|
30
|
+
"#757575",
|
|
31
|
+
"#616161",
|
|
32
|
+
"#424242",
|
|
33
|
+
"#FFEbEE",
|
|
34
|
+
"#FFCDD2",
|
|
35
|
+
"#EF9A9A",
|
|
36
|
+
"#E57373",
|
|
37
|
+
"#EF5350",
|
|
38
|
+
"#F44336",
|
|
39
|
+
"#E53935",
|
|
40
|
+
"#D32F2F",
|
|
41
|
+
"#C62828",
|
|
42
|
+
"#B71C1C",
|
|
43
|
+
"#FCE4EC",
|
|
44
|
+
"#F8BBD9",
|
|
45
|
+
"#F48FB1",
|
|
46
|
+
"#F06292",
|
|
47
|
+
"#EC407A",
|
|
48
|
+
"#E91E63",
|
|
49
|
+
"#D81B60",
|
|
50
|
+
"#C2185B",
|
|
51
|
+
"#AD1457",
|
|
52
|
+
"#880E4F",
|
|
53
|
+
"#FFF3E0",
|
|
54
|
+
"#FFE0B2",
|
|
55
|
+
"#FFCC80",
|
|
56
|
+
"#FFB74D",
|
|
57
|
+
"#FFA726",
|
|
58
|
+
"#FF9800",
|
|
59
|
+
"#FB8C00",
|
|
60
|
+
"#F57C00",
|
|
61
|
+
"#EF6C00",
|
|
62
|
+
"#E65100",
|
|
63
|
+
"#EFEBE9",
|
|
64
|
+
"#D7CCC8",
|
|
65
|
+
"#BCAAA4",
|
|
66
|
+
"#A1887F",
|
|
67
|
+
"#8D6E63",
|
|
68
|
+
"#795548",
|
|
69
|
+
"#6D4C41",
|
|
70
|
+
"#5D4037",
|
|
71
|
+
"#4E342E",
|
|
72
|
+
"#3E2723",
|
|
73
|
+
"#E8F5E8",
|
|
74
|
+
"#C8E6C9",
|
|
75
|
+
"#A5D6A7",
|
|
76
|
+
"#81C784",
|
|
77
|
+
"#66BB6A",
|
|
78
|
+
"#4CAF50",
|
|
79
|
+
"#43A047",
|
|
80
|
+
"#388E3C",
|
|
81
|
+
"#2E7D32",
|
|
82
|
+
"#1B5E20",
|
|
83
|
+
"#E0F2F1",
|
|
84
|
+
"#B2DFDB",
|
|
85
|
+
"#80CBC4",
|
|
86
|
+
"#4DB6AC",
|
|
87
|
+
"#26A69A",
|
|
88
|
+
"#009688",
|
|
89
|
+
"#00897B",
|
|
90
|
+
"#00796B",
|
|
91
|
+
"#00695C",
|
|
92
|
+
"#004D40",
|
|
93
|
+
"#E3F2FD",
|
|
94
|
+
"#BBDEFB",
|
|
95
|
+
"#90CAF9",
|
|
96
|
+
"#64B5F6",
|
|
97
|
+
"#42A5F5",
|
|
98
|
+
"#2196F3",
|
|
99
|
+
"#1E88E5",
|
|
100
|
+
"#1976D2",
|
|
101
|
+
"#1565C0",
|
|
102
|
+
"#0D47A1",
|
|
103
|
+
"#F3E5F5",
|
|
104
|
+
"#E1BEE7",
|
|
105
|
+
"#CE93D8",
|
|
106
|
+
"#BA68C8",
|
|
107
|
+
"#AB47BC",
|
|
108
|
+
"#9C27B0",
|
|
109
|
+
"#8E24AA",
|
|
110
|
+
"#7B1FA2",
|
|
111
|
+
"#6A1B9A",
|
|
112
|
+
"#4A148C"
|
|
113
|
+
], c = {
|
|
114
|
+
normal: E.NORMAL,
|
|
115
|
+
multiply: E.MULTIPLY,
|
|
116
|
+
screen: E.SCREEN,
|
|
117
|
+
overlay: E.OVERLAY,
|
|
118
|
+
"soft-light": E.SOFT_LIGHT,
|
|
119
|
+
"hard-light": E.HARD_LIGHT,
|
|
120
|
+
"color-dodge": E.COLOR_DODGE,
|
|
121
|
+
"color-burn": E.COLOR_BURN,
|
|
122
|
+
darken: E.DARKEN,
|
|
123
|
+
lighten: E.LIGHTEN,
|
|
124
|
+
difference: E.DIFFERENCE,
|
|
125
|
+
exclusion: E.EXCLUSION
|
|
126
|
+
}, e = {
|
|
127
|
+
product: "Product information",
|
|
128
|
+
shapes: "Shapes",
|
|
129
|
+
images: "Upload images",
|
|
130
|
+
text: "Text",
|
|
131
|
+
textEffects: "Text effects",
|
|
132
|
+
layer: "Layers",
|
|
133
|
+
templates: "Designs",
|
|
134
|
+
clipart: "Clipart",
|
|
135
|
+
ai: "AI image generator",
|
|
136
|
+
files: "My files",
|
|
137
|
+
background: "Background color",
|
|
138
|
+
sca: "Custom"
|
|
139
|
+
};
|
|
140
|
+
export {
|
|
141
|
+
a as ALIGN_TYPES,
|
|
142
|
+
c as BLEND_MODES_MAP,
|
|
143
|
+
B as DEFAULT_FILL_COLOR_LIST,
|
|
144
|
+
i as DEFAULT_FONT_SIZE,
|
|
145
|
+
e as ELEMENT_TITLE_MAP,
|
|
146
|
+
l as FONT_WEIGHT,
|
|
147
|
+
t as LAYER_BLACK_LIST
|
|
148
|
+
};
|