vibrant-tool 0.1.9 → 0.1.10
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/lib/hooks/useKeyboardEvents.d.ts +1 -1
- package/dist/lib/services/crop-image.service.d.ts +1 -0
- package/dist/lib/utils/background-utils.d.ts +2 -1
- package/dist/lib/utils/grid-manager.d.ts +4 -0
- package/dist/modules/icons/gridicon/index.d.ts +4 -0
- package/dist/modules/toolbar/text-toolbar/index.d.ts +4 -0
- package/dist/vibrant-tool.css +19 -11
- package/dist/vibrant-tool.es.js +705 -219
- package/dist/vibrant-tool.umd.js +705 -219
- package/dist/zustand/editorStore.d.ts +3 -0
- package/package.json +1 -1
package/dist/vibrant-tool.es.js
CHANGED
|
@@ -1123,11 +1123,25 @@ const useEditorStore = create((set, get) => ({
|
|
|
1123
1123
|
back: null
|
|
1124
1124
|
},
|
|
1125
1125
|
templateData: null,
|
|
1126
|
+
// Grid state
|
|
1127
|
+
showGrid: false,
|
|
1128
|
+
setShowGrid: (showGrid) => set({ showGrid }),
|
|
1129
|
+
toggleGrid: () => set((state) => ({ showGrid: !state.showGrid })),
|
|
1126
1130
|
history: [],
|
|
1127
1131
|
historyIndex: -1,
|
|
1128
1132
|
// Crop state
|
|
1129
1133
|
isCropping: false,
|
|
1130
|
-
startCropping: () =>
|
|
1134
|
+
startCropping: () => {
|
|
1135
|
+
const canvas2 = get().canvas;
|
|
1136
|
+
if (canvas2 && canvas2.isDrawingMode) {
|
|
1137
|
+
canvas2.isDrawingMode = false;
|
|
1138
|
+
canvas2.selection = true;
|
|
1139
|
+
canvas2.defaultCursor = "default";
|
|
1140
|
+
canvas2._isCurrentlyDrawing = false;
|
|
1141
|
+
canvas2.requestRenderAll();
|
|
1142
|
+
}
|
|
1143
|
+
set({ isCropping: true });
|
|
1144
|
+
},
|
|
1131
1145
|
stopCropping: () => set({ isCropping: false }),
|
|
1132
1146
|
// Canvas setter (NO history here)
|
|
1133
1147
|
setCanvas: (canvas2) => {
|
|
@@ -8442,6 +8456,7 @@ function createShapeCornerOverlays(shape, bounds, pageSide = "front", overlayCol
|
|
|
8442
8456
|
originX: "left",
|
|
8443
8457
|
originY: "top",
|
|
8444
8458
|
fill: overlayColor,
|
|
8459
|
+
opacity: 0.6,
|
|
8445
8460
|
strokeWidth: 0,
|
|
8446
8461
|
selectable: false,
|
|
8447
8462
|
evented: false,
|
|
@@ -8493,6 +8508,7 @@ function createShapeCornerOverlays(shape, bounds, pageSide = "front", overlayCol
|
|
|
8493
8508
|
originX: "left",
|
|
8494
8509
|
originY: "top",
|
|
8495
8510
|
fill: overlayColor,
|
|
8511
|
+
opacity: 0.6,
|
|
8496
8512
|
strokeWidth: 0,
|
|
8497
8513
|
selectable: false,
|
|
8498
8514
|
evented: false,
|
|
@@ -8789,6 +8805,7 @@ function createOverlays(canvas2, workarea, pageSide) {
|
|
|
8789
8805
|
const overlayColor = canvas2.backgroundColor || "#F3F4F6";
|
|
8790
8806
|
const makeOverlay = (props) => new jr({
|
|
8791
8807
|
fill: overlayColor,
|
|
8808
|
+
opacity: 0.6,
|
|
8792
8809
|
selectable: false,
|
|
8793
8810
|
evented: false,
|
|
8794
8811
|
excludeFromExport: true,
|
|
@@ -8862,10 +8879,14 @@ function createOverlays(canvas2, workarea, pageSide) {
|
|
|
8862
8879
|
canvas2.requestRenderAll();
|
|
8863
8880
|
}
|
|
8864
8881
|
function bringOverlaysToFront(canvas2) {
|
|
8882
|
+
if (!canvas2) return;
|
|
8883
|
+
canvas2.preserveObjectStacking = true;
|
|
8884
|
+
canvas2.controlsAboveOverlay = true;
|
|
8865
8885
|
const overlays = canvas2.getObjects().filter((o2) => o2.name?.startsWith("overlay-"));
|
|
8866
8886
|
const guidelines = canvas2.getObjects().filter((o2) => o2.name?.startsWith("guideline-"));
|
|
8867
8887
|
overlays.forEach((overlay) => canvas2.bringObjectToFront(overlay));
|
|
8868
8888
|
guidelines.forEach((g2) => canvas2.bringObjectToFront(g2));
|
|
8889
|
+
canvas2.requestRenderAll();
|
|
8869
8890
|
}
|
|
8870
8891
|
const BASE_URL = "https://www.api.vibrantprintshop.com";
|
|
8871
8892
|
const IMAGE_UPLOAD_URL = "https://upload.vibrantprint.com";
|
|
@@ -9102,12 +9123,16 @@ async function loadPageToCanvas(canvas2, json, pageSide) {
|
|
|
9102
9123
|
}
|
|
9103
9124
|
}
|
|
9104
9125
|
createOverlays(canvas2, workarea, currentSide);
|
|
9126
|
+
if (bgImg) {
|
|
9127
|
+
canvas2.sendObjectToBack(bgImg);
|
|
9128
|
+
}
|
|
9105
9129
|
canvas2.sendObjectToBack(workarea);
|
|
9106
9130
|
}
|
|
9107
9131
|
canvas2.getObjects().forEach((obj) => {
|
|
9108
9132
|
const isWorkarea = obj.name === "workarea";
|
|
9109
9133
|
const isOverlayOrGuide = obj.name?.startsWith("overlay-") || obj.name?.startsWith("guideline-");
|
|
9110
|
-
|
|
9134
|
+
const isBgImage = obj.name === "bg-image";
|
|
9135
|
+
if (!isWorkarea && !isOverlayOrGuide && !isBgImage) {
|
|
9111
9136
|
obj.set({
|
|
9112
9137
|
selectable: true,
|
|
9113
9138
|
evented: true,
|
|
@@ -9245,6 +9270,77 @@ async function renderPageDataUrl(json, baseCanvas, multiplier = 1, targetSide, i
|
|
|
9245
9270
|
return "";
|
|
9246
9271
|
}
|
|
9247
9272
|
}
|
|
9273
|
+
const useDrawStore = create((set) => ({
|
|
9274
|
+
drawTool: "select",
|
|
9275
|
+
strokeWidth: 5,
|
|
9276
|
+
opacity: 100,
|
|
9277
|
+
color: "#000000",
|
|
9278
|
+
setDrawTool: (tool) => set(() => {
|
|
9279
|
+
if (tool === "highlighter") {
|
|
9280
|
+
return { drawTool: tool, opacity: 50 };
|
|
9281
|
+
}
|
|
9282
|
+
if (tool === "brush") {
|
|
9283
|
+
return { drawTool: tool, opacity: 100 };
|
|
9284
|
+
}
|
|
9285
|
+
return { drawTool: tool };
|
|
9286
|
+
}),
|
|
9287
|
+
setStrokeWidth: (v2) => set({ strokeWidth: v2 }),
|
|
9288
|
+
setOpacity: (v2) => set({ opacity: v2 }),
|
|
9289
|
+
setColor: (v2) => set({ color: v2 })
|
|
9290
|
+
}));
|
|
9291
|
+
function deriveType(objects) {
|
|
9292
|
+
if (objects.length === 0) return "none";
|
|
9293
|
+
if (objects.length > 1) return "multiple";
|
|
9294
|
+
const obj = objects[0];
|
|
9295
|
+
const t2 = obj.type?.toLowerCase();
|
|
9296
|
+
if (t2 === "activeselection") return "multiple";
|
|
9297
|
+
if (t2 === "group") {
|
|
9298
|
+
if (obj.name === "qr") return "qr";
|
|
9299
|
+
if (obj.name === "barcode") return "barcode";
|
|
9300
|
+
return "group";
|
|
9301
|
+
}
|
|
9302
|
+
if (t2 === "textbox" || t2 === "i-text" || t2 === "text") return "textbox";
|
|
9303
|
+
if (t2 === "image") return "image";
|
|
9304
|
+
return t2 || "none";
|
|
9305
|
+
}
|
|
9306
|
+
const useSelectionStore = create((set) => ({
|
|
9307
|
+
type: "none",
|
|
9308
|
+
objects: [],
|
|
9309
|
+
activeColor: null,
|
|
9310
|
+
activeColorIndex: 0,
|
|
9311
|
+
setSelection: (objects) => {
|
|
9312
|
+
if (objects && objects.length > 0) {
|
|
9313
|
+
const drawState = useDrawStore.getState();
|
|
9314
|
+
if (drawState.drawTool !== "select") {
|
|
9315
|
+
drawState.setDrawTool("select");
|
|
9316
|
+
}
|
|
9317
|
+
const canvas2 = useEditorStore.getState().canvas;
|
|
9318
|
+
if (canvas2 && canvas2.isDrawingMode) {
|
|
9319
|
+
canvas2.isDrawingMode = false;
|
|
9320
|
+
canvas2.selection = true;
|
|
9321
|
+
canvas2.defaultCursor = "default";
|
|
9322
|
+
canvas2._isCurrentlyDrawing = false;
|
|
9323
|
+
canvas2.requestRenderAll();
|
|
9324
|
+
}
|
|
9325
|
+
}
|
|
9326
|
+
set({
|
|
9327
|
+
objects,
|
|
9328
|
+
type: deriveType(objects),
|
|
9329
|
+
activeColor: null,
|
|
9330
|
+
activeColorIndex: 0
|
|
9331
|
+
});
|
|
9332
|
+
},
|
|
9333
|
+
setActiveColor: (color, index = 0) => set({
|
|
9334
|
+
activeColor: color,
|
|
9335
|
+
activeColorIndex: index
|
|
9336
|
+
}),
|
|
9337
|
+
clearSelection: () => set({
|
|
9338
|
+
type: "none",
|
|
9339
|
+
objects: [],
|
|
9340
|
+
activeColor: null,
|
|
9341
|
+
activeColorIndex: 0
|
|
9342
|
+
})
|
|
9343
|
+
}));
|
|
9248
9344
|
const HISTORY_CUSTOM_PROPERTIES = [
|
|
9249
9345
|
"name",
|
|
9250
9346
|
"id",
|
|
@@ -9255,6 +9351,9 @@ const HISTORY_CUSTOM_PROPERTIES = [
|
|
|
9255
9351
|
"lockMovementY",
|
|
9256
9352
|
"rx",
|
|
9257
9353
|
"ry",
|
|
9354
|
+
"src",
|
|
9355
|
+
"crossOrigin",
|
|
9356
|
+
"__maskPath",
|
|
9258
9357
|
"__radiusOfCanvas",
|
|
9259
9358
|
"__shapeType",
|
|
9260
9359
|
"__pageSide",
|
|
@@ -9265,7 +9364,8 @@ const HISTORY_CUSTOM_PROPERTIES = [
|
|
|
9265
9364
|
"__initialZoom",
|
|
9266
9365
|
"__borderRect",
|
|
9267
9366
|
"__rotationControlSize",
|
|
9268
|
-
"__showDegree"
|
|
9367
|
+
"__showDegree",
|
|
9368
|
+
"textAlign"
|
|
9269
9369
|
];
|
|
9270
9370
|
const useHistoryStore = create((set, get) => ({
|
|
9271
9371
|
canvas: null,
|
|
@@ -9288,11 +9388,12 @@ const useHistoryStore = create((set, get) => ({
|
|
|
9288
9388
|
setPage: (page) => set({ currentPage: page }),
|
|
9289
9389
|
saveState: () => {
|
|
9290
9390
|
const { canvas: canvas2, currentPage, pages, isRestoring } = get();
|
|
9291
|
-
|
|
9292
|
-
|
|
9391
|
+
const targetCanvas = canvas2 || useEditorStore.getState().canvas;
|
|
9392
|
+
if (!targetCanvas || isRestoring) return;
|
|
9393
|
+
const rawJson = targetCanvas.toObject(HISTORY_CUSTOM_PROPERTIES);
|
|
9293
9394
|
const cleanObjects = (rawJson.objects || []).filter((obj) => {
|
|
9294
9395
|
const name = obj.name || "";
|
|
9295
|
-
return name !== "watermark" && !name.startsWith("overlay-") && !name.startsWith("guideline-");
|
|
9396
|
+
return name !== "watermark" && !name.startsWith("overlay-") && !name.startsWith("guideline-") && name !== "canvas-grid";
|
|
9296
9397
|
});
|
|
9297
9398
|
const json = { ...rawJson, objects: cleanObjects };
|
|
9298
9399
|
const history = pages[currentPage]?.history ?? [];
|
|
@@ -9312,10 +9413,12 @@ const useHistoryStore = create((set, get) => ({
|
|
|
9312
9413
|
},
|
|
9313
9414
|
undo: async () => {
|
|
9314
9415
|
const { canvas: canvas2, currentPage, pages, isRestoring } = get();
|
|
9315
|
-
|
|
9416
|
+
const targetCanvas = canvas2 || useEditorStore.getState().canvas;
|
|
9417
|
+
if (!targetCanvas || isRestoring) return;
|
|
9316
9418
|
const page = pages[currentPage];
|
|
9317
9419
|
if (!page || page.history.length <= 1) return;
|
|
9318
|
-
|
|
9420
|
+
targetCanvas.discardActiveObject();
|
|
9421
|
+
useSelectionStore.getState().clearSelection();
|
|
9319
9422
|
const current = page.history.at(-1);
|
|
9320
9423
|
const previous = page.history.at(-2);
|
|
9321
9424
|
set({
|
|
@@ -9329,8 +9432,8 @@ const useHistoryStore = create((set, get) => ({
|
|
|
9329
9432
|
}
|
|
9330
9433
|
});
|
|
9331
9434
|
try {
|
|
9332
|
-
await loadPageToCanvas(
|
|
9333
|
-
|
|
9435
|
+
await loadPageToCanvas(targetCanvas, previous, currentPage);
|
|
9436
|
+
targetCanvas.requestRenderAll();
|
|
9334
9437
|
const editorStore = useEditorStore.getState();
|
|
9335
9438
|
if (editorStore.pages) {
|
|
9336
9439
|
editorStore.setPages({
|
|
@@ -9346,10 +9449,12 @@ const useHistoryStore = create((set, get) => ({
|
|
|
9346
9449
|
},
|
|
9347
9450
|
redoAction: async () => {
|
|
9348
9451
|
const { canvas: canvas2, currentPage, pages, isRestoring } = get();
|
|
9349
|
-
|
|
9452
|
+
const targetCanvas = canvas2 || useEditorStore.getState().canvas;
|
|
9453
|
+
if (!targetCanvas || isRestoring) return;
|
|
9350
9454
|
const page = pages[currentPage];
|
|
9351
9455
|
if (!page || page.redo.length === 0) return;
|
|
9352
|
-
|
|
9456
|
+
targetCanvas.discardActiveObject();
|
|
9457
|
+
useSelectionStore.getState().clearSelection();
|
|
9353
9458
|
const next = page.redo[0];
|
|
9354
9459
|
set({
|
|
9355
9460
|
isRestoring: true,
|
|
@@ -9362,8 +9467,8 @@ const useHistoryStore = create((set, get) => ({
|
|
|
9362
9467
|
}
|
|
9363
9468
|
});
|
|
9364
9469
|
try {
|
|
9365
|
-
await loadPageToCanvas(
|
|
9366
|
-
|
|
9470
|
+
await loadPageToCanvas(targetCanvas, next, currentPage);
|
|
9471
|
+
targetCanvas.requestRenderAll();
|
|
9367
9472
|
const editorStore = useEditorStore.getState();
|
|
9368
9473
|
if (editorStore.pages) {
|
|
9369
9474
|
editorStore.setPages({
|
|
@@ -9663,7 +9768,7 @@ function triggerDownload(url, filename) {
|
|
|
9663
9768
|
}
|
|
9664
9769
|
function exportDesignJSON(canvas2, workarea) {
|
|
9665
9770
|
const objects = canvas2.getObjects();
|
|
9666
|
-
const children = objects.filter((obj) => obj.name !== "workarea" && !obj.name?.startsWith("overlay-")).map((obj) => {
|
|
9771
|
+
const children = objects.filter((obj) => obj.name !== "workarea" && !obj.name?.startsWith("overlay-") && !obj.name?.startsWith("guideline-") && obj.name !== "canvas-grid").map((obj) => {
|
|
9667
9772
|
const base = obj.toObject();
|
|
9668
9773
|
return {
|
|
9669
9774
|
id: obj.id || crypto.randomUUID(),
|
|
@@ -9888,6 +9993,7 @@ async function addImageToCanvas(url) {
|
|
|
9888
9993
|
});
|
|
9889
9994
|
canvas2.add(img);
|
|
9890
9995
|
canvas2.setActiveObject(img);
|
|
9996
|
+
bringOverlaysToFront(canvas2);
|
|
9891
9997
|
canvas2.requestRenderAll();
|
|
9892
9998
|
}).catch((err) => {
|
|
9893
9999
|
console.warn("Fabric failed to load image from URL:", url, err);
|
|
@@ -9910,7 +10016,7 @@ function captureWorkareaSVG(canvas2, workarea, pageSide) {
|
|
|
9910
10016
|
canvas2.renderAll();
|
|
9911
10017
|
const originalProps = /* @__PURE__ */ new Map();
|
|
9912
10018
|
objects.forEach((obj) => {
|
|
9913
|
-
const isExcluded = obj.excludeFromExport || obj.name?.startsWith("overlay-") || obj.name?.startsWith("guide-") || obj.name?.startsWith("guideline-") || obj.name === "crop-grid";
|
|
10019
|
+
const isExcluded = obj.excludeFromExport || obj.name?.startsWith("overlay-") || obj.name?.startsWith("guide-") || obj.name?.startsWith("guideline-") || obj.name === "canvas-grid" || obj.name === "crop-grid";
|
|
9914
10020
|
if (isExcluded && obj !== targetWorkarea) {
|
|
9915
10021
|
originalProps.set(obj, {
|
|
9916
10022
|
visible: obj.visible,
|
|
@@ -102390,7 +102496,23 @@ const UploadIcon = () => /* @__PURE__ */ jsx(
|
|
|
102390
102496
|
const useSidePanelStore = create(
|
|
102391
102497
|
(set) => ({
|
|
102392
102498
|
activePanel: null,
|
|
102393
|
-
setActivePanel: (val) =>
|
|
102499
|
+
setActivePanel: (val) => {
|
|
102500
|
+
if (val !== "draw") {
|
|
102501
|
+
const drawState = useDrawStore.getState();
|
|
102502
|
+
if (drawState.drawTool !== "select") {
|
|
102503
|
+
drawState.setDrawTool("select");
|
|
102504
|
+
}
|
|
102505
|
+
const canvas2 = useEditorStore.getState().canvas;
|
|
102506
|
+
if (canvas2 && canvas2.isDrawingMode) {
|
|
102507
|
+
canvas2.isDrawingMode = false;
|
|
102508
|
+
canvas2.selection = true;
|
|
102509
|
+
canvas2.defaultCursor = "default";
|
|
102510
|
+
canvas2._isCurrentlyDrawing = false;
|
|
102511
|
+
canvas2.requestRenderAll();
|
|
102512
|
+
}
|
|
102513
|
+
}
|
|
102514
|
+
set({ activePanel: val });
|
|
102515
|
+
}
|
|
102394
102516
|
})
|
|
102395
102517
|
);
|
|
102396
102518
|
function Panel({ panelName }) {
|
|
@@ -102456,43 +102578,6 @@ function Panel({ panelName }) {
|
|
|
102456
102578
|
] })
|
|
102457
102579
|
] });
|
|
102458
102580
|
}
|
|
102459
|
-
function deriveType(objects) {
|
|
102460
|
-
if (objects.length === 0) return "none";
|
|
102461
|
-
if (objects.length > 1) return "multiple";
|
|
102462
|
-
const obj = objects[0];
|
|
102463
|
-
const t2 = obj.type?.toLowerCase();
|
|
102464
|
-
if (t2 === "activeselection") return "multiple";
|
|
102465
|
-
if (t2 === "group") {
|
|
102466
|
-
if (obj.name === "qr") return "qr";
|
|
102467
|
-
if (obj.name === "barcode") return "barcode";
|
|
102468
|
-
return "group";
|
|
102469
|
-
}
|
|
102470
|
-
if (t2 === "textbox" || t2 === "i-text" || t2 === "text") return "textbox";
|
|
102471
|
-
if (t2 === "image") return "image";
|
|
102472
|
-
return t2 || "none";
|
|
102473
|
-
}
|
|
102474
|
-
const useSelectionStore = create((set) => ({
|
|
102475
|
-
type: "none",
|
|
102476
|
-
objects: [],
|
|
102477
|
-
activeColor: null,
|
|
102478
|
-
activeColorIndex: 0,
|
|
102479
|
-
setSelection: (objects) => set({
|
|
102480
|
-
objects,
|
|
102481
|
-
type: deriveType(objects),
|
|
102482
|
-
activeColor: null,
|
|
102483
|
-
activeColorIndex: 0
|
|
102484
|
-
}),
|
|
102485
|
-
setActiveColor: (color, index = 0) => set({
|
|
102486
|
-
activeColor: color,
|
|
102487
|
-
activeColorIndex: index
|
|
102488
|
-
}),
|
|
102489
|
-
clearSelection: () => set({
|
|
102490
|
-
type: "none",
|
|
102491
|
-
objects: [],
|
|
102492
|
-
activeColor: null,
|
|
102493
|
-
activeColorIndex: 0
|
|
102494
|
-
})
|
|
102495
|
-
}));
|
|
102496
102581
|
function TemplatesPanel() {
|
|
102497
102582
|
const { productData } = useProductStore();
|
|
102498
102583
|
const { startLoading, stopLoading, isLoading } = useLoaderStore();
|
|
@@ -102933,6 +103018,7 @@ async function addSVGToCanvas(type = "svg", url) {
|
|
|
102933
103018
|
svg.setCoords();
|
|
102934
103019
|
canvas2.add(svg);
|
|
102935
103020
|
canvas2.setActiveObject(svg);
|
|
103021
|
+
bringOverlaysToFront(canvas2);
|
|
102936
103022
|
useSelectionStore.getState().setSelection([svg]);
|
|
102937
103023
|
canvas2.requestRenderAll();
|
|
102938
103024
|
}
|
|
@@ -102983,6 +103069,7 @@ async function renderSVGStringToCanvas(type = "svg", svg, options = {}) {
|
|
|
102983
103069
|
group.setCoords();
|
|
102984
103070
|
canvas2.add(group);
|
|
102985
103071
|
canvas2.setActiveObject(group);
|
|
103072
|
+
bringOverlaysToFront(canvas2);
|
|
102986
103073
|
useSelectionStore.getState().setSelection([group]);
|
|
102987
103074
|
canvas2.requestRenderAll();
|
|
102988
103075
|
return group;
|
|
@@ -103387,7 +103474,7 @@ async function addTextToCanvas(fontSize, width, textName) {
|
|
|
103387
103474
|
if (!workarea) return;
|
|
103388
103475
|
const workareaCenter = workarea.getCenterPoint();
|
|
103389
103476
|
const workareaBounds = workarea.getBoundingRect();
|
|
103390
|
-
const maxTextWidth = Math.max(40, workareaBounds.width * 0.
|
|
103477
|
+
const maxTextWidth = Math.max(40, workareaBounds.width * 0.85);
|
|
103391
103478
|
const textWidth = Math.min(width, maxTextWidth);
|
|
103392
103479
|
const text = new Uo(textName, {
|
|
103393
103480
|
fontSize,
|
|
@@ -103400,19 +103487,26 @@ async function addTextToCanvas(fontSize, width, textName) {
|
|
|
103400
103487
|
strokeWidth: 0,
|
|
103401
103488
|
hasRotatingPoint: true,
|
|
103402
103489
|
centerTransform: true,
|
|
103403
|
-
padding:
|
|
103490
|
+
padding: 0,
|
|
103404
103491
|
strokeUniform: true,
|
|
103405
103492
|
paintFirst: "stroke",
|
|
103406
103493
|
objectCaching: false
|
|
103407
103494
|
// Ensure maximum sharpness
|
|
103408
103495
|
});
|
|
103496
|
+
const measuredWidth = Math.ceil(text.calcTextWidth());
|
|
103497
|
+
if (measuredWidth > 0 && !textName.includes("\n")) {
|
|
103498
|
+
text.set({ width: Math.min(Math.max(measuredWidth + 4, 20), maxTextWidth) });
|
|
103499
|
+
text.initDimensions();
|
|
103500
|
+
}
|
|
103409
103501
|
canvas2.add(text);
|
|
103410
103502
|
text.set({
|
|
103411
103503
|
left: workareaCenter.x - text.getScaledWidth() / 2,
|
|
103412
103504
|
top: workareaCenter.y - text.getScaledHeight() / 2
|
|
103413
103505
|
});
|
|
103414
103506
|
canvas2.setActiveObject(text);
|
|
103507
|
+
bringOverlaysToFront(canvas2);
|
|
103415
103508
|
canvas2.requestRenderAll();
|
|
103509
|
+
useHistoryStore.getState().saveState();
|
|
103416
103510
|
}
|
|
103417
103511
|
async function addTextTemplate(id) {
|
|
103418
103512
|
try {
|
|
@@ -103444,6 +103538,7 @@ async function addTextTemplate(id) {
|
|
|
103444
103538
|
canvas2.add(...fabricObjects);
|
|
103445
103539
|
canvas2.renderOnAddRemove = true;
|
|
103446
103540
|
canvas2.requestRenderAll();
|
|
103541
|
+
useHistoryStore.getState().saveState();
|
|
103447
103542
|
} catch (err) {
|
|
103448
103543
|
console.error("Failed to add text template:", err);
|
|
103449
103544
|
}
|
|
@@ -104211,11 +104306,20 @@ function PhotosPanel() {
|
|
|
104211
104306
|
}) : !isLoading ? /* @__PURE__ */ jsx("div", { className: "col-span-full py-8 text-center text-xs text-gray-500", children: "No images found" }) : null }) })
|
|
104212
104307
|
] });
|
|
104213
104308
|
}
|
|
104309
|
+
let bgSaveTimer = null;
|
|
104310
|
+
function flushBackgroundSave() {
|
|
104311
|
+
if (bgSaveTimer) {
|
|
104312
|
+
clearTimeout(bgSaveTimer);
|
|
104313
|
+
bgSaveTimer = null;
|
|
104314
|
+
useHistoryStore.getState().saveState();
|
|
104315
|
+
}
|
|
104316
|
+
}
|
|
104214
104317
|
async function addBackgroundImage(url) {
|
|
104215
104318
|
const canvas2 = useEditorStore.getState().canvas;
|
|
104216
104319
|
if (!canvas2) return;
|
|
104217
104320
|
const workarea = canvas2.getObjects().find((o2) => o2.name === "workarea");
|
|
104218
104321
|
if (!workarea) return;
|
|
104322
|
+
flushBackgroundSave();
|
|
104219
104323
|
workarea.set("fill", "#ffffff");
|
|
104220
104324
|
canvas2.getObjects("image").forEach((o2) => {
|
|
104221
104325
|
if (o2.name === "bg-image") canvas2.remove(o2);
|
|
@@ -104227,7 +104331,16 @@ async function addBackgroundImage(url) {
|
|
|
104227
104331
|
const activeSide = workarea.__pageSide || useHistoryStore.getState().currentPage || "front";
|
|
104228
104332
|
const baseRx = (workarea.rx || workarea.__radiusOfCanvas || 0) * (workarea.scaleX || 1);
|
|
104229
104333
|
const baseRy = (workarea.ry || workarea.__radiusOfCanvas || 0) * (workarea.scaleY || 1);
|
|
104230
|
-
|
|
104334
|
+
let finalUrl = url;
|
|
104335
|
+
try {
|
|
104336
|
+
const b64 = await getBase64ImageFromURL(url);
|
|
104337
|
+
if (b64 && (b64.startsWith("data:image/png") || b64.startsWith("data:image/jpeg"))) {
|
|
104338
|
+
finalUrl = b64;
|
|
104339
|
+
}
|
|
104340
|
+
} catch {
|
|
104341
|
+
}
|
|
104342
|
+
try {
|
|
104343
|
+
const img = await oa.fromURL(finalUrl, { crossOrigin: "anonymous" });
|
|
104231
104344
|
const imgW = img.width || 1;
|
|
104232
104345
|
const imgH = img.height || 1;
|
|
104233
104346
|
const scale2 = Math.max(waW / imgW, waH / imgH);
|
|
@@ -104263,12 +104376,14 @@ async function addBackgroundImage(url) {
|
|
|
104263
104376
|
canvas2.add(img);
|
|
104264
104377
|
canvas2.sendObjectToBack(img);
|
|
104265
104378
|
canvas2.sendObjectToBack(workarea);
|
|
104379
|
+
bringOverlaysToFront(canvas2);
|
|
104266
104380
|
canvas2.requestRenderAll();
|
|
104267
|
-
|
|
104381
|
+
useHistoryStore.getState().saveState();
|
|
104382
|
+
} catch (err) {
|
|
104268
104383
|
console.warn("Fabric failed to load background image:", url, err);
|
|
104269
|
-
}
|
|
104384
|
+
}
|
|
104270
104385
|
}
|
|
104271
|
-
async function addBackgroundColor(color) {
|
|
104386
|
+
async function addBackgroundColor(color, immediate = false) {
|
|
104272
104387
|
const canvas2 = useEditorStore.getState().canvas;
|
|
104273
104388
|
if (!canvas2) return;
|
|
104274
104389
|
const workarea = canvas2.getObjects().find((o2) => o2.name === "workarea");
|
|
@@ -104277,7 +104392,20 @@ async function addBackgroundColor(color) {
|
|
|
104277
104392
|
if (o2.name === "bg-image") canvas2.remove(o2);
|
|
104278
104393
|
});
|
|
104279
104394
|
workarea.set("fill", color);
|
|
104395
|
+
bringOverlaysToFront(canvas2);
|
|
104280
104396
|
canvas2.requestRenderAll();
|
|
104397
|
+
if (bgSaveTimer) {
|
|
104398
|
+
clearTimeout(bgSaveTimer);
|
|
104399
|
+
bgSaveTimer = null;
|
|
104400
|
+
}
|
|
104401
|
+
if (immediate) {
|
|
104402
|
+
useHistoryStore.getState().saveState();
|
|
104403
|
+
} else {
|
|
104404
|
+
bgSaveTimer = setTimeout(() => {
|
|
104405
|
+
useHistoryStore.getState().saveState();
|
|
104406
|
+
bgSaveTimer = null;
|
|
104407
|
+
}, 120);
|
|
104408
|
+
}
|
|
104281
104409
|
}
|
|
104282
104410
|
function normalizeHexColor(c2) {
|
|
104283
104411
|
if (!c2 || typeof c2 !== "string" || c2 === "none" || c2 === "transparent" || c2.trim() === "") return null;
|
|
@@ -106037,11 +106165,11 @@ function BackgroundPanel() {
|
|
|
106037
106165
|
const [hasMore, setHasMore] = useState(true);
|
|
106038
106166
|
const [page, setPage] = useState(1);
|
|
106039
106167
|
const scrollRef = useRef(null);
|
|
106040
|
-
const handleApplyBackground = (type, value) => {
|
|
106168
|
+
const handleApplyBackground = async (type, value, immediate = false) => {
|
|
106041
106169
|
if (type === "color") {
|
|
106042
|
-
addBackgroundColor(value);
|
|
106170
|
+
await addBackgroundColor(value, immediate);
|
|
106043
106171
|
} else {
|
|
106044
|
-
addBackgroundImage(value);
|
|
106172
|
+
await addBackgroundImage(value);
|
|
106045
106173
|
}
|
|
106046
106174
|
if (window.innerWidth < 768) {
|
|
106047
106175
|
setActivePanel(null);
|
|
@@ -106094,7 +106222,7 @@ function BackgroundPanel() {
|
|
|
106094
106222
|
CMYKColorPicker,
|
|
106095
106223
|
{
|
|
106096
106224
|
value: "#ffffff",
|
|
106097
|
-
onChange: (hex) => handleApplyBackground("color", hex)
|
|
106225
|
+
onChange: (hex) => handleApplyBackground("color", hex, false)
|
|
106098
106226
|
}
|
|
106099
106227
|
),
|
|
106100
106228
|
CMYK_SAFE_COLORS.map(({ hex, label }) => /* @__PURE__ */ jsx(
|
|
@@ -106102,7 +106230,7 @@ function BackgroundPanel() {
|
|
|
106102
106230
|
{
|
|
106103
106231
|
className: "w-8 h-8 rounded border border-neutral-600 cursor-pointer transition-transform hover:scale-110",
|
|
106104
106232
|
style: { backgroundColor: hex },
|
|
106105
|
-
onClick: () => handleApplyBackground("color", hex),
|
|
106233
|
+
onClick: () => handleApplyBackground("color", hex, true),
|
|
106106
106234
|
title: label
|
|
106107
106235
|
},
|
|
106108
106236
|
hex
|
|
@@ -106118,7 +106246,7 @@ function BackgroundPanel() {
|
|
|
106118
106246
|
const image = await ShapeService.convertImages(item.largeImage);
|
|
106119
106247
|
const imageUrl = image?.success ? image?.url : null;
|
|
106120
106248
|
if (!imageUrl) return;
|
|
106121
|
-
handleApplyBackground("image", imageUrl);
|
|
106249
|
+
await handleApplyBackground("image", imageUrl);
|
|
106122
106250
|
if (window.innerWidth < 768) {
|
|
106123
106251
|
useSidePanelStore.getState().setActivePanel(null);
|
|
106124
106252
|
}
|
|
@@ -106214,24 +106342,6 @@ function UploadPanel() {
|
|
|
106214
106342
|
)) })
|
|
106215
106343
|
] });
|
|
106216
106344
|
}
|
|
106217
|
-
const useDrawStore = create((set) => ({
|
|
106218
|
-
drawTool: "select",
|
|
106219
|
-
strokeWidth: 5,
|
|
106220
|
-
opacity: 100,
|
|
106221
|
-
color: "#000000",
|
|
106222
|
-
setDrawTool: (tool) => set(() => {
|
|
106223
|
-
if (tool === "highlighter") {
|
|
106224
|
-
return { drawTool: tool, opacity: 50 };
|
|
106225
|
-
}
|
|
106226
|
-
if (tool === "brush") {
|
|
106227
|
-
return { drawTool: tool, opacity: 100 };
|
|
106228
|
-
}
|
|
106229
|
-
return { drawTool: tool };
|
|
106230
|
-
}),
|
|
106231
|
-
setStrokeWidth: (v2) => set({ strokeWidth: v2 }),
|
|
106232
|
-
setOpacity: (v2) => set({ opacity: v2 }),
|
|
106233
|
-
setColor: (v2) => set({ color: v2 })
|
|
106234
|
-
}));
|
|
106235
106345
|
function DrawPanel() {
|
|
106236
106346
|
const {
|
|
106237
106347
|
drawTool,
|
|
@@ -106246,7 +106356,7 @@ function DrawPanel() {
|
|
|
106246
106356
|
const isDisabled = drawTool === "select";
|
|
106247
106357
|
const TOOLS = [
|
|
106248
106358
|
{ key: "select", label: "✦ Selection" },
|
|
106249
|
-
{ key: "brush", label: "
|
|
106359
|
+
{ key: "brush", label: "✏️ Brush" },
|
|
106250
106360
|
{ key: "highlighter", label: "✎ Highlighter" }
|
|
106251
106361
|
];
|
|
106252
106362
|
return /* @__PURE__ */ jsxs("div", { className: "mx-4 select-none", children: [
|
|
@@ -111037,8 +111147,8 @@ function MaskPanel() {
|
|
|
111037
111147
|
const objWidth = obj.width ?? 1;
|
|
111038
111148
|
const objHeight = obj.height ?? 1;
|
|
111039
111149
|
const pathDims = clipPath.getBoundingRect();
|
|
111040
|
-
const scaleX = objWidth / pathDims.width;
|
|
111041
|
-
const scaleY = objHeight / pathDims.height;
|
|
111150
|
+
const scaleX = objWidth / (clipPath.width || pathDims.width);
|
|
111151
|
+
const scaleY = objHeight / (clipPath.height || pathDims.height);
|
|
111042
111152
|
clipPath.set({
|
|
111043
111153
|
scaleX,
|
|
111044
111154
|
scaleY,
|
|
@@ -111047,6 +111157,8 @@ function MaskPanel() {
|
|
|
111047
111157
|
angle: 0
|
|
111048
111158
|
// Should not inherit angle since the parent handles rotation
|
|
111049
111159
|
});
|
|
111160
|
+
clipPath.__maskPath = svgPath;
|
|
111161
|
+
obj.__maskPath = svgPath;
|
|
111050
111162
|
obj.set({ clipPath });
|
|
111051
111163
|
obj.setCoords();
|
|
111052
111164
|
canvas2.requestRenderAll();
|
|
@@ -156997,7 +157109,7 @@ function SidePanel() {
|
|
|
156997
157109
|
id: item.id,
|
|
156998
157110
|
item,
|
|
156999
157111
|
isActive: activePanel === item.id,
|
|
157000
|
-
onClick: () => setActivePanel(item.id)
|
|
157112
|
+
onClick: () => setActivePanel(activePanel === item.id ? null : item.id)
|
|
157001
157113
|
},
|
|
157002
157114
|
item.id
|
|
157003
157115
|
)
|
|
@@ -157012,7 +157124,7 @@ function SidePanel() {
|
|
|
157012
157124
|
item,
|
|
157013
157125
|
variant: "mobile",
|
|
157014
157126
|
isActive: activePanel === item.id,
|
|
157015
|
-
onClick: () => setActivePanel(item.id)
|
|
157127
|
+
onClick: () => setActivePanel(activePanel === item.id ? null : item.id)
|
|
157016
157128
|
},
|
|
157017
157129
|
item.id
|
|
157018
157130
|
)
|
|
@@ -157138,20 +157250,48 @@ function TextFontSize({
|
|
|
157138
157250
|
}
|
|
157139
157251
|
);
|
|
157140
157252
|
}
|
|
157141
|
-
function
|
|
157253
|
+
function TextAlignGroup({
|
|
157142
157254
|
value,
|
|
157143
157255
|
onChange
|
|
157144
157256
|
}) {
|
|
157145
|
-
const
|
|
157257
|
+
const current = value === "center" || value === "right" ? value : "left";
|
|
157146
157258
|
return /* @__PURE__ */ jsxs(
|
|
157147
|
-
"
|
|
157259
|
+
"div",
|
|
157148
157260
|
{
|
|
157149
|
-
|
|
157150
|
-
|
|
157261
|
+
className: "flex items-center bg-neutral-800 rounded p-0.5 gap-0.5 border border-neutral-700",
|
|
157262
|
+
role: "group",
|
|
157263
|
+
"aria-label": "Text alignment",
|
|
157151
157264
|
children: [
|
|
157152
|
-
|
|
157153
|
-
|
|
157154
|
-
|
|
157265
|
+
/* @__PURE__ */ jsx(
|
|
157266
|
+
"button",
|
|
157267
|
+
{
|
|
157268
|
+
type: "button",
|
|
157269
|
+
title: "Align Left",
|
|
157270
|
+
onClick: () => onChange("left"),
|
|
157271
|
+
className: `p-1 rounded transition-colors ${current === "left" ? "bg-neutral-600 text-white shadow-sm" : "text-neutral-400 hover:text-white hover:bg-neutral-700"}`,
|
|
157272
|
+
children: /* @__PURE__ */ jsx(AlignLeftIcon$1, {})
|
|
157273
|
+
}
|
|
157274
|
+
),
|
|
157275
|
+
/* @__PURE__ */ jsx(
|
|
157276
|
+
"button",
|
|
157277
|
+
{
|
|
157278
|
+
type: "button",
|
|
157279
|
+
title: "Align Center",
|
|
157280
|
+
onClick: () => onChange("center"),
|
|
157281
|
+
className: `p-1 rounded transition-colors ${current === "center" ? "bg-neutral-600 text-white shadow-sm" : "text-neutral-400 hover:text-white hover:bg-neutral-700"}`,
|
|
157282
|
+
children: /* @__PURE__ */ jsx(AlignCenterIcon$1, {})
|
|
157283
|
+
}
|
|
157284
|
+
),
|
|
157285
|
+
/* @__PURE__ */ jsx(
|
|
157286
|
+
"button",
|
|
157287
|
+
{
|
|
157288
|
+
type: "button",
|
|
157289
|
+
title: "Align Right",
|
|
157290
|
+
onClick: () => onChange("right"),
|
|
157291
|
+
className: `p-1 rounded transition-colors ${current === "right" ? "bg-neutral-600 text-white shadow-sm" : "text-neutral-400 hover:text-white hover:bg-neutral-700"}`,
|
|
157292
|
+
children: /* @__PURE__ */ jsx(AlignRightIcon$1, {})
|
|
157293
|
+
}
|
|
157294
|
+
)
|
|
157155
157295
|
]
|
|
157156
157296
|
}
|
|
157157
157297
|
);
|
|
@@ -157204,15 +157344,29 @@ function TextToolbar() {
|
|
|
157204
157344
|
}, [type, objects]);
|
|
157205
157345
|
useEffect(() => {
|
|
157206
157346
|
if (!text) return;
|
|
157207
|
-
|
|
157208
|
-
|
|
157209
|
-
|
|
157210
|
-
|
|
157211
|
-
|
|
157212
|
-
|
|
157213
|
-
|
|
157214
|
-
|
|
157215
|
-
|
|
157347
|
+
const syncProps = () => {
|
|
157348
|
+
setFontSize(text.fontSize ?? 18);
|
|
157349
|
+
setLineHeight2((text.lineHeight ?? 1) * 100);
|
|
157350
|
+
setCharSpacing(text.charSpacing ?? 0);
|
|
157351
|
+
setAlign(text.textAlign ?? "left");
|
|
157352
|
+
const dashArray = text.strokeDashArray;
|
|
157353
|
+
const currentStrokeStyle = Array.isArray(dashArray) && dashArray.length === 2 && dashArray[0] === 2 && dashArray[1] === 4 ? "Dotted" : Array.isArray(dashArray) && dashArray.length === 2 && dashArray[0] === 10 && dashArray[1] === 5 ? "Dashed" : "Line";
|
|
157354
|
+
setStrokeColor(typeof text.stroke === "string" && text.stroke ? text.stroke : "#000000");
|
|
157355
|
+
setStrokeSize(Math.max(0, Number(text.strokeWidth ?? 0)));
|
|
157356
|
+
setStrokeStyle(currentStrokeStyle);
|
|
157357
|
+
};
|
|
157358
|
+
syncProps();
|
|
157359
|
+
const canvas2 = text.canvas;
|
|
157360
|
+
if (canvas2) {
|
|
157361
|
+
canvas2.on("object:modified", syncProps);
|
|
157362
|
+
canvas2.on("selection:updated", syncProps);
|
|
157363
|
+
}
|
|
157364
|
+
return () => {
|
|
157365
|
+
if (canvas2) {
|
|
157366
|
+
canvas2.off("object:modified", syncProps);
|
|
157367
|
+
canvas2.off("selection:updated", syncProps);
|
|
157368
|
+
}
|
|
157369
|
+
};
|
|
157216
157370
|
}, [text]);
|
|
157217
157371
|
const updateText = useCallback(
|
|
157218
157372
|
(props) => {
|
|
@@ -157220,6 +157374,11 @@ function TextToolbar() {
|
|
|
157220
157374
|
const canvas2 = text.canvas;
|
|
157221
157375
|
if (!canvas2) return;
|
|
157222
157376
|
text.set(props);
|
|
157377
|
+
if (props.textAlign) {
|
|
157378
|
+
text.dirty = true;
|
|
157379
|
+
text.initDimensions?.();
|
|
157380
|
+
text.setCoords();
|
|
157381
|
+
}
|
|
157223
157382
|
canvas2.requestRenderAll();
|
|
157224
157383
|
useHistoryStore.getState().saveState();
|
|
157225
157384
|
},
|
|
@@ -157276,7 +157435,7 @@ function TextToolbar() {
|
|
|
157276
157435
|
}
|
|
157277
157436
|
),
|
|
157278
157437
|
/* @__PURE__ */ jsx(
|
|
157279
|
-
|
|
157438
|
+
TextAlignGroup,
|
|
157280
157439
|
{
|
|
157281
157440
|
value: align,
|
|
157282
157441
|
onChange: (v2) => {
|
|
@@ -157532,6 +157691,7 @@ class CropService {
|
|
|
157532
157691
|
darkOverlay = null;
|
|
157533
157692
|
focusedImage = null;
|
|
157534
157693
|
cropZone = null;
|
|
157694
|
+
maskPath = null;
|
|
157535
157695
|
onEnd = null;
|
|
157536
157696
|
init(canvas2) {
|
|
157537
157697
|
this.canvas = canvas2;
|
|
@@ -157543,6 +157703,7 @@ class CropService {
|
|
|
157543
157703
|
this.cleanup();
|
|
157544
157704
|
this.targetImage = image;
|
|
157545
157705
|
this.onEnd = onEnd || null;
|
|
157706
|
+
this.maskPath = image.__maskPath || image.clipPath?.__maskPath || null;
|
|
157546
157707
|
const canvas2 = this.canvas;
|
|
157547
157708
|
canvas2.renderOnAddRemove = false;
|
|
157548
157709
|
canvas2.discardActiveObject();
|
|
@@ -157559,7 +157720,8 @@ class CropService {
|
|
|
157559
157720
|
width: naturalWidth,
|
|
157560
157721
|
height: naturalHeight,
|
|
157561
157722
|
selectable: false,
|
|
157562
|
-
evented: false
|
|
157723
|
+
evented: false,
|
|
157724
|
+
clipPath: void 0
|
|
157563
157725
|
});
|
|
157564
157726
|
const cropX = image.cropX || 0;
|
|
157565
157727
|
const cropY = image.cropY || 0;
|
|
@@ -157690,14 +157852,31 @@ class CropService {
|
|
|
157690
157852
|
const local = Mn.transformPoint(center, inv);
|
|
157691
157853
|
const localW = zone.getScaledWidth() / Math.abs(img.scaleX);
|
|
157692
157854
|
const localH = zone.getScaledHeight() / Math.abs(img.scaleY);
|
|
157693
|
-
|
|
157694
|
-
|
|
157695
|
-
|
|
157696
|
-
|
|
157697
|
-
|
|
157698
|
-
|
|
157699
|
-
|
|
157700
|
-
|
|
157855
|
+
if (this.maskPath) {
|
|
157856
|
+
const maskClip = new no(this.maskPath, {
|
|
157857
|
+
originX: "center",
|
|
157858
|
+
originY: "center"
|
|
157859
|
+
});
|
|
157860
|
+
const pathW = maskClip.width || 1;
|
|
157861
|
+
const pathH = maskClip.height || 1;
|
|
157862
|
+
maskClip.set({
|
|
157863
|
+
left: local.x,
|
|
157864
|
+
top: local.y,
|
|
157865
|
+
scaleX: localW / pathW,
|
|
157866
|
+
scaleY: localH / pathH,
|
|
157867
|
+
angle: 0
|
|
157868
|
+
});
|
|
157869
|
+
img.clipPath = maskClip;
|
|
157870
|
+
} else {
|
|
157871
|
+
img.clipPath = new jr({
|
|
157872
|
+
left: local.x,
|
|
157873
|
+
top: local.y,
|
|
157874
|
+
width: localW,
|
|
157875
|
+
height: localH,
|
|
157876
|
+
originX: "center",
|
|
157877
|
+
originY: "center"
|
|
157878
|
+
});
|
|
157879
|
+
}
|
|
157701
157880
|
img.dirty = true;
|
|
157702
157881
|
}
|
|
157703
157882
|
/* ======================= APPLY CROP ======================= */
|
|
@@ -157722,11 +157901,13 @@ class CropService {
|
|
|
157722
157901
|
const minY = Math.min(...ys2);
|
|
157723
157902
|
const maxX = Math.max(...xs2);
|
|
157724
157903
|
const maxY = Math.max(...ys2);
|
|
157904
|
+
const newW = Math.min(full.width, maxX - minX);
|
|
157905
|
+
const newH = Math.min(full.height, maxY - minY);
|
|
157725
157906
|
img.set({
|
|
157726
157907
|
cropX: Math.max(0, minX),
|
|
157727
157908
|
cropY: Math.max(0, minY),
|
|
157728
|
-
width:
|
|
157729
|
-
height:
|
|
157909
|
+
width: newW,
|
|
157910
|
+
height: newH,
|
|
157730
157911
|
scaleX: full.scaleX,
|
|
157731
157912
|
scaleY: full.scaleY,
|
|
157732
157913
|
angle: full.angle,
|
|
@@ -157738,6 +157919,35 @@ class CropService {
|
|
|
157738
157919
|
selectable: true,
|
|
157739
157920
|
evented: true
|
|
157740
157921
|
});
|
|
157922
|
+
if (this.maskPath) {
|
|
157923
|
+
const newClip = new no(this.maskPath, {
|
|
157924
|
+
originX: "center",
|
|
157925
|
+
originY: "center"
|
|
157926
|
+
});
|
|
157927
|
+
const pathW = newClip.width || 1;
|
|
157928
|
+
const pathH = newClip.height || 1;
|
|
157929
|
+
newClip.set({
|
|
157930
|
+
scaleX: newW / pathW,
|
|
157931
|
+
scaleY: newH / pathH,
|
|
157932
|
+
left: 0,
|
|
157933
|
+
top: 0,
|
|
157934
|
+
angle: 0
|
|
157935
|
+
});
|
|
157936
|
+
newClip.__maskPath = this.maskPath;
|
|
157937
|
+
img.__maskPath = this.maskPath;
|
|
157938
|
+
img.set({ clipPath: newClip });
|
|
157939
|
+
} else if (img.clipPath && img.clipPath.type === "path") {
|
|
157940
|
+
const pW = img.clipPath.width || 1;
|
|
157941
|
+
const pH = img.clipPath.height || 1;
|
|
157942
|
+
img.clipPath.set({
|
|
157943
|
+
scaleX: newW / pW,
|
|
157944
|
+
scaleY: newH / pH,
|
|
157945
|
+
left: 0,
|
|
157946
|
+
top: 0,
|
|
157947
|
+
originX: "center",
|
|
157948
|
+
originY: "center"
|
|
157949
|
+
});
|
|
157950
|
+
}
|
|
157741
157951
|
img.setPositionByOrigin(
|
|
157742
157952
|
new ot(zone.left, zone.top),
|
|
157743
157953
|
"center",
|
|
@@ -157746,7 +157956,9 @@ class CropService {
|
|
|
157746
157956
|
img.setCoords();
|
|
157747
157957
|
this.cleanup();
|
|
157748
157958
|
this.canvas.setActiveObject(img);
|
|
157959
|
+
bringOverlaysToFront(this.canvas);
|
|
157749
157960
|
this.canvas.requestRenderAll();
|
|
157961
|
+
useHistoryStore.getState().saveState();
|
|
157750
157962
|
this.onEnd?.();
|
|
157751
157963
|
}
|
|
157752
157964
|
/* ======================== CANCEL ========================== */
|
|
@@ -157782,6 +157994,7 @@ class CropService {
|
|
|
157782
157994
|
this.fullImage = null;
|
|
157783
157995
|
this.darkOverlay = null;
|
|
157784
157996
|
this.targetImage = null;
|
|
157997
|
+
this.maskPath = null;
|
|
157785
157998
|
}
|
|
157786
157999
|
}
|
|
157787
158000
|
const cropService = new CropService();
|
|
@@ -157868,7 +158081,7 @@ function PictureToolbar() {
|
|
|
157868
158081
|
const [isRemovingBg, setIsRemovingBg] = useState(false);
|
|
157869
158082
|
const [bgStatus, setBgStatus] = useState(null);
|
|
157870
158083
|
const activeObj = canvas2?.getActiveObject();
|
|
157871
|
-
const hasMask = !!activeObj?.clipPath;
|
|
158084
|
+
const hasMask = !!activeObj?.clipPath || !!activeObj?.__maskPath;
|
|
157872
158085
|
activeObj && (activeObj.type === "image" || activeObj.isType?.("image"));
|
|
157873
158086
|
const isBgRemoved = !!activeObj?.__originalSrc || !!activeObj?.__isBgRemoved;
|
|
157874
158087
|
if (type !== "image" || objects?.[0]?.name === "qr" || objects?.[0]?.name === "barcode")
|
|
@@ -157877,8 +158090,9 @@ function PictureToolbar() {
|
|
|
157877
158090
|
if (!canvas2) return;
|
|
157878
158091
|
const obj = canvas2.getActiveObject();
|
|
157879
158092
|
if (!obj) return;
|
|
157880
|
-
if (obj.clipPath) {
|
|
158093
|
+
if (obj.clipPath || obj.__maskPath) {
|
|
157881
158094
|
obj.set({ clipPath: null });
|
|
158095
|
+
obj.__maskPath = null;
|
|
157882
158096
|
obj.setCoords();
|
|
157883
158097
|
canvas2.requestRenderAll();
|
|
157884
158098
|
saveState();
|
|
@@ -158169,6 +158383,7 @@ function DuplicateButton() {
|
|
|
158169
158383
|
);
|
|
158170
158384
|
const newSelection = clones.length > 1 ? new Qo(clones, { canvas: canvas2 }) : clones[0];
|
|
158171
158385
|
canvas2.setActiveObject(newSelection);
|
|
158386
|
+
bringOverlaysToFront(canvas2);
|
|
158172
158387
|
canvas2.requestRenderAll();
|
|
158173
158388
|
saveState();
|
|
158174
158389
|
return;
|
|
@@ -158184,6 +158399,7 @@ function DuplicateButton() {
|
|
|
158184
158399
|
canvas2.discardActiveObject();
|
|
158185
158400
|
canvas2.add(cloned);
|
|
158186
158401
|
canvas2.setActiveObject(cloned);
|
|
158402
|
+
bringOverlaysToFront(canvas2);
|
|
158187
158403
|
canvas2.requestRenderAll();
|
|
158188
158404
|
};
|
|
158189
158405
|
return /* @__PURE__ */ jsx(
|
|
@@ -158737,44 +158953,50 @@ function PositionPicker() {
|
|
|
158737
158953
|
if (!active) return [];
|
|
158738
158954
|
return active.type?.toLowerCase() === "activeselection" ? active.getObjects() : [active];
|
|
158739
158955
|
};
|
|
158740
|
-
const
|
|
158741
|
-
const normalizeOrigin = (obj) => {
|
|
158742
|
-
if (obj.originX === "left" && obj.originY === "top") return;
|
|
158743
|
-
const point = obj.getPointByOrigin("left", "top");
|
|
158744
|
-
obj.set({ originX: "left", originY: "top" });
|
|
158745
|
-
obj.setPositionByOrigin(point, "left", "top");
|
|
158746
|
-
};
|
|
158956
|
+
const getAlignmentBoundary = () => canvas2.getObjects().find((o2) => o2.name === "workarea");
|
|
158747
158957
|
const applyAlign = (align) => {
|
|
158748
|
-
const
|
|
158749
|
-
if (!
|
|
158750
|
-
const
|
|
158751
|
-
const
|
|
158752
|
-
const
|
|
158753
|
-
const
|
|
158958
|
+
const boundary = getAlignmentBoundary();
|
|
158959
|
+
if (!boundary) return;
|
|
158960
|
+
const bBounds = boundary.getBoundingRect();
|
|
158961
|
+
const bLeft = bBounds.left;
|
|
158962
|
+
const bTop = bBounds.top;
|
|
158963
|
+
const bWidth = bBounds.width;
|
|
158964
|
+
const bHeight = bBounds.height;
|
|
158754
158965
|
getTargets().forEach((obj) => {
|
|
158755
|
-
|
|
158756
|
-
const
|
|
158757
|
-
const
|
|
158966
|
+
const objBounds = obj.getBoundingRect();
|
|
158967
|
+
const pad = obj.padding || 0;
|
|
158968
|
+
const effLeft = objBounds.left - pad;
|
|
158969
|
+
const effTop = objBounds.top - pad;
|
|
158970
|
+
const effWidth = objBounds.width + pad * 2;
|
|
158971
|
+
const effHeight = objBounds.height + pad * 2;
|
|
158972
|
+
let dx = 0;
|
|
158973
|
+
let dy = 0;
|
|
158758
158974
|
switch (align) {
|
|
158759
158975
|
case "left":
|
|
158760
|
-
|
|
158976
|
+
dx = bLeft - effLeft;
|
|
158761
158977
|
break;
|
|
158762
158978
|
case "center":
|
|
158763
|
-
|
|
158979
|
+
dx = bLeft + (bWidth - effWidth) / 2 - effLeft;
|
|
158764
158980
|
break;
|
|
158765
158981
|
case "right":
|
|
158766
|
-
|
|
158982
|
+
dx = bLeft + bWidth - effWidth - effLeft;
|
|
158767
158983
|
break;
|
|
158768
158984
|
case "top":
|
|
158769
|
-
|
|
158985
|
+
dy = bTop - effTop;
|
|
158770
158986
|
break;
|
|
158771
158987
|
case "middle":
|
|
158772
|
-
|
|
158988
|
+
dy = bTop + (bHeight - effHeight) / 2 - effTop;
|
|
158773
158989
|
break;
|
|
158774
158990
|
case "bottom":
|
|
158775
|
-
|
|
158991
|
+
dy = bTop + bHeight - effHeight - effTop;
|
|
158776
158992
|
break;
|
|
158777
158993
|
}
|
|
158994
|
+
if (dx !== 0) {
|
|
158995
|
+
obj.set({ left: (obj.left ?? 0) + dx });
|
|
158996
|
+
}
|
|
158997
|
+
if (dy !== 0) {
|
|
158998
|
+
obj.set({ top: (obj.top ?? 0) + dy });
|
|
158999
|
+
}
|
|
158778
159000
|
obj.setCoords();
|
|
158779
159001
|
});
|
|
158780
159002
|
canvas2.requestRenderAll();
|
|
@@ -158797,42 +159019,40 @@ function PositionPicker() {
|
|
|
158797
159019
|
const objects = active.getObjects();
|
|
158798
159020
|
if (objects.length && objects.length > 1) {
|
|
158799
159021
|
objects.forEach(function(obj) {
|
|
158800
|
-
const itemWidth = obj.
|
|
159022
|
+
const itemWidth = obj.getScaledWidth();
|
|
159023
|
+
const itemHeight = obj.getScaledHeight();
|
|
159024
|
+
obj.set({ originX: "center", originY: "center" });
|
|
158801
159025
|
switch (align) {
|
|
158802
159026
|
case "left":
|
|
158803
|
-
obj.set({ left: -
|
|
159027
|
+
obj.set({ left: -groupWidth / 2 + itemWidth / 2 });
|
|
158804
159028
|
break;
|
|
158805
159029
|
case "center":
|
|
158806
|
-
obj.set({ left: 0
|
|
159030
|
+
obj.set({ left: 0 });
|
|
158807
159031
|
break;
|
|
158808
159032
|
case "right":
|
|
158809
|
-
obj.set({
|
|
158810
|
-
left: groupWidth / 2 - itemWidth / 2,
|
|
158811
|
-
originX: "center"
|
|
158812
|
-
});
|
|
159033
|
+
obj.set({ left: groupWidth / 2 - itemWidth / 2 });
|
|
158813
159034
|
break;
|
|
158814
159035
|
case "top":
|
|
158815
|
-
obj.set({
|
|
158816
|
-
break;
|
|
158817
|
-
case "bottom":
|
|
158818
|
-
obj.set({ originY: "bottom", top: groupHeight / 2 });
|
|
159036
|
+
obj.set({ top: -groupHeight / 2 + itemHeight / 2 });
|
|
158819
159037
|
break;
|
|
158820
159038
|
case "middle":
|
|
158821
|
-
obj.set({
|
|
158822
|
-
|
|
158823
|
-
|
|
158824
|
-
});
|
|
159039
|
+
obj.set({ top: 0 });
|
|
159040
|
+
break;
|
|
159041
|
+
case "bottom":
|
|
159042
|
+
obj.set({ top: groupHeight / 2 - itemHeight / 2 });
|
|
158825
159043
|
break;
|
|
158826
159044
|
}
|
|
158827
159045
|
obj.setCoords();
|
|
158828
|
-
canvas2.requestRenderAll();
|
|
158829
|
-
saveState();
|
|
158830
159046
|
});
|
|
159047
|
+
active.setCoords();
|
|
159048
|
+
canvas2.requestRenderAll();
|
|
159049
|
+
saveState();
|
|
158831
159050
|
}
|
|
158832
159051
|
};
|
|
158833
159052
|
const bringForward = () => {
|
|
158834
159053
|
const objects = canvas2.getObjects();
|
|
158835
159054
|
[...getTargets()].sort((a2, b2) => objects.indexOf(a2) - objects.indexOf(b2)).reverse().forEach((obj) => canvas2.bringObjectForward(obj, true));
|
|
159055
|
+
bringOverlaysToFront(canvas2);
|
|
158836
159056
|
canvas2.requestRenderAll();
|
|
158837
159057
|
saveState();
|
|
158838
159058
|
};
|
|
@@ -158861,6 +159081,7 @@ function PositionPicker() {
|
|
|
158861
159081
|
const bringToFront = () => {
|
|
158862
159082
|
const objects = canvas2.getObjects();
|
|
158863
159083
|
[...getTargets()].sort((a2, b2) => objects.indexOf(a2) - objects.indexOf(b2)).reverse().forEach((obj) => canvas2.bringObjectToFront(obj));
|
|
159084
|
+
bringOverlaysToFront(canvas2);
|
|
158864
159085
|
canvas2.requestRenderAll();
|
|
158865
159086
|
saveState();
|
|
158866
159087
|
};
|
|
@@ -159215,6 +159436,7 @@ function GroupButton() {
|
|
|
159215
159436
|
canvas2.add(group);
|
|
159216
159437
|
}
|
|
159217
159438
|
canvas2.setActiveObject(group);
|
|
159439
|
+
bringOverlaysToFront(canvas2);
|
|
159218
159440
|
canvas2.requestRenderAll();
|
|
159219
159441
|
useSelectionStore.getState().setSelection([group]);
|
|
159220
159442
|
saveState();
|
|
@@ -159366,6 +159588,9 @@ function configureObjectControls(obj) {
|
|
|
159366
159588
|
obj.__rotationControlSize = rotationSize;
|
|
159367
159589
|
obj.controls.mtr = createRotateControl(rotationSize, rotationOffset);
|
|
159368
159590
|
const textObject = isTextObject(obj);
|
|
159591
|
+
if (textObject) {
|
|
159592
|
+
obj.set({ padding: 0 });
|
|
159593
|
+
}
|
|
159369
159594
|
if (!obj.controls.mb) {
|
|
159370
159595
|
obj.controls.mb = new ai({
|
|
159371
159596
|
x: 0,
|
|
@@ -159484,6 +159709,7 @@ function UngroupButton() {
|
|
|
159484
159709
|
});
|
|
159485
159710
|
canvas2.discardActiveObject();
|
|
159486
159711
|
useSelectionStore.getState().clearSelection();
|
|
159712
|
+
bringOverlaysToFront(canvas2);
|
|
159487
159713
|
canvas2.requestRenderAll();
|
|
159488
159714
|
saveState();
|
|
159489
159715
|
};
|
|
@@ -159593,12 +159819,31 @@ function Toolbar() {
|
|
|
159593
159819
|
) });
|
|
159594
159820
|
}
|
|
159595
159821
|
function applyOpacity(hex, opacity) {
|
|
159596
|
-
const alpha = Math.max(0, Math.min(1, opacity / 100));
|
|
159597
|
-
|
|
159598
|
-
|
|
159599
|
-
|
|
159600
|
-
|
|
159601
|
-
|
|
159822
|
+
const alpha = Math.max(0, Math.min(1, (opacity ?? 100) / 100));
|
|
159823
|
+
if (!hex) return `rgba(0, 0, 0, ${alpha})`;
|
|
159824
|
+
let clean = hex.trim();
|
|
159825
|
+
if (clean.startsWith("#")) {
|
|
159826
|
+
clean = clean.slice(1);
|
|
159827
|
+
if (clean.length === 3) {
|
|
159828
|
+
clean = clean.split("").map((c2) => c2 + c2).join("");
|
|
159829
|
+
}
|
|
159830
|
+
if (clean.length >= 6) {
|
|
159831
|
+
const r2 = parseInt(clean.slice(0, 2), 16) || 0;
|
|
159832
|
+
const g2 = parseInt(clean.slice(2, 4), 16) || 0;
|
|
159833
|
+
const b2 = parseInt(clean.slice(4, 6), 16) || 0;
|
|
159834
|
+
return `rgba(${r2}, ${g2}, ${b2}, ${alpha})`;
|
|
159835
|
+
}
|
|
159836
|
+
}
|
|
159837
|
+
return clean;
|
|
159838
|
+
}
|
|
159839
|
+
const PENCIL_CURSOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
159840
|
+
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" fill="#ffffff" stroke="#ffffff" stroke-width="2.5" stroke-linejoin="round"/>
|
|
159841
|
+
<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" fill="#1e293b" stroke="#0f172a" stroke-width="1.2" stroke-linejoin="round"/>
|
|
159842
|
+
<polygon points="2,22 5.5,20 4,18.5" fill="#f59e0b"/>
|
|
159843
|
+
<polygon points="2,22 3.2,21.3 2.7,20.8" fill="#000000"/>
|
|
159844
|
+
<path d="m15 5 4 4" stroke="#94a3b8" stroke-width="1.2" stroke-linecap="round"/>
|
|
159845
|
+
</svg>`;
|
|
159846
|
+
const PENCIL_CURSOR = `url("data:image/svg+xml;utf8,${encodeURIComponent(PENCIL_CURSOR_SVG)}") 2 22, crosshair`;
|
|
159602
159847
|
function useFabricDrawing() {
|
|
159603
159848
|
const { drawTool, strokeWidth, opacity, color } = useDrawStore();
|
|
159604
159849
|
useEffect(() => {
|
|
@@ -159608,19 +159853,99 @@ function useFabricDrawing() {
|
|
|
159608
159853
|
canvas2.isDrawingMode = false;
|
|
159609
159854
|
canvas2.selection = true;
|
|
159610
159855
|
canvas2.defaultCursor = "default";
|
|
159856
|
+
canvas2.freeDrawingCursor = "default";
|
|
159857
|
+
canvas2.setCursor("default");
|
|
159858
|
+
if (canvas2.upperCanvasEl) {
|
|
159859
|
+
canvas2.upperCanvasEl.style.cursor = "default";
|
|
159860
|
+
}
|
|
159861
|
+
canvas2._isCurrentlyDrawing = false;
|
|
159611
159862
|
return;
|
|
159612
159863
|
}
|
|
159864
|
+
if (canvas2.getActiveObject()) {
|
|
159865
|
+
canvas2.discardActiveObject();
|
|
159866
|
+
useSelectionStore.getState().clearSelection();
|
|
159867
|
+
canvas2.requestRenderAll();
|
|
159868
|
+
}
|
|
159869
|
+
const activeCursor = drawTool === "brush" ? PENCIL_CURSOR : "crosshair";
|
|
159613
159870
|
canvas2.isDrawingMode = true;
|
|
159614
159871
|
canvas2.selection = false;
|
|
159615
|
-
canvas2.defaultCursor =
|
|
159872
|
+
canvas2.defaultCursor = activeCursor;
|
|
159873
|
+
canvas2.freeDrawingCursor = activeCursor;
|
|
159874
|
+
canvas2.setCursor(activeCursor);
|
|
159875
|
+
if (canvas2.upperCanvasEl) {
|
|
159876
|
+
canvas2.upperCanvasEl.style.cursor = activeCursor;
|
|
159877
|
+
}
|
|
159616
159878
|
const brush = new oo(canvas2);
|
|
159617
|
-
brush.width = strokeWidth;
|
|
159618
|
-
brush.color = applyOpacity(color, opacity);
|
|
159619
159879
|
if (drawTool === "highlighter") {
|
|
159620
159880
|
brush.width = strokeWidth * 1.5;
|
|
159621
|
-
brush.color = applyOpacity(color,
|
|
159881
|
+
brush.color = applyOpacity(color, opacity ?? 50);
|
|
159882
|
+
} else {
|
|
159883
|
+
brush.width = strokeWidth;
|
|
159884
|
+
brush.color = applyOpacity(color, opacity ?? 100);
|
|
159622
159885
|
}
|
|
159623
159886
|
canvas2.freeDrawingBrush = brush;
|
|
159887
|
+
const handleMouseDownBefore = (opt) => {
|
|
159888
|
+
if (!canvas2.isDrawingMode) return;
|
|
159889
|
+
const target = opt.target || canvas2.findTarget(opt.e);
|
|
159890
|
+
if (!target) return;
|
|
159891
|
+
const name = target.name || "";
|
|
159892
|
+
if (name === "workarea" || name === "watermark" || name.startsWith("overlay-") || name.startsWith("guideline-")) {
|
|
159893
|
+
return;
|
|
159894
|
+
}
|
|
159895
|
+
if (target.isDrawingPath || name === "drawing-path") {
|
|
159896
|
+
return;
|
|
159897
|
+
}
|
|
159898
|
+
if (target.selectable !== false && target.evented !== false) {
|
|
159899
|
+
canvas2.isDrawingMode = false;
|
|
159900
|
+
canvas2.selection = true;
|
|
159901
|
+
canvas2.defaultCursor = "default";
|
|
159902
|
+
canvas2.freeDrawingCursor = "default";
|
|
159903
|
+
canvas2.setCursor("default");
|
|
159904
|
+
if (canvas2.upperCanvasEl) {
|
|
159905
|
+
canvas2.upperCanvasEl.style.cursor = "default";
|
|
159906
|
+
}
|
|
159907
|
+
canvas2._isCurrentlyDrawing = false;
|
|
159908
|
+
useDrawStore.getState().setDrawTool("select");
|
|
159909
|
+
canvas2.setActiveObject(target);
|
|
159910
|
+
canvas2.requestRenderAll();
|
|
159911
|
+
}
|
|
159912
|
+
};
|
|
159913
|
+
const handlePathCreated = (e3) => {
|
|
159914
|
+
if (e3?.path) {
|
|
159915
|
+
e3.path.name = "drawing-path";
|
|
159916
|
+
e3.path.isDrawingPath = true;
|
|
159917
|
+
}
|
|
159918
|
+
};
|
|
159919
|
+
const handleSelectionChange = () => {
|
|
159920
|
+
if (useDrawStore.getState().drawTool !== "select") {
|
|
159921
|
+
useDrawStore.getState().setDrawTool("select");
|
|
159922
|
+
}
|
|
159923
|
+
if (canvas2.isDrawingMode) {
|
|
159924
|
+
canvas2.isDrawingMode = false;
|
|
159925
|
+
canvas2.selection = true;
|
|
159926
|
+
canvas2.defaultCursor = "default";
|
|
159927
|
+
canvas2.freeDrawingCursor = "default";
|
|
159928
|
+
canvas2.setCursor("default");
|
|
159929
|
+
if (canvas2.upperCanvasEl) {
|
|
159930
|
+
canvas2.upperCanvasEl.style.cursor = "default";
|
|
159931
|
+
}
|
|
159932
|
+
canvas2._isCurrentlyDrawing = false;
|
|
159933
|
+
canvas2.requestRenderAll();
|
|
159934
|
+
}
|
|
159935
|
+
};
|
|
159936
|
+
canvas2.on("mouse:down:before", handleMouseDownBefore);
|
|
159937
|
+
canvas2.on("path:created", handlePathCreated);
|
|
159938
|
+
canvas2.on("selection:created", handleSelectionChange);
|
|
159939
|
+
canvas2.on("selection:updated", handleSelectionChange);
|
|
159940
|
+
return () => {
|
|
159941
|
+
canvas2.off("mouse:down:before", handleMouseDownBefore);
|
|
159942
|
+
canvas2.off("path:created", handlePathCreated);
|
|
159943
|
+
canvas2.off("selection:created", handleSelectionChange);
|
|
159944
|
+
canvas2.off("selection:updated", handleSelectionChange);
|
|
159945
|
+
if (canvas2.upperCanvasEl) {
|
|
159946
|
+
canvas2.upperCanvasEl.style.cursor = "default";
|
|
159947
|
+
}
|
|
159948
|
+
};
|
|
159624
159949
|
}, [drawTool, strokeWidth, opacity, color]);
|
|
159625
159950
|
}
|
|
159626
159951
|
function PointerIcon() {
|
|
@@ -159651,6 +159976,89 @@ function HandIcon() {
|
|
|
159651
159976
|
/* @__PURE__ */ jsx("path", { d: "M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15" })
|
|
159652
159977
|
] });
|
|
159653
159978
|
}
|
|
159979
|
+
function GridIcon({
|
|
159980
|
+
size = 18,
|
|
159981
|
+
className = ""
|
|
159982
|
+
}) {
|
|
159983
|
+
return /* @__PURE__ */ jsxs(
|
|
159984
|
+
"svg",
|
|
159985
|
+
{
|
|
159986
|
+
width: size,
|
|
159987
|
+
height: size,
|
|
159988
|
+
viewBox: "0 0 24 24",
|
|
159989
|
+
fill: "none",
|
|
159990
|
+
stroke: "currentColor",
|
|
159991
|
+
strokeWidth: "2",
|
|
159992
|
+
strokeLinecap: "round",
|
|
159993
|
+
strokeLinejoin: "round",
|
|
159994
|
+
className,
|
|
159995
|
+
children: [
|
|
159996
|
+
/* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
|
|
159997
|
+
/* @__PURE__ */ jsx("path", { d: "M3 9h18" }),
|
|
159998
|
+
/* @__PURE__ */ jsx("path", { d: "M3 15h18" }),
|
|
159999
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3v18" }),
|
|
160000
|
+
/* @__PURE__ */ jsx("path", { d: "M15 3v18" })
|
|
160001
|
+
]
|
|
160002
|
+
}
|
|
160003
|
+
);
|
|
160004
|
+
}
|
|
160005
|
+
function getGridStep(width, height) {
|
|
160006
|
+
const minDim = Math.min(width, height);
|
|
160007
|
+
if (minDim <= 200) return 10;
|
|
160008
|
+
if (minDim <= 400) return 20;
|
|
160009
|
+
if (minDim <= 800) return 25;
|
|
160010
|
+
return 40;
|
|
160011
|
+
}
|
|
160012
|
+
function renderGrid(canvas2) {
|
|
160013
|
+
if (!canvas2) return;
|
|
160014
|
+
canvas2.getObjects().forEach((o2) => {
|
|
160015
|
+
if (o2.name === "canvas-grid") {
|
|
160016
|
+
canvas2.remove(o2);
|
|
160017
|
+
}
|
|
160018
|
+
});
|
|
160019
|
+
const showGrid = useEditorStore.getState().showGrid;
|
|
160020
|
+
if (!showGrid) {
|
|
160021
|
+
canvas2.requestRenderAll();
|
|
160022
|
+
return;
|
|
160023
|
+
}
|
|
160024
|
+
const workarea = canvas2.getObjects().find((o2) => o2.name === "workarea");
|
|
160025
|
+
if (!workarea) {
|
|
160026
|
+
canvas2.requestRenderAll();
|
|
160027
|
+
return;
|
|
160028
|
+
}
|
|
160029
|
+
const waL = workarea.left ?? 0;
|
|
160030
|
+
const waT = workarea.top ?? 0;
|
|
160031
|
+
const waW = workarea.getScaledWidth();
|
|
160032
|
+
const waH = workarea.getScaledHeight();
|
|
160033
|
+
if (waW <= 0 || waH <= 0) return;
|
|
160034
|
+
const step = getGridStep(waW, waH);
|
|
160035
|
+
let pathData = "";
|
|
160036
|
+
for (let x2 = step; x2 < waW; x2 += step) {
|
|
160037
|
+
const roundX = Math.round(x2 * 100) / 100;
|
|
160038
|
+
pathData += `M ${roundX} 0 V ${waH} `;
|
|
160039
|
+
}
|
|
160040
|
+
for (let y2 = step; y2 < waH; y2 += step) {
|
|
160041
|
+
const roundY = Math.round(y2 * 100) / 100;
|
|
160042
|
+
pathData += `M 0 ${roundY} H ${waW} `;
|
|
160043
|
+
}
|
|
160044
|
+
if (!pathData) return;
|
|
160045
|
+
const gridPath = new no(pathData, {
|
|
160046
|
+
name: "canvas-grid",
|
|
160047
|
+
left: waL,
|
|
160048
|
+
top: waT,
|
|
160049
|
+
originX: "left",
|
|
160050
|
+
originY: "top",
|
|
160051
|
+
stroke: "rgba(100, 116, 139, 0.28)",
|
|
160052
|
+
strokeWidth: 1,
|
|
160053
|
+
fill: "",
|
|
160054
|
+
selectable: false,
|
|
160055
|
+
evented: false,
|
|
160056
|
+
excludeFromExport: true
|
|
160057
|
+
});
|
|
160058
|
+
canvas2.add(gridPath);
|
|
160059
|
+
bringOverlaysToFront(canvas2);
|
|
160060
|
+
canvas2.requestRenderAll();
|
|
160061
|
+
}
|
|
159654
160062
|
function enablePanMode(canvas2) {
|
|
159655
160063
|
let isDragging = false;
|
|
159656
160064
|
let lastClientX = 0;
|
|
@@ -159918,10 +160326,11 @@ function setupHistoryRecording(canvas2) {
|
|
|
159918
160326
|
const target = e3?.target;
|
|
159919
160327
|
if (!target) return;
|
|
159920
160328
|
const name = target.name || "";
|
|
159921
|
-
if (name === "workarea" || name === "watermark" || name.startsWith("overlay-") || name.startsWith("guideline-")) {
|
|
160329
|
+
if (name === "workarea" || name === "watermark" || name === "bg-image" || name.startsWith("overlay-") || name.startsWith("guideline-") || name === "canvas-grid") {
|
|
159922
160330
|
return;
|
|
159923
160331
|
}
|
|
159924
160332
|
if (useHistoryStore.getState().isRestoring) return;
|
|
160333
|
+
flushBackgroundSave();
|
|
159925
160334
|
if (modifiedTimer) {
|
|
159926
160335
|
clearTimeout(modifiedTimer);
|
|
159927
160336
|
modifiedTimer = null;
|
|
@@ -159936,7 +160345,7 @@ function setupHistoryRecording(canvas2) {
|
|
|
159936
160345
|
const target = e3?.target;
|
|
159937
160346
|
if (!target) return;
|
|
159938
160347
|
const name = target.name || "";
|
|
159939
|
-
if (name === "workarea" || name === "watermark" || name.startsWith("overlay-") || name.startsWith("guideline-")) {
|
|
160348
|
+
if (name === "workarea" || name === "watermark" || name.startsWith("overlay-") || name.startsWith("guideline-") || name === "canvas-grid") {
|
|
159940
160349
|
return;
|
|
159941
160350
|
}
|
|
159942
160351
|
if (useHistoryStore.getState().isRestoring) return;
|
|
@@ -159959,6 +160368,12 @@ function setupHistoryRecording(canvas2) {
|
|
|
159959
160368
|
}
|
|
159960
160369
|
function setupDoublClickCrop(canvas2) {
|
|
159961
160370
|
const handleDoubleClick = (e3) => {
|
|
160371
|
+
const isCropping = useEditorStore.getState().isCropping;
|
|
160372
|
+
if (isCropping) {
|
|
160373
|
+
applyCrop(canvas2);
|
|
160374
|
+
useEditorStore.getState().stopCropping();
|
|
160375
|
+
return;
|
|
160376
|
+
}
|
|
159962
160377
|
const target = e3.target;
|
|
159963
160378
|
if (target && target.type === "image" && target.name !== "bg-image") {
|
|
159964
160379
|
useEditorStore.getState().startCropping();
|
|
@@ -160004,6 +160419,13 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160004
160419
|
canvas2.requestRenderAll();
|
|
160005
160420
|
};
|
|
160006
160421
|
canvas2.on("selection:created", (e3) => {
|
|
160422
|
+
if (useDrawStore.getState().drawTool !== "select") {
|
|
160423
|
+
useDrawStore.getState().setDrawTool("select");
|
|
160424
|
+
canvas2.isDrawingMode = false;
|
|
160425
|
+
canvas2.selection = true;
|
|
160426
|
+
canvas2.defaultCursor = "default";
|
|
160427
|
+
canvas2._isCurrentlyDrawing = false;
|
|
160428
|
+
}
|
|
160007
160429
|
if (e3.selected) {
|
|
160008
160430
|
e3.selected.forEach((o2) => {
|
|
160009
160431
|
o2.__showDegree = false;
|
|
@@ -160011,8 +160433,16 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160011
160433
|
}
|
|
160012
160434
|
updateSelection();
|
|
160013
160435
|
configureSelectionControls();
|
|
160436
|
+
bringOverlaysToFront(canvas2);
|
|
160014
160437
|
});
|
|
160015
160438
|
canvas2.on("selection:updated", (e3) => {
|
|
160439
|
+
if (useDrawStore.getState().drawTool !== "select") {
|
|
160440
|
+
useDrawStore.getState().setDrawTool("select");
|
|
160441
|
+
canvas2.isDrawingMode = false;
|
|
160442
|
+
canvas2.selection = true;
|
|
160443
|
+
canvas2.defaultCursor = "default";
|
|
160444
|
+
canvas2._isCurrentlyDrawing = false;
|
|
160445
|
+
}
|
|
160016
160446
|
const active = canvas2.getActiveObject();
|
|
160017
160447
|
const bgImg = canvas2.getObjects().find((o2) => o2.name === "bg-image");
|
|
160018
160448
|
if (bgImg && active !== bgImg) {
|
|
@@ -160033,6 +160463,7 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160033
160463
|
}
|
|
160034
160464
|
updateSelection();
|
|
160035
160465
|
configureSelectionControls();
|
|
160466
|
+
bringOverlaysToFront(canvas2);
|
|
160036
160467
|
});
|
|
160037
160468
|
canvas2.on("object:scaling", configureSelectionControls);
|
|
160038
160469
|
canvas2.on("object:rotating", (e3) => {
|
|
@@ -160049,7 +160480,12 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160049
160480
|
o2.__showDegree = false;
|
|
160050
160481
|
});
|
|
160051
160482
|
configureSelectionControls();
|
|
160483
|
+
bringOverlaysToFront(canvas2);
|
|
160484
|
+
};
|
|
160485
|
+
const handleObjectMoving = () => {
|
|
160486
|
+
bringOverlaysToFront(canvas2);
|
|
160052
160487
|
};
|
|
160488
|
+
canvas2.on("object:moving", handleObjectMoving);
|
|
160053
160489
|
canvas2.on("object:modified", hideDegree);
|
|
160054
160490
|
canvas2.on("mouse:up", hideDegree);
|
|
160055
160491
|
canvas2.on("selection:cleared", () => {
|
|
@@ -160066,6 +160502,7 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160066
160502
|
}
|
|
160067
160503
|
}
|
|
160068
160504
|
hideDegree();
|
|
160505
|
+
bringOverlaysToFront(canvas2);
|
|
160069
160506
|
clearSelection();
|
|
160070
160507
|
});
|
|
160071
160508
|
return () => {
|
|
@@ -160073,6 +160510,7 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160073
160510
|
canvas2.off("selection:updated");
|
|
160074
160511
|
canvas2.off("object:scaling", configureSelectionControls);
|
|
160075
160512
|
canvas2.off("object:rotating");
|
|
160513
|
+
canvas2.off("object:moving", handleObjectMoving);
|
|
160076
160514
|
canvas2.off("object:modified", hideDegree);
|
|
160077
160515
|
canvas2.off("mouse:up", hideDegree);
|
|
160078
160516
|
canvas2.off("selection:cleared");
|
|
@@ -160081,7 +160519,9 @@ function setupSelectionHandlers(canvas2, setSelection, clearSelection) {
|
|
|
160081
160519
|
function setupObjectAddedHandler(canvas2) {
|
|
160082
160520
|
const handleObjectAdded = (e3) => {
|
|
160083
160521
|
const obj = e3.target;
|
|
160084
|
-
if (!obj || obj.name === "workarea")
|
|
160522
|
+
if (!obj || obj.name === "workarea" || obj.name?.startsWith("overlay-") || obj.name?.startsWith("guideline-")) {
|
|
160523
|
+
return;
|
|
160524
|
+
}
|
|
160085
160525
|
configureObjectControls(obj);
|
|
160086
160526
|
bringOverlaysToFront(canvas2);
|
|
160087
160527
|
};
|
|
@@ -160575,21 +161015,27 @@ function ZoomControls({ onReset }) {
|
|
|
160575
161015
|
] }) });
|
|
160576
161016
|
}
|
|
160577
161017
|
const OFFSET = 20;
|
|
160578
|
-
function useKeyboardEvents(
|
|
161018
|
+
function useKeyboardEvents(canvasParam) {
|
|
160579
161019
|
const clipboardRef = useRef(null);
|
|
161020
|
+
const storeCanvas = useEditorStore((s2) => s2.canvas);
|
|
161021
|
+
const historyCanvas = useHistoryStore((s2) => s2.canvas);
|
|
161022
|
+
const canvas2 = canvasParam || storeCanvas || historyCanvas;
|
|
160580
161023
|
const saveState = useHistoryStore((s2) => s2.saveState);
|
|
160581
161024
|
useEffect(() => {
|
|
160582
|
-
|
|
161025
|
+
const getActiveCanvas = () => canvas2 || useEditorStore.getState().canvas || useHistoryStore.getState().canvas;
|
|
160583
161026
|
const handleCopy = async () => {
|
|
160584
|
-
const
|
|
161027
|
+
const activeCanvas = getActiveCanvas();
|
|
161028
|
+
if (!activeCanvas) return;
|
|
161029
|
+
const activeObject = activeCanvas.getActiveObject();
|
|
160585
161030
|
if (!activeObject || activeObject.name === "workarea") return;
|
|
160586
161031
|
const cloned = await activeObject.clone();
|
|
160587
161032
|
clipboardRef.current = cloned;
|
|
160588
161033
|
};
|
|
160589
161034
|
const handlePaste = async () => {
|
|
160590
|
-
|
|
161035
|
+
const activeCanvas = getActiveCanvas();
|
|
161036
|
+
if (!activeCanvas || !clipboardRef.current) return;
|
|
160591
161037
|
const clonedObj = await clipboardRef.current.clone();
|
|
160592
|
-
|
|
161038
|
+
activeCanvas.discardActiveObject();
|
|
160593
161039
|
clonedObj.set({
|
|
160594
161040
|
left: (clonedObj.left ?? 0) + OFFSET,
|
|
160595
161041
|
top: (clonedObj.top ?? 0) + OFFSET,
|
|
@@ -160600,16 +161046,17 @@ function useKeyboardEvents(canvas2) {
|
|
|
160600
161046
|
top: (clipboardRef.current.top ?? 0) + OFFSET
|
|
160601
161047
|
});
|
|
160602
161048
|
if (clonedObj.type?.toLowerCase() === "activeselection") {
|
|
160603
|
-
clonedObj.canvas =
|
|
161049
|
+
clonedObj.canvas = activeCanvas;
|
|
160604
161050
|
clonedObj.forEachObject((obj) => {
|
|
160605
|
-
|
|
161051
|
+
activeCanvas.add(obj);
|
|
160606
161052
|
});
|
|
160607
161053
|
clonedObj.setCoords();
|
|
160608
161054
|
} else {
|
|
160609
|
-
|
|
161055
|
+
activeCanvas.add(clonedObj);
|
|
160610
161056
|
}
|
|
160611
|
-
|
|
160612
|
-
|
|
161057
|
+
activeCanvas.setActiveObject(clonedObj);
|
|
161058
|
+
bringOverlaysToFront(activeCanvas);
|
|
161059
|
+
activeCanvas.requestRenderAll();
|
|
160613
161060
|
saveState();
|
|
160614
161061
|
};
|
|
160615
161062
|
const handleKeyDown = (e3) => {
|
|
@@ -160617,25 +161064,36 @@ function useKeyboardEvents(canvas2) {
|
|
|
160617
161064
|
const isInput = activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement || activeElement?.isContentEditable;
|
|
160618
161065
|
if (isInput) return;
|
|
160619
161066
|
const isModifier = e3.ctrlKey || e3.metaKey;
|
|
160620
|
-
if (isModifier
|
|
161067
|
+
if (!isModifier) return;
|
|
161068
|
+
const isZ = e3.key?.toLowerCase() === "z" || e3.code === "KeyZ";
|
|
161069
|
+
const isY = e3.key?.toLowerCase() === "y" || e3.code === "KeyY";
|
|
161070
|
+
const isC = e3.key?.toLowerCase() === "c" || e3.code === "KeyC";
|
|
161071
|
+
const isV = e3.key?.toLowerCase() === "v" || e3.code === "KeyV";
|
|
161072
|
+
if (isZ && !e3.shiftKey) {
|
|
160621
161073
|
e3.preventDefault();
|
|
160622
|
-
|
|
161074
|
+
useHistoryStore.getState().undo();
|
|
161075
|
+
return;
|
|
160623
161076
|
}
|
|
160624
|
-
if (
|
|
161077
|
+
if (isZ && e3.shiftKey || isY) {
|
|
160625
161078
|
e3.preventDefault();
|
|
160626
|
-
|
|
161079
|
+
useHistoryStore.getState().redoAction();
|
|
161080
|
+
return;
|
|
160627
161081
|
}
|
|
160628
|
-
if (
|
|
161082
|
+
if (isC) {
|
|
160629
161083
|
e3.preventDefault();
|
|
160630
|
-
|
|
160631
|
-
|
|
160632
|
-
} else {
|
|
160633
|
-
useHistoryStore.getState().undo();
|
|
160634
|
-
}
|
|
161084
|
+
handleCopy();
|
|
161085
|
+
return;
|
|
160635
161086
|
}
|
|
160636
|
-
if (
|
|
161087
|
+
if (isV) {
|
|
160637
161088
|
e3.preventDefault();
|
|
160638
|
-
|
|
161089
|
+
handlePaste();
|
|
161090
|
+
return;
|
|
161091
|
+
}
|
|
161092
|
+
const isQuote = e3.key === "'" || e3.code === "Quote";
|
|
161093
|
+
if (isQuote) {
|
|
161094
|
+
e3.preventDefault();
|
|
161095
|
+
useEditorStore.getState().toggleGrid();
|
|
161096
|
+
return;
|
|
160639
161097
|
}
|
|
160640
161098
|
};
|
|
160641
161099
|
window.addEventListener("keydown", handleKeyDown);
|
|
@@ -160651,9 +161109,14 @@ function Workspace() {
|
|
|
160651
161109
|
const workareaRef = useRef(null);
|
|
160652
161110
|
const panHandlersRef = useRef(null);
|
|
160653
161111
|
const isCropping = useEditorStore((s2) => s2.isCropping);
|
|
161112
|
+
const canvas2 = useEditorStore((s2) => s2.canvas);
|
|
160654
161113
|
const setCanvas = useEditorStore((s2) => s2.setCanvas);
|
|
161114
|
+
const showGrid = useEditorStore((s2) => s2.showGrid);
|
|
161115
|
+
const toggleGrid = useEditorStore((s2) => s2.toggleGrid);
|
|
160655
161116
|
const setSelection = useSelectionStore((s2) => s2.setSelection);
|
|
160656
161117
|
const clearSelection = useSelectionStore((s2) => s2.clearSelection);
|
|
161118
|
+
const drawTool = useDrawStore((s2) => s2.drawTool);
|
|
161119
|
+
const setDrawTool = useDrawStore((s2) => s2.setDrawTool);
|
|
160657
161120
|
const productData = useProductStore((s2) => s2.productData);
|
|
160658
161121
|
const isTwoSided = productData?.optionsMap?.printing === "4/4";
|
|
160659
161122
|
const [currentPage, setCurrentPage] = useState("front");
|
|
@@ -160703,20 +161166,20 @@ function Workspace() {
|
|
|
160703
161166
|
}
|
|
160704
161167
|
if (!isMounted || !canvasRef.current || !containerRef.current || fabricRef.current) return;
|
|
160705
161168
|
initializeRotateImage();
|
|
160706
|
-
const
|
|
160707
|
-
fabricRef.current =
|
|
160708
|
-
setCanvas(
|
|
160709
|
-
useHistoryStore.getState().setCanvas(
|
|
160710
|
-
const workarea = createWorkarea(
|
|
161169
|
+
const canvas22 = initializeCanvas(canvasRef.current, containerRef.current);
|
|
161170
|
+
fabricRef.current = canvas22;
|
|
161171
|
+
setCanvas(canvas22);
|
|
161172
|
+
useHistoryStore.getState().setCanvas(canvas22);
|
|
161173
|
+
const workarea = createWorkarea(canvas22, containerRef.current, product);
|
|
160711
161174
|
workareaRef.current = workarea;
|
|
160712
|
-
const cleanupHistory = setupHistoryRecording(
|
|
160713
|
-
const cleanupCrop = setupDoublClickCrop(
|
|
161175
|
+
const cleanupHistory = setupHistoryRecording(canvas22);
|
|
161176
|
+
const cleanupCrop = setupDoublClickCrop(canvas22);
|
|
160714
161177
|
const cleanupSelection = setupSelectionHandlers(
|
|
160715
|
-
|
|
161178
|
+
canvas22,
|
|
160716
161179
|
setSelection,
|
|
160717
161180
|
clearSelection
|
|
160718
161181
|
);
|
|
160719
|
-
const cleanupObjectAdded = setupObjectAddedHandler(
|
|
161182
|
+
const cleanupObjectAdded = setupObjectAddedHandler(canvas22);
|
|
160720
161183
|
if (isTextDesign && templateId) {
|
|
160721
161184
|
const item = await ShapeService.getTextTemplateById(templateId);
|
|
160722
161185
|
if (item?.jsonData) {
|
|
@@ -160724,7 +161187,7 @@ function Workspace() {
|
|
|
160724
161187
|
pageJSON.current.front = parsed;
|
|
160725
161188
|
await loadTemplateFontsIntoHead(null, parsed);
|
|
160726
161189
|
useHistoryStore.setState({ isRestoring: true });
|
|
160727
|
-
await loadPageToCanvas(
|
|
161190
|
+
await loadPageToCanvas(canvas22, parsed);
|
|
160728
161191
|
useHistoryStore.setState({ isRestoring: false });
|
|
160729
161192
|
useHistoryStore.getState().saveState();
|
|
160730
161193
|
}
|
|
@@ -160745,7 +161208,7 @@ function Workspace() {
|
|
|
160745
161208
|
if (frontData) {
|
|
160746
161209
|
pageJSON.current.front = frontData;
|
|
160747
161210
|
useHistoryStore.setState({ isRestoring: true });
|
|
160748
|
-
await loadPageToCanvas(
|
|
161211
|
+
await loadPageToCanvas(canvas22, frontData);
|
|
160749
161212
|
useHistoryStore.setState({ isRestoring: false });
|
|
160750
161213
|
useHistoryStore.getState().saveState();
|
|
160751
161214
|
}
|
|
@@ -160762,10 +161225,10 @@ function Workspace() {
|
|
|
160762
161225
|
cleanupCrop();
|
|
160763
161226
|
cleanupSelection();
|
|
160764
161227
|
cleanupObjectAdded();
|
|
160765
|
-
if (
|
|
160766
|
-
|
|
161228
|
+
if (canvas22.__cleanupResizeObserver) {
|
|
161229
|
+
canvas22.__cleanupResizeObserver();
|
|
160767
161230
|
}
|
|
160768
|
-
|
|
161231
|
+
canvas22.dispose();
|
|
160769
161232
|
fabricRef.current = null;
|
|
160770
161233
|
setCanvas(null);
|
|
160771
161234
|
clearSelection();
|
|
@@ -160803,23 +161266,30 @@ function Workspace() {
|
|
|
160803
161266
|
return setupBorderSync(fabricRef.current);
|
|
160804
161267
|
}, [fabricRef.current]);
|
|
160805
161268
|
useEffect(() => {
|
|
160806
|
-
const
|
|
160807
|
-
if (!
|
|
160808
|
-
removePanHandlers(
|
|
161269
|
+
const canvas22 = fabricRef.current;
|
|
161270
|
+
if (!canvas22) return;
|
|
161271
|
+
removePanHandlers(canvas22, panHandlersRef.current);
|
|
160809
161272
|
panHandlersRef.current = null;
|
|
160810
161273
|
if (isPanning) {
|
|
160811
|
-
panHandlersRef.current = enablePanMode(
|
|
161274
|
+
panHandlersRef.current = enablePanMode(canvas22);
|
|
160812
161275
|
} else {
|
|
160813
|
-
disablePanMode(
|
|
161276
|
+
disablePanMode(canvas22);
|
|
160814
161277
|
}
|
|
160815
161278
|
return () => {
|
|
160816
|
-
removePanHandlers(
|
|
161279
|
+
removePanHandlers(canvas22, panHandlersRef.current);
|
|
160817
161280
|
};
|
|
160818
161281
|
}, [isPanning]);
|
|
160819
161282
|
useFabricDrawing();
|
|
160820
|
-
useKeyboardEvents(fabricRef.current);
|
|
161283
|
+
useKeyboardEvents(canvas2 || fabricRef.current);
|
|
161284
|
+
useEffect(() => {
|
|
161285
|
+
const activeCanvas = canvas2 || fabricRef.current;
|
|
161286
|
+
if (activeCanvas) {
|
|
161287
|
+
renderGrid(activeCanvas);
|
|
161288
|
+
}
|
|
161289
|
+
}, [showGrid, canvas2, currentPage]);
|
|
160821
161290
|
const switchPage = async (page) => {
|
|
160822
161291
|
if (!fabricRef.current) return;
|
|
161292
|
+
setDrawTool("select");
|
|
160823
161293
|
await switchCanvasPage(
|
|
160824
161294
|
fabricRef.current,
|
|
160825
161295
|
currentPage,
|
|
@@ -160830,6 +161300,7 @@ function Workspace() {
|
|
|
160830
161300
|
);
|
|
160831
161301
|
useEditorStore.getState().setPages({ ...pageJSON.current });
|
|
160832
161302
|
setCurrentPage(page);
|
|
161303
|
+
renderGrid(fabricRef.current);
|
|
160833
161304
|
};
|
|
160834
161305
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
160835
161306
|
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-6 z-50 flex items-center bg-white/80 backdrop-blur-xl rounded-2xl shadow-[0_8px_32px_rgba(0,0,0,0.12)] px-1.5 py-1.5 border border-white/40 ring-1 ring-black/5", children: [
|
|
@@ -160856,20 +161327,35 @@ function Workspace() {
|
|
|
160856
161327
|
/* @__PURE__ */ jsx(
|
|
160857
161328
|
"button",
|
|
160858
161329
|
{
|
|
160859
|
-
onClick: () =>
|
|
161330
|
+
onClick: () => {
|
|
161331
|
+
setIsPanning(false);
|
|
161332
|
+
setDrawTool("select");
|
|
161333
|
+
},
|
|
160860
161334
|
title: "Selection Mode",
|
|
160861
|
-
className: `p-2 rounded-xl transition-all duration-200 ${!isPanning ? "bg-[#02bc71] text-white shadow-lg shadow-
|
|
161335
|
+
className: `p-2 rounded-xl transition-all duration-200 cursor-pointer ${!isPanning && drawTool === "select" ? "bg-[#02bc71] text-white shadow-lg shadow-green-200" : "text-gray-400 hover:bg-gray-100 hover:text-gray-600"}`,
|
|
160862
161336
|
children: /* @__PURE__ */ jsx(PointerIcon, {})
|
|
160863
161337
|
}
|
|
160864
161338
|
),
|
|
160865
161339
|
/* @__PURE__ */ jsx(
|
|
160866
161340
|
"button",
|
|
160867
161341
|
{
|
|
160868
|
-
onClick: () =>
|
|
161342
|
+
onClick: () => {
|
|
161343
|
+
setIsPanning(true);
|
|
161344
|
+
setDrawTool("select");
|
|
161345
|
+
},
|
|
160869
161346
|
title: "Hand Mode",
|
|
160870
|
-
className: `p-2 rounded-xl transition-all duration-200 ${isPanning ? "bg-[#02bc71] text-white shadow-lg shadow-
|
|
161347
|
+
className: `p-2 rounded-xl transition-all duration-200 cursor-pointer ${isPanning ? "bg-[#02bc71] text-white shadow-lg shadow-green-200" : "text-gray-400 hover:bg-gray-100 hover:text-gray-600"}`,
|
|
160871
161348
|
children: /* @__PURE__ */ jsx(HandIcon, {})
|
|
160872
161349
|
}
|
|
161350
|
+
),
|
|
161351
|
+
/* @__PURE__ */ jsx(
|
|
161352
|
+
"button",
|
|
161353
|
+
{
|
|
161354
|
+
onClick: () => toggleGrid(),
|
|
161355
|
+
title: showGrid ? "Hide Grid (Ctrl+')" : "Show Grid (Ctrl+')",
|
|
161356
|
+
className: `p-2 rounded-xl transition-all duration-200 cursor-pointer ${showGrid ? "bg-[#02bc71] text-white shadow-lg shadow-green-200" : "text-gray-400 hover:bg-gray-100 hover:text-gray-600"}`,
|
|
161357
|
+
children: /* @__PURE__ */ jsx(GridIcon, {})
|
|
161358
|
+
}
|
|
160873
161359
|
)
|
|
160874
161360
|
] }),
|
|
160875
161361
|
/* @__PURE__ */ jsx("div", { className: "w-[1px] h-6 bg-gray-300/50 mx-3" }),
|