@merchi/product-editor 0.1.9
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/.turbo/turbo-build.log +1 -0
- package/README.md +174 -0
- package/dist/components/AlignMenu.d.ts +3 -0
- package/dist/components/AlignMenu.js +61 -0
- package/dist/components/FloatingToolbar.d.ts +4 -0
- package/dist/components/FloatingToolbar.js +97 -0
- package/dist/components/FormatButtons.d.ts +2 -0
- package/dist/components/FormatButtons.js +22 -0
- package/dist/components/ImageNavButton.d.ts +7 -0
- package/dist/components/ImageNavButton.js +14 -0
- package/dist/components/ImageZoomModal.d.ts +12 -0
- package/dist/components/ImageZoomModal.js +129 -0
- package/dist/components/LayerPanel.d.ts +4 -0
- package/dist/components/LayerPanel.js +223 -0
- package/dist/components/LoadingOverlay.d.ts +9 -0
- package/dist/components/LoadingOverlay.js +17 -0
- package/dist/components/ProductEditor.d.ts +4 -0
- package/dist/components/ProductEditor.js +67 -0
- package/dist/components/ProductImageGallery.d.ts +6 -0
- package/dist/components/ProductImageGallery.js +148 -0
- package/dist/components/ProductPreviews.d.ts +7 -0
- package/dist/components/ProductPreviews.js +281 -0
- package/dist/components/TextToolbar.d.ts +4 -0
- package/dist/components/TextToolbar.js +117 -0
- package/dist/components/Toolbar.d.ts +3 -0
- package/dist/components/Toolbar.js +47 -0
- package/dist/config/colorConfig.d.ts +1 -0
- package/dist/config/colorConfig.js +10 -0
- package/dist/config/fontConfig.d.ts +5 -0
- package/dist/config/fontConfig.js +21 -0
- package/dist/context/ProductEditorContext.d.ts +60 -0
- package/dist/context/ProductEditorContext.js +743 -0
- package/dist/hooks/useSwipeNavigate.d.ts +11 -0
- package/dist/hooks/useSwipeNavigate.js +35 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +30 -0
- package/dist/styles/BottomPreviewDisplay.css +65 -0
- package/dist/styles/FloatingToolbar.css +41 -0
- package/dist/styles/ImageGallery.css +147 -0
- package/dist/styles/ImageNavButton.css +35 -0
- package/dist/styles/ImageZoomModal.css +101 -0
- package/dist/styles/LayerPanel.css +179 -0
- package/dist/styles/LoadingOverlay.css +48 -0
- package/dist/styles/ProductEditor.css +192 -0
- package/dist/styles/TextToolbar.css +327 -0
- package/dist/styles/Toolbar.css +125 -0
- package/dist/styles/index.css +5 -0
- package/dist/styles/textToolbarSelectStyles.d.ts +3 -0
- package/dist/styles/textToolbarSelectStyles.js +30 -0
- package/dist/types.d.ts +228 -0
- package/dist/types.js +17 -0
- package/dist/utils/canvasAddText.d.ts +11 -0
- package/dist/utils/canvasAddText.js +66 -0
- package/dist/utils/canvasUtils.d.ts +37 -0
- package/dist/utils/canvasUtils.js +342 -0
- package/dist/utils/deviceUtils.d.ts +5 -0
- package/dist/utils/deviceUtils.js +33 -0
- package/dist/utils/draftTemplateUtils.d.ts +23 -0
- package/dist/utils/draftTemplateUtils.js +66 -0
- package/dist/utils/grid.d.ts +32 -0
- package/dist/utils/grid.js +151 -0
- package/dist/utils/imageUtils.d.ts +12 -0
- package/dist/utils/imageUtils.js +178 -0
- package/dist/utils/job.d.ts +40 -0
- package/dist/utils/job.js +115 -0
- package/dist/utils/keyboard.d.ts +1 -0
- package/dist/utils/keyboard.js +26 -0
- package/dist/utils/previewUtils.d.ts +9 -0
- package/dist/utils/previewUtils.js +39 -0
- package/dist/utils/psdConverter.d.ts +40 -0
- package/dist/utils/psdConverter.js +516 -0
- package/dist/utils/psdRenderUtils.d.ts +12 -0
- package/dist/utils/psdRenderUtils.js +465 -0
- package/dist/utils/renderUtils.d.ts +2 -0
- package/dist/utils/renderUtils.js +85 -0
- package/package.json +66 -0
- package/src/components/AlignMenu.tsx +49 -0
- package/src/components/FloatingToolbar.tsx +83 -0
- package/src/components/FormatButtons.tsx +31 -0
- package/src/components/ImageNavButton.tsx +23 -0
- package/src/components/ImageZoomModal.tsx +163 -0
- package/src/components/LayerPanel.tsx +256 -0
- package/src/components/LoadingOverlay.tsx +27 -0
- package/src/components/ProductEditor.tsx +104 -0
- package/src/components/ProductImageGallery.tsx +181 -0
- package/src/components/ProductPreviews.tsx +243 -0
- package/src/components/TextToolbar.tsx +164 -0
- package/src/components/Toolbar.tsx +86 -0
- package/src/config/colorConfig.ts +7 -0
- package/src/config/fontConfig.ts +23 -0
- package/src/context/ProductEditorContext.tsx +829 -0
- package/src/hooks/useSwipeNavigate.ts +40 -0
- package/src/index.ts +6 -0
- package/src/styles/BottomPreviewDisplay.css +65 -0
- package/src/styles/FloatingToolbar.css +41 -0
- package/src/styles/ImageGallery.css +147 -0
- package/src/styles/ImageNavButton.css +35 -0
- package/src/styles/ImageZoomModal.css +101 -0
- package/src/styles/LayerPanel.css +179 -0
- package/src/styles/LoadingOverlay.css +48 -0
- package/src/styles/ProductEditor.css +192 -0
- package/src/styles/TextToolbar.css +327 -0
- package/src/styles/Toolbar.css +125 -0
- package/src/styles/index.css +5 -0
- package/src/styles/textToolbarSelectStyles.ts +60 -0
- package/src/types/ag-psd/index.d.ts +1 -0
- package/src/types/fabric.d.ts +14 -0
- package/src/types/lodash/index.d.ts +1 -0
- package/src/types/psd.d.ts +53 -0
- package/src/types.ts +247 -0
- package/src/utils/canvasAddText.ts +72 -0
- package/src/utils/canvasUtils.ts +406 -0
- package/src/utils/deviceUtils.ts +31 -0
- package/src/utils/draftTemplateUtils.ts +70 -0
- package/src/utils/grid.ts +154 -0
- package/src/utils/imageUtils.ts +218 -0
- package/src/utils/job.ts +128 -0
- package/src/utils/keyboard.ts +28 -0
- package/src/utils/previewUtils.ts +43 -0
- package/src/utils/psdConverter.ts +595 -0
- package/src/utils/psdRenderUtils.ts +453 -0
- package/src/utils/renderUtils.ts +44 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
50
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
51
|
+
if (ar || !(i in from)) {
|
|
52
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
53
|
+
ar[i] = from[i];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
57
|
+
};
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.loadPsdOntoCanvas = exports.extractPsdBaseLayer = void 0;
|
|
60
|
+
var fabric_1 = require("fabric");
|
|
61
|
+
var ag_psd_1 = require("ag-psd");
|
|
62
|
+
var job_1 = require("./job");
|
|
63
|
+
/**
|
|
64
|
+
* Extracts layers from a PSD file and renders them to a PNG
|
|
65
|
+
*
|
|
66
|
+
* @param psdUrl URL to the PSD file
|
|
67
|
+
* @returns Promise that resolves to a PNG data URL
|
|
68
|
+
*/
|
|
69
|
+
var extractPsdBaseLayer = function (psdUrl) { return __awaiter(void 0, void 0, void 0, function () {
|
|
70
|
+
var response, arrayBuffer, firstBytes, signature, psd, canvas, ctx, designBounds, imageData, layers, designLayer, maskLayer, contentLayers, _i, layers_1, layer, renderLayer_1, processLayer_1, _a, contentLayers_1, layer, dataUrl, blob, objectUrl_1, img_1, error_1;
|
|
71
|
+
return __generator(this, function (_b) {
|
|
72
|
+
switch (_b.label) {
|
|
73
|
+
case 0:
|
|
74
|
+
_b.trys.push([0, 3, , 4]);
|
|
75
|
+
return [4 /*yield*/, fetch(psdUrl, {
|
|
76
|
+
mode: 'cors',
|
|
77
|
+
credentials: 'same-origin',
|
|
78
|
+
headers: {
|
|
79
|
+
'Accept': '*/*',
|
|
80
|
+
}
|
|
81
|
+
})];
|
|
82
|
+
case 1:
|
|
83
|
+
response = _b.sent();
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new Error("Failed to fetch PSD file: ".concat(response.status, " ").concat(response.statusText));
|
|
86
|
+
}
|
|
87
|
+
return [4 /*yield*/, response.arrayBuffer()];
|
|
88
|
+
case 2:
|
|
89
|
+
arrayBuffer = _b.sent();
|
|
90
|
+
firstBytes = new Uint8Array(arrayBuffer, 0, 4);
|
|
91
|
+
signature = String.fromCharCode(firstBytes[0]) +
|
|
92
|
+
String.fromCharCode(firstBytes[1]) +
|
|
93
|
+
String.fromCharCode(firstBytes[2]) +
|
|
94
|
+
String.fromCharCode(firstBytes[3]);
|
|
95
|
+
if (signature !== '8BPS') {
|
|
96
|
+
// TODO handle different file types
|
|
97
|
+
console.warn('Warning: File does not have PSD signature. Got:', signature);
|
|
98
|
+
// Continue anyway - the server might be returning a different format
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
psd = (0, ag_psd_1.readPsd)(arrayBuffer, {
|
|
102
|
+
skipCompositeImageData: false,
|
|
103
|
+
skipLayerImageData: false,
|
|
104
|
+
skipThumbnail: false
|
|
105
|
+
});
|
|
106
|
+
canvas = document.createElement('canvas');
|
|
107
|
+
canvas.width = psd.width;
|
|
108
|
+
canvas.height = psd.height;
|
|
109
|
+
ctx = canvas.getContext('2d');
|
|
110
|
+
if (!ctx) {
|
|
111
|
+
throw new Error('Could not get canvas context');
|
|
112
|
+
}
|
|
113
|
+
designBounds = void 0;
|
|
114
|
+
// If there are no layers or children, try to use the document itself
|
|
115
|
+
if (!psd.children || psd.children.length === 0) {
|
|
116
|
+
if (psd.imageData) {
|
|
117
|
+
imageData = new ImageData(new Uint8ClampedArray(psd.imageData.data), psd.width, psd.height);
|
|
118
|
+
ctx.putImageData(imageData, 0, 0);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
throw new Error('No layers or composite image data found in PSD');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
layers = __spreadArray([], psd.children, true);
|
|
126
|
+
designLayer = null;
|
|
127
|
+
maskLayer = null;
|
|
128
|
+
contentLayers = [];
|
|
129
|
+
// First pass - identify special layers and regular content layers
|
|
130
|
+
for (_i = 0, layers_1 = layers; _i < layers_1.length; _i++) {
|
|
131
|
+
layer = layers_1[_i];
|
|
132
|
+
if (layer.name === 'Design') {
|
|
133
|
+
designLayer = layer;
|
|
134
|
+
// Store design layer bounds for future reference
|
|
135
|
+
if (typeof layer.left === 'number' &&
|
|
136
|
+
typeof layer.top === 'number' &&
|
|
137
|
+
typeof layer.right === 'number' &&
|
|
138
|
+
typeof layer.bottom === 'number') {
|
|
139
|
+
designBounds = {
|
|
140
|
+
left: layer.left,
|
|
141
|
+
top: layer.top,
|
|
142
|
+
right: layer.right,
|
|
143
|
+
bottom: layer.bottom
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else if (layer.name === 'Mask') {
|
|
148
|
+
maskLayer = layer;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
contentLayers.push(layer);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
renderLayer_1 = function (layer, ctx) {
|
|
155
|
+
// Check if the layer has a canvas
|
|
156
|
+
if (layer.canvas &&
|
|
157
|
+
typeof layer.left === 'number' &&
|
|
158
|
+
typeof layer.top === 'number') {
|
|
159
|
+
// Apply layer blending and opacity
|
|
160
|
+
ctx.globalAlpha = layer.opacity !== undefined ? layer.opacity : 1;
|
|
161
|
+
// Draw this layer onto the main canvas at its position
|
|
162
|
+
ctx.drawImage(layer.canvas, layer.left, layer.top);
|
|
163
|
+
// Reset alpha
|
|
164
|
+
ctx.globalAlpha = 1;
|
|
165
|
+
}
|
|
166
|
+
else if (layer.imageData &&
|
|
167
|
+
typeof layer.left === 'number' &&
|
|
168
|
+
typeof layer.top === 'number') {
|
|
169
|
+
// Create a temporary canvas for this layer
|
|
170
|
+
var layerCanvas = document.createElement('canvas');
|
|
171
|
+
var width = layer.right - layer.left;
|
|
172
|
+
var height = layer.bottom - layer.top;
|
|
173
|
+
layerCanvas.width = width;
|
|
174
|
+
layerCanvas.height = height;
|
|
175
|
+
var layerCtx = layerCanvas.getContext('2d');
|
|
176
|
+
if (layerCtx && layer.imageData) {
|
|
177
|
+
// Create an ImageData object from the PSD image data
|
|
178
|
+
var imageData = new ImageData(new Uint8ClampedArray(layer.imageData.data), width, height);
|
|
179
|
+
// Put the layer's image data on this canvas
|
|
180
|
+
layerCtx.putImageData(imageData, 0, 0);
|
|
181
|
+
// Apply layer blending and opacity
|
|
182
|
+
ctx.globalAlpha = layer.opacity !== undefined ? layer.opacity : 1;
|
|
183
|
+
// Draw this layer onto the main canvas at its position
|
|
184
|
+
ctx.drawImage(layerCanvas, layer.left, layer.top);
|
|
185
|
+
// Reset alpha
|
|
186
|
+
ctx.globalAlpha = 1;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.warn("Layer \"".concat(layer.name, "\" has no canvas or imageData"));
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
processLayer_1 = function (layer, ctx) {
|
|
194
|
+
// Skip hidden layers
|
|
195
|
+
if (layer.hidden) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// If this is a group layer with children, process its children
|
|
199
|
+
if (layer.children && layer.children.length > 0) {
|
|
200
|
+
// Process children
|
|
201
|
+
var children = __spreadArray([], layer.children, true);
|
|
202
|
+
children.forEach(function (child) { return processLayer_1(child, ctx); });
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Render the actual layer
|
|
206
|
+
renderLayer_1(layer, ctx);
|
|
207
|
+
};
|
|
208
|
+
// Render in the correct order:
|
|
209
|
+
// 1. First render the "Design" layer (margins/boundaries)
|
|
210
|
+
if (designLayer) {
|
|
211
|
+
processLayer_1(designLayer, ctx);
|
|
212
|
+
}
|
|
213
|
+
// 2. Then render all content layers
|
|
214
|
+
for (_a = 0, contentLayers_1 = contentLayers; _a < contentLayers_1.length; _a++) {
|
|
215
|
+
layer = contentLayers_1[_a];
|
|
216
|
+
processLayer_1(layer, ctx);
|
|
217
|
+
}
|
|
218
|
+
// 3. Finally render the "Mask" layer on top to hide overflow
|
|
219
|
+
if (maskLayer) {
|
|
220
|
+
processLayer_1(maskLayer, ctx);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
dataUrl = canvas.toDataURL('image/png');
|
|
224
|
+
// Return both the data URL and the design bounds if found
|
|
225
|
+
return [2 /*return*/, { dataUrl: dataUrl, designBounds: designBounds }];
|
|
226
|
+
}
|
|
227
|
+
catch (parseError) {
|
|
228
|
+
blob = new Blob([arrayBuffer], {
|
|
229
|
+
type: response.headers.get('content-type') || 'application/octet-stream'
|
|
230
|
+
});
|
|
231
|
+
objectUrl_1 = URL.createObjectURL(blob);
|
|
232
|
+
img_1 = new Image();
|
|
233
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
234
|
+
img_1.onload = function () {
|
|
235
|
+
var canvas = document.createElement('canvas');
|
|
236
|
+
canvas.width = img_1.width;
|
|
237
|
+
canvas.height = img_1.height;
|
|
238
|
+
var ctx = canvas.getContext('2d');
|
|
239
|
+
if (!ctx) {
|
|
240
|
+
reject(new Error('Could not get canvas context'));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
ctx.drawImage(img_1, 0, 0);
|
|
244
|
+
var dataUrl = canvas.toDataURL('image/png');
|
|
245
|
+
URL.revokeObjectURL(objectUrl_1);
|
|
246
|
+
resolve({ dataUrl: dataUrl });
|
|
247
|
+
};
|
|
248
|
+
img_1.onerror = function () {
|
|
249
|
+
URL.revokeObjectURL(objectUrl_1);
|
|
250
|
+
reject(new Error('Could not parse PSD or load as image'));
|
|
251
|
+
};
|
|
252
|
+
img_1.src = objectUrl_1;
|
|
253
|
+
})];
|
|
254
|
+
}
|
|
255
|
+
return [3 /*break*/, 4];
|
|
256
|
+
case 3:
|
|
257
|
+
error_1 = _b.sent();
|
|
258
|
+
throw error_1;
|
|
259
|
+
case 4: return [2 /*return*/];
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}); };
|
|
263
|
+
exports.extractPsdBaseLayer = extractPsdBaseLayer;
|
|
264
|
+
/**
|
|
265
|
+
* Loads a PSD file onto a fabric.js canvas
|
|
266
|
+
*
|
|
267
|
+
* @param canvas fabric.js Canvas instance
|
|
268
|
+
* @param psdUrl URL to the PSD file
|
|
269
|
+
* @param width Canvas width
|
|
270
|
+
* @param height Canvas height
|
|
271
|
+
* @returns Promise that resolves when the image is added to the canvas
|
|
272
|
+
*/
|
|
273
|
+
var loadPsdOntoCanvas = function (canvas, psdUrl, variations, savedObjects, width, height) { return __awaiter(void 0, void 0, void 0, function () {
|
|
274
|
+
var canvasRef_1, _a, dataUrl_1, designBounds_1, error_2;
|
|
275
|
+
return __generator(this, function (_b) {
|
|
276
|
+
switch (_b.label) {
|
|
277
|
+
case 0:
|
|
278
|
+
_b.trys.push([0, 2, , 3]);
|
|
279
|
+
canvasRef_1 = canvas;
|
|
280
|
+
// Store the current psdUrl on the canvas to help track which operation is active
|
|
281
|
+
canvasRef_1.psdUrl = psdUrl;
|
|
282
|
+
return [4 /*yield*/, (0, exports.extractPsdBaseLayer)(psdUrl)];
|
|
283
|
+
case 1:
|
|
284
|
+
_a = _b.sent(), dataUrl_1 = _a.dataUrl, designBounds_1 = _a.designBounds;
|
|
285
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
286
|
+
// Check if the canvas is still the same one that requested this operation
|
|
287
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
288
|
+
console.warn('Canvas changed or disposed during PSD processing, aborting.');
|
|
289
|
+
resolve();
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
fabric_1.fabric.Image.fromURL(dataUrl_1, function (img) {
|
|
293
|
+
// Check again if the canvas is still valid
|
|
294
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
295
|
+
console.warn('Canvas changed or disposed during image loading, aborting.');
|
|
296
|
+
resolve();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (!img || !img.width || !img.height) {
|
|
300
|
+
reject(new Error('Failed to create fabric image from PSD'));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// Scale image to fit canvas
|
|
304
|
+
var scale = Math.min(width / img.width, height / img.height);
|
|
305
|
+
// Center the image - important for design bounds calculation
|
|
306
|
+
var imgLeft = (width - img.width * scale) / 2;
|
|
307
|
+
var imgTop = (height - img.height * scale) / 2;
|
|
308
|
+
// Set image scale and position
|
|
309
|
+
img.scaleX = scale;
|
|
310
|
+
img.scaleY = scale;
|
|
311
|
+
img.left = imgLeft;
|
|
312
|
+
img.top = imgTop;
|
|
313
|
+
img.selectable = false;
|
|
314
|
+
img.evented = false;
|
|
315
|
+
// Add image to canvas - check canvas validity first
|
|
316
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
317
|
+
console.warn('Canvas changed or disposed before adding image, aborting.');
|
|
318
|
+
resolve();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
canvasRef_1.add(img);
|
|
322
|
+
// If we have design bounds, store them for reference
|
|
323
|
+
if (designBounds_1) {
|
|
324
|
+
// Calculate scaled design bounds
|
|
325
|
+
var scaledDesignBounds_1 = {
|
|
326
|
+
left: imgLeft + (designBounds_1.left * scale),
|
|
327
|
+
top: imgTop + (designBounds_1.top * scale),
|
|
328
|
+
width: (designBounds_1.right - designBounds_1.left) * scale,
|
|
329
|
+
height: (designBounds_1.bottom - designBounds_1.top) * scale,
|
|
330
|
+
right: imgLeft + (designBounds_1.right * scale),
|
|
331
|
+
bottom: imgTop + (designBounds_1.bottom * scale)
|
|
332
|
+
};
|
|
333
|
+
// Check canvas validity before continuing
|
|
334
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
335
|
+
console.warn('Canvas changed or disposed before adding design bounds, aborting.');
|
|
336
|
+
resolve();
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
// Store on the canvas for future reference
|
|
340
|
+
canvasRef_1.designBounds = scaledDesignBounds_1;
|
|
341
|
+
// Add a visual indicator of the design area
|
|
342
|
+
var boundaryRect = new fabric_1.fabric.Rect({
|
|
343
|
+
left: scaledDesignBounds_1.left,
|
|
344
|
+
top: scaledDesignBounds_1.top,
|
|
345
|
+
width: scaledDesignBounds_1.width,
|
|
346
|
+
height: scaledDesignBounds_1.height,
|
|
347
|
+
fill: 'transparent',
|
|
348
|
+
stroke: 'rgba(255, 0, 0, 0.5)',
|
|
349
|
+
strokeWidth: 1,
|
|
350
|
+
strokeDashArray: [5, 5],
|
|
351
|
+
selectable: false,
|
|
352
|
+
evented: false,
|
|
353
|
+
id: 'design-boundary-rect'
|
|
354
|
+
});
|
|
355
|
+
// Check canvas validity before adding rect
|
|
356
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
357
|
+
console.warn('Canvas changed or disposed before adding boundary rect, aborting.');
|
|
358
|
+
resolve();
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
canvasRef_1.add(boundaryRect);
|
|
362
|
+
// Create a clip path for the text based on design bounds
|
|
363
|
+
var clipPath_1 = new fabric_1.fabric.Rect({
|
|
364
|
+
left: scaledDesignBounds_1.left,
|
|
365
|
+
top: scaledDesignBounds_1.top,
|
|
366
|
+
width: scaledDesignBounds_1.width,
|
|
367
|
+
height: scaledDesignBounds_1.height,
|
|
368
|
+
absolutePositioned: true
|
|
369
|
+
});
|
|
370
|
+
// Convert variations into canvas objects which obay the design bounds here
|
|
371
|
+
if (variations && variations.length > 0) {
|
|
372
|
+
// Process each variation to create appropriate canvas objects
|
|
373
|
+
variations.forEach(function (variation) {
|
|
374
|
+
if (!variation) {
|
|
375
|
+
return; // Skip invalid variations
|
|
376
|
+
}
|
|
377
|
+
// Get common positioning within design bounds
|
|
378
|
+
var objectLeft = scaledDesignBounds_1.left + scaledDesignBounds_1.width / 2;
|
|
379
|
+
var objectTop = scaledDesignBounds_1.top + scaledDesignBounds_1.height / 2;
|
|
380
|
+
// Extract the field type and value from the variation
|
|
381
|
+
var canvasObjectType = variation.canvasObjectType, file = variation.file, fieldId = variation.fieldId, fontFamily = variation.fontFamily, fontSize = variation.fontSize;
|
|
382
|
+
var value = variation.value;
|
|
383
|
+
// Check if this variation exists in savedObjects
|
|
384
|
+
var savedObject = savedObjects.find(function (obj) { return obj.fieldId === fieldId; });
|
|
385
|
+
// Create canvas
|
|
386
|
+
var canvasObject;
|
|
387
|
+
// Handle text variations
|
|
388
|
+
if (canvasObjectType === 'text') {
|
|
389
|
+
// Create the text object with either saved or defaults
|
|
390
|
+
if (savedObject) {
|
|
391
|
+
// Create text with default first
|
|
392
|
+
canvasObject = new fabric_1.fabric.IText((value === null || value === void 0 ? void 0 : value.toString()) || 'Text', __assign(__assign({}, savedObject), { left: savedObject.left || objectLeft, top: savedObject.top || objectTop, fontFamily: savedObject.fontFamily || fontFamily, fontSize: savedObject.fontSize || fontSize, fill: savedObject.fill || '#000000', originX: savedObject.originX || 'center', originY: savedObject.originY || 'center', selectable: true, editable: true, text: value === null || value === void 0 ? void 0 : value.toString(), scaleX: savedObject.scaleX || 1, scaleY: savedObject.scaleY || 1, angle: savedObject.angle || 0 }));
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
// Create with default properties
|
|
396
|
+
canvasObject = new fabric_1.fabric.IText((value === null || value === void 0 ? void 0 : value.toString()) || 'Text', {
|
|
397
|
+
left: objectLeft,
|
|
398
|
+
top: objectTop,
|
|
399
|
+
fontFamily: fontFamily,
|
|
400
|
+
fontSize: fontSize,
|
|
401
|
+
fill: '#000000',
|
|
402
|
+
originX: 'center',
|
|
403
|
+
originY: 'center',
|
|
404
|
+
selectable: true,
|
|
405
|
+
editable: false,
|
|
406
|
+
text: value === null || value === void 0 ? void 0 : value.toString(),
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
// Store fieldId as a custom property
|
|
410
|
+
canvasObject.fieldId = fieldId;
|
|
411
|
+
// Store uniqueId if it exists in the saved object
|
|
412
|
+
canvasObject.uniqueId = (savedObject === null || savedObject === void 0 ? void 0 : savedObject.uniqueId) || (0, job_1.generateUniqueId)();
|
|
413
|
+
// Apply the clip path to the text
|
|
414
|
+
// Omit clip path for now to restore movability
|
|
415
|
+
canvasObject.clipPath = clipPath_1;
|
|
416
|
+
canvasRef_1.add(canvasObject);
|
|
417
|
+
}
|
|
418
|
+
// Handle image variations
|
|
419
|
+
else if (canvasObjectType === "image") {
|
|
420
|
+
// Get the file ID for comparison with saved objects
|
|
421
|
+
var fileId_1 = file === null || file === void 0 ? void 0 : file.id;
|
|
422
|
+
// Find by both fieldId and fileId for images
|
|
423
|
+
var savedImageObject_1 = fileId_1 ?
|
|
424
|
+
savedObjects.find(function (obj) { return obj.fieldId === fieldId && obj.fileId === fileId_1; }) :
|
|
425
|
+
savedObject;
|
|
426
|
+
if (file && file.viewUrl) {
|
|
427
|
+
fabric_1.fabric.Image.fromURL(file.viewUrl, function (img) {
|
|
428
|
+
if (!img)
|
|
429
|
+
return;
|
|
430
|
+
// Default scaling to fit design bounds
|
|
431
|
+
var maxWidth = scaledDesignBounds_1.width * 0.8;
|
|
432
|
+
var maxHeight = scaledDesignBounds_1.height * 0.8;
|
|
433
|
+
var defaultScale = Math.min(maxWidth / img.width, maxHeight / img.height, 1);
|
|
434
|
+
if (savedImageObject_1) {
|
|
435
|
+
// Apply saved properties
|
|
436
|
+
img.set(__assign(__assign({}, savedImageObject_1), { left: savedImageObject_1.left || objectLeft, top: savedImageObject_1.top || objectTop, scaleX: savedImageObject_1.scaleX || defaultScale, scaleY: savedImageObject_1.scaleY || defaultScale, angle: savedImageObject_1.angle || 0, originX: savedImageObject_1.originX || 'center', originY: savedImageObject_1.originY || 'center', cornerSize: 8, borderColor: '#303DBF', cornerColor: '#303DBF', cornerStrokeColor: '#303DBF', transparentCorners: false, selectable: true, crossOrigin: 'anonymous' }));
|
|
437
|
+
// Store uniqueId if it exists
|
|
438
|
+
img.uniqueId = (savedImageObject_1 === null || savedImageObject_1 === void 0 ? void 0 : savedImageObject_1.uniqueId) || (0, job_1.generateUniqueId)();
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
// Apply default properties
|
|
442
|
+
img.scale(defaultScale);
|
|
443
|
+
img.set({
|
|
444
|
+
left: objectLeft,
|
|
445
|
+
top: objectTop,
|
|
446
|
+
originX: 'center',
|
|
447
|
+
originY: 'center',
|
|
448
|
+
cornerSize: 8,
|
|
449
|
+
borderColor: '#303DBF',
|
|
450
|
+
cornerColor: '#303DBF',
|
|
451
|
+
cornerStrokeColor: '#303DBF',
|
|
452
|
+
transparentCorners: false,
|
|
453
|
+
selectable: true,
|
|
454
|
+
crossOrigin: 'anonymous',
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
// Store fieldId and fileId as custom properties
|
|
458
|
+
img.fieldId = fieldId;
|
|
459
|
+
if (fileId_1) {
|
|
460
|
+
img.fileId = fileId_1;
|
|
461
|
+
}
|
|
462
|
+
img.uniqueId = (0, job_1.generateUniqueId)();
|
|
463
|
+
// Apply clip path
|
|
464
|
+
var imageClipPath = new fabric_1.fabric.Rect({
|
|
465
|
+
left: scaledDesignBounds_1.left,
|
|
466
|
+
top: scaledDesignBounds_1.top,
|
|
467
|
+
width: scaledDesignBounds_1.width,
|
|
468
|
+
height: scaledDesignBounds_1.height,
|
|
469
|
+
absolutePositioned: true
|
|
470
|
+
});
|
|
471
|
+
img.clipPath = imageClipPath;
|
|
472
|
+
// Check canvas validity before adding
|
|
473
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
canvasRef_1.add(img);
|
|
477
|
+
canvasRef_1.renderAll();
|
|
478
|
+
}, { crossOrigin: 'anonymous' });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
// Check canvas validity before adding text
|
|
484
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
485
|
+
console.warn('Canvas changed or disposed before adding test text, aborting.');
|
|
486
|
+
resolve();
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
// Final check before renderAll
|
|
491
|
+
if (!canvasRef_1 || canvasRef_1.psdUrl !== psdUrl) {
|
|
492
|
+
console.warn('Canvas changed or disposed before final render, aborting.');
|
|
493
|
+
resolve();
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
// Try to render the canvas, with error handling
|
|
497
|
+
try {
|
|
498
|
+
if (canvasRef_1 && canvasRef_1.renderAll) {
|
|
499
|
+
canvasRef_1.renderAll();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
catch (e) {
|
|
503
|
+
console.error('Error rendering canvas:', e);
|
|
504
|
+
}
|
|
505
|
+
resolve();
|
|
506
|
+
}, { crossOrigin: 'anonymous' });
|
|
507
|
+
})];
|
|
508
|
+
case 2:
|
|
509
|
+
error_2 = _b.sent();
|
|
510
|
+
console.error('Error loading PSD onto canvas:', error_2);
|
|
511
|
+
throw error_2;
|
|
512
|
+
case 3: return [2 /*return*/];
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
}); };
|
|
516
|
+
exports.loadPsdOntoCanvas = loadPsdOntoCanvas;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MappedPreview } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Process mapped previews, replacing layers in PSD files with rendered layers
|
|
4
|
+
* and converting the results to PNG images
|
|
5
|
+
*
|
|
6
|
+
* @param mappedPreviews Array of mapped previews with draftPreview and draftPreviewLayers
|
|
7
|
+
* @returns Promise that resolves to an array of processed previews with PNG data URLs
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderDraftPreviewsWithLayers(mappedPreviews: MappedPreview[]): Promise<Array<{
|
|
10
|
+
draftPreviewId: number | undefined;
|
|
11
|
+
pngDataUrl: string;
|
|
12
|
+
}>>;
|