labellife-design-tool 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -1
- package/dist/lib/index.css +42 -0
- package/dist/lib/lib/index.js +159 -17
- package/dist/lib/wordpress.js +159 -17
- package/dist/types/CanvasEditor.d.ts.map +1 -1
- package/dist/types/lib/index.d.ts +2 -1
- package/dist/types/lib/index.d.ts.map +1 -1
- package/dist/types/panels/ExportPanel.d.ts +1 -0
- package/dist/types/panels/ExportPanel.d.ts.map +1 -1
- package/dist/types/utils/exportImportUtils.d.ts +96 -0
- package/dist/types/utils/exportImportUtils.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -128,7 +128,8 @@ import {
|
|
|
128
128
|
exportToJPG,
|
|
129
129
|
exportToJSON,
|
|
130
130
|
canvasToBlob,
|
|
131
|
-
importFromJSON
|
|
131
|
+
importFromJSON,
|
|
132
|
+
importFromJSONData
|
|
132
133
|
} from 'labellife-design-tool';
|
|
133
134
|
import type { CanvasElement } from 'labellife-design-tool';
|
|
134
135
|
|
|
@@ -143,6 +144,122 @@ function MyEditor() {
|
|
|
143
144
|
}
|
|
144
145
|
```
|
|
145
146
|
|
|
147
|
+
### Template Import
|
|
148
|
+
|
|
149
|
+
The library provides two ways to import template designs:
|
|
150
|
+
|
|
151
|
+
#### File-Based Import
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { importFromJSON } from 'labellife-design-tool';
|
|
155
|
+
|
|
156
|
+
// Use with file input
|
|
157
|
+
function handleFileImport(event) {
|
|
158
|
+
importFromJSON(
|
|
159
|
+
event,
|
|
160
|
+
(design) => {
|
|
161
|
+
console.log('Design loaded:', design);
|
|
162
|
+
// Use the design
|
|
163
|
+
},
|
|
164
|
+
(error) => {
|
|
165
|
+
alert('Import failed: ' + error);
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Direct JSON Data Import
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { importFromJSONData } from 'labellife-design-tool';
|
|
175
|
+
|
|
176
|
+
// Import JSON data directly (no file needed)
|
|
177
|
+
const templateData = {
|
|
178
|
+
width: 800,
|
|
179
|
+
height: 600,
|
|
180
|
+
pages: [{
|
|
181
|
+
id: "1",
|
|
182
|
+
name: "Page 1",
|
|
183
|
+
elements: [
|
|
184
|
+
{
|
|
185
|
+
type: "text",
|
|
186
|
+
text: "Hello World",
|
|
187
|
+
x: 100,
|
|
188
|
+
y: 100,
|
|
189
|
+
fontSize: 24
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
background: "white"
|
|
193
|
+
}]
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
importFromJSONData(
|
|
197
|
+
templateData,
|
|
198
|
+
(design) => {
|
|
199
|
+
console.log('Design loaded:', design);
|
|
200
|
+
// Use the design in CanvasEditor
|
|
201
|
+
},
|
|
202
|
+
(error) => {
|
|
203
|
+
console.error('Import failed:', error);
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### Import from API
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
// Load template from API
|
|
212
|
+
async function loadTemplateFromAPI(templateId: string) {
|
|
213
|
+
try {
|
|
214
|
+
const response = await fetch(`/api/templates/${templateId}`);
|
|
215
|
+
const templateData = await response.json();
|
|
216
|
+
|
|
217
|
+
importFromJSONData(
|
|
218
|
+
templateData,
|
|
219
|
+
(design) => {
|
|
220
|
+
// Template loaded successfully
|
|
221
|
+
setDesign(design);
|
|
222
|
+
},
|
|
223
|
+
(error) => {
|
|
224
|
+
alert('Failed to load template: ' + error);
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error('API error:', error);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### Import with User Inputs
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
importFromJSONData(
|
|
237
|
+
templateData,
|
|
238
|
+
(design) => {
|
|
239
|
+
// Design loaded with user inputs applied
|
|
240
|
+
setDesign(design);
|
|
241
|
+
},
|
|
242
|
+
(error) => {
|
|
243
|
+
alert('Import failed: ' + error);
|
|
244
|
+
},
|
|
245
|
+
(inputs, onComplete) => {
|
|
246
|
+
// Show custom input modal
|
|
247
|
+
showInputModal(inputs, (values) => {
|
|
248
|
+
onComplete(values);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Comparison:**
|
|
255
|
+
|
|
256
|
+
| Feature | `importFromJSON` | `importFromJSONData` |
|
|
257
|
+
|---------|------------------|---------------------|
|
|
258
|
+
| **Input Source** | File upload event | JSON data object |
|
|
259
|
+
| **File Reading** | Built-in FileReader | Not needed |
|
|
260
|
+
| **Use Case** | User file uploads | API data, database, programmatic imports |
|
|
261
|
+
| **Processing** | Identical | Identical |
|
|
262
|
+
|
|
146
263
|
### Canvas to Blob Export
|
|
147
264
|
|
|
148
265
|
The library provides a flexible `canvasToBlob` function that allows converting the canvas to a Blob for various use cases:
|
package/dist/lib/index.css
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
--color-red-500: oklch(63.7% 0.237 25.331);
|
|
12
12
|
--color-red-600: oklch(57.7% 0.245 27.325);
|
|
13
13
|
--color-red-700: oklch(50.5% 0.213 27.518);
|
|
14
|
+
--color-green-600: oklch(62.7% 0.194 149.214);
|
|
15
|
+
--color-green-700: oklch(52.7% 0.154 150.069);
|
|
14
16
|
--color-blue-400: oklch(70.7% 0.165 254.624);
|
|
15
17
|
--color-blue-500: oklch(62.3% 0.214 259.815);
|
|
16
18
|
--color-blue-600: oklch(54.6% 0.245 262.881);
|
|
@@ -215,6 +217,12 @@
|
|
|
215
217
|
.inset-0 {
|
|
216
218
|
inset: calc(var(--spacing) * 0);
|
|
217
219
|
}
|
|
220
|
+
.-top-1 {
|
|
221
|
+
top: calc(var(--spacing) * -1);
|
|
222
|
+
}
|
|
223
|
+
.-right-1 {
|
|
224
|
+
right: calc(var(--spacing) * -1);
|
|
225
|
+
}
|
|
218
226
|
.bottom-4 {
|
|
219
227
|
bottom: calc(var(--spacing) * 4);
|
|
220
228
|
}
|
|
@@ -257,6 +265,9 @@
|
|
|
257
265
|
.mt-2 {
|
|
258
266
|
margin-top: calc(var(--spacing) * 2);
|
|
259
267
|
}
|
|
268
|
+
.mt-4 {
|
|
269
|
+
margin-top: calc(var(--spacing) * 4);
|
|
270
|
+
}
|
|
260
271
|
.mt-6 {
|
|
261
272
|
margin-top: calc(var(--spacing) * 6);
|
|
262
273
|
}
|
|
@@ -320,6 +331,9 @@
|
|
|
320
331
|
.h-12 {
|
|
321
332
|
height: calc(var(--spacing) * 12);
|
|
322
333
|
}
|
|
334
|
+
.h-64 {
|
|
335
|
+
height: calc(var(--spacing) * 64);
|
|
336
|
+
}
|
|
323
337
|
.h-full {
|
|
324
338
|
height: 100%;
|
|
325
339
|
}
|
|
@@ -329,6 +343,9 @@
|
|
|
329
343
|
.max-h-32 {
|
|
330
344
|
max-height: calc(var(--spacing) * 32);
|
|
331
345
|
}
|
|
346
|
+
.max-h-\[80vh\] {
|
|
347
|
+
max-height: 80vh;
|
|
348
|
+
}
|
|
332
349
|
.max-h-\[90vh\] {
|
|
333
350
|
max-height: 90vh;
|
|
334
351
|
}
|
|
@@ -395,6 +412,9 @@
|
|
|
395
412
|
.resize {
|
|
396
413
|
resize: both;
|
|
397
414
|
}
|
|
415
|
+
.resize-none {
|
|
416
|
+
resize: none;
|
|
417
|
+
}
|
|
398
418
|
.grid-cols-2 {
|
|
399
419
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
400
420
|
}
|
|
@@ -419,6 +439,9 @@
|
|
|
419
439
|
.justify-center {
|
|
420
440
|
justify-content: center;
|
|
421
441
|
}
|
|
442
|
+
.justify-end {
|
|
443
|
+
justify-content: flex-end;
|
|
444
|
+
}
|
|
422
445
|
.gap-2 {
|
|
423
446
|
gap: calc(var(--spacing) * 2);
|
|
424
447
|
}
|
|
@@ -482,6 +505,9 @@
|
|
|
482
505
|
text-overflow: ellipsis;
|
|
483
506
|
white-space: nowrap;
|
|
484
507
|
}
|
|
508
|
+
.overflow-auto {
|
|
509
|
+
overflow: auto;
|
|
510
|
+
}
|
|
485
511
|
.overflow-hidden {
|
|
486
512
|
overflow: hidden;
|
|
487
513
|
}
|
|
@@ -570,6 +596,12 @@
|
|
|
570
596
|
.bg-gray-900 {
|
|
571
597
|
background-color: var(--color-gray-900);
|
|
572
598
|
}
|
|
599
|
+
.bg-green-600 {
|
|
600
|
+
background-color: var(--color-green-600);
|
|
601
|
+
}
|
|
602
|
+
.bg-red-500 {
|
|
603
|
+
background-color: var(--color-red-500);
|
|
604
|
+
}
|
|
573
605
|
.bg-red-700 {
|
|
574
606
|
background-color: var(--color-red-700);
|
|
575
607
|
}
|
|
@@ -636,6 +668,9 @@
|
|
|
636
668
|
.text-right {
|
|
637
669
|
text-align: right;
|
|
638
670
|
}
|
|
671
|
+
.font-mono {
|
|
672
|
+
font-family: var(--font-mono);
|
|
673
|
+
}
|
|
639
674
|
.text-2xl {
|
|
640
675
|
font-size: var(--text-2xl);
|
|
641
676
|
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
|
@@ -828,6 +863,13 @@
|
|
|
828
863
|
}
|
|
829
864
|
}
|
|
830
865
|
}
|
|
866
|
+
.hover\:bg-green-700 {
|
|
867
|
+
&:hover {
|
|
868
|
+
@media (hover: hover) {
|
|
869
|
+
background-color: var(--color-green-700);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
831
873
|
.hover\:bg-red-500 {
|
|
832
874
|
&:hover {
|
|
833
875
|
@media (hover: hover) {
|
package/dist/lib/lib/index.js
CHANGED
|
@@ -26,7 +26,8 @@ function initJsxCompat() {
|
|
|
26
26
|
import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
|
|
27
27
|
import { Stage, Layer, Rect as Rect2 } from "react-konva";
|
|
28
28
|
import {
|
|
29
|
-
PlusCircle
|
|
29
|
+
PlusCircle,
|
|
30
|
+
X as X2
|
|
30
31
|
} from "lucide-react";
|
|
31
32
|
|
|
32
33
|
// src/elements/EditableTextElement.tsx
|
|
@@ -1964,7 +1965,8 @@ var ExportPanel = ({
|
|
|
1964
1965
|
onExportToPNG,
|
|
1965
1966
|
onExportToJPG,
|
|
1966
1967
|
onExportToJSON,
|
|
1967
|
-
onImportJSON
|
|
1968
|
+
onImportJSON,
|
|
1969
|
+
onLoadJSON
|
|
1968
1970
|
}) => {
|
|
1969
1971
|
return /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("h3", {
|
|
1970
1972
|
className: "text-white font-semibold mb-4"
|
|
@@ -1982,7 +1984,10 @@ var ExportPanel = ({
|
|
|
1982
1984
|
}, "Export as JSON"), /* @__PURE__ */ React15.createElement("button", {
|
|
1983
1985
|
onClick: onImportJSON,
|
|
1984
1986
|
className: "w-full p-3 bg-gray-700 text-white rounded hover:bg-gray-600"
|
|
1985
|
-
}, "Import JSON")
|
|
1987
|
+
}, "Import JSON"), onLoadJSON && /* @__PURE__ */ React15.createElement("button", {
|
|
1988
|
+
onClick: onLoadJSON,
|
|
1989
|
+
className: "w-full p-3 bg-green-600 text-white rounded hover:bg-green-700"
|
|
1990
|
+
}, "Load JSON")));
|
|
1986
1991
|
};
|
|
1987
1992
|
var ExportPanel_default = ExportPanel;
|
|
1988
1993
|
|
|
@@ -2161,6 +2166,12 @@ function convertTemplateToCanvasDesign(json) {
|
|
|
2161
2166
|
if (!converted.name) {
|
|
2162
2167
|
converted.name = json.name || "Imported Design";
|
|
2163
2168
|
}
|
|
2169
|
+
if (converted.width === "auto" || !converted.width) {
|
|
2170
|
+
converted.width = 800;
|
|
2171
|
+
}
|
|
2172
|
+
if (converted.height === "auto" || !converted.height) {
|
|
2173
|
+
converted.height = 600;
|
|
2174
|
+
}
|
|
2164
2175
|
if (!converted.fonts) {
|
|
2165
2176
|
converted.fonts = [];
|
|
2166
2177
|
}
|
|
@@ -2172,11 +2183,19 @@ function convertTemplateToCanvasDesign(json) {
|
|
|
2172
2183
|
}
|
|
2173
2184
|
if (converted.pages && Array.isArray(converted.pages)) {
|
|
2174
2185
|
converted.pages = converted.pages.map((page, index) => {
|
|
2186
|
+
const pageWidth = page.width === "auto" || !page.width ? converted.width : page.width;
|
|
2187
|
+
const pageHeight = page.height === "auto" || !page.height ? converted.height : page.height;
|
|
2175
2188
|
const elements = (page.elements || page.children || []).map((element) => {
|
|
2189
|
+
let elementType = element.type;
|
|
2190
|
+
let shapeType = element.shapeType;
|
|
2191
|
+
if (element.type === "figure" && element.subType) {
|
|
2192
|
+
elementType = "shape";
|
|
2193
|
+
shapeType = element.subType;
|
|
2194
|
+
}
|
|
2176
2195
|
return {
|
|
2177
2196
|
...element,
|
|
2178
2197
|
id: element.id || `${Date.now()}-${Math.random()}`,
|
|
2179
|
-
type:
|
|
2198
|
+
type: elementType || "text",
|
|
2180
2199
|
name: element.name || "Untitled",
|
|
2181
2200
|
x: element.x ?? 0,
|
|
2182
2201
|
y: element.y ?? 0,
|
|
@@ -2200,7 +2219,7 @@ function convertTemplateToCanvasDesign(json) {
|
|
|
2200
2219
|
cornerRadius: element.cornerRadius,
|
|
2201
2220
|
filters: element.filters,
|
|
2202
2221
|
mask: element.mask,
|
|
2203
|
-
shapeType
|
|
2222
|
+
shapeType,
|
|
2204
2223
|
align: element.align,
|
|
2205
2224
|
lineHeight: element.lineHeight,
|
|
2206
2225
|
letterSpacing: element.letterSpacing,
|
|
@@ -2435,6 +2454,9 @@ function replaceUserInputs(design, collectedInputs) {
|
|
|
2435
2454
|
return defaultSize;
|
|
2436
2455
|
};
|
|
2437
2456
|
unusedInputs.forEach(([inputId, value]) => {
|
|
2457
|
+
if (!value || value === "" || value === "undefined" || value === "null") {
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2438
2460
|
if ((inputId === "optionalImage" || inputId.toLowerCase().includes("image")) && typeof value === "string") {
|
|
2439
2461
|
const imageProps = processImageElement(value);
|
|
2440
2462
|
newElements.push({
|
|
@@ -2567,6 +2589,22 @@ var canvasToBlob = (stage, format = "png", options) => {
|
|
|
2567
2589
|
resolve(new Blob([arrayBuffer], { type: mimeType }));
|
|
2568
2590
|
});
|
|
2569
2591
|
};
|
|
2592
|
+
var importFromJSONData = (jsonData, onLoad, onError, onInputsRequired) => {
|
|
2593
|
+
try {
|
|
2594
|
+
const convertedDesign = convertTemplateToCanvasDesign(jsonData);
|
|
2595
|
+
const requiredInputs = findRequiredInputs(convertedDesign);
|
|
2596
|
+
if (requiredInputs.length > 0 && onInputsRequired) {
|
|
2597
|
+
onInputsRequired(requiredInputs, (collectedValues) => {
|
|
2598
|
+
const finalDesign = replaceUserInputs(convertedDesign, collectedValues);
|
|
2599
|
+
onLoad(finalDesign);
|
|
2600
|
+
});
|
|
2601
|
+
} else {
|
|
2602
|
+
onLoad(convertedDesign);
|
|
2603
|
+
}
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
onError(`Invalid JSON data: ${error instanceof Error ? error.message : String(error)}`);
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2570
2608
|
var importFromJSON = (event, onLoad, onError, onInputsRequired) => {
|
|
2571
2609
|
const file = event.target.files?.[0];
|
|
2572
2610
|
if (file) {
|
|
@@ -3019,6 +3057,8 @@ var CanvasEditor = forwardRef(({
|
|
|
3019
3057
|
const [historyIndex, setHistoryIndex] = useState3(-1);
|
|
3020
3058
|
const [showInputModal, setShowInputModal] = useState3(false);
|
|
3021
3059
|
const [pendingInputs, setPendingInputs] = useState3([]);
|
|
3060
|
+
const [showJsonModal, setShowJsonModal] = useState3(false);
|
|
3061
|
+
const [jsonInputText, setJsonInputText] = useState3("");
|
|
3022
3062
|
const stageRef = useRef5(null);
|
|
3023
3063
|
useImperativeHandle(ref, () => ({
|
|
3024
3064
|
stage: stageRef.current,
|
|
@@ -3224,15 +3264,35 @@ var CanvasEditor = forwardRef(({
|
|
|
3224
3264
|
}, [design.pages.length]);
|
|
3225
3265
|
const deletePage = useCallback4((pageId) => {
|
|
3226
3266
|
if (design.pages.length > 1) {
|
|
3227
|
-
setDesign((prev) =>
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3267
|
+
setDesign((prev) => {
|
|
3268
|
+
const filteredPages = prev.pages.filter((p) => p.id !== pageId);
|
|
3269
|
+
const renamedPages = filteredPages.map((p, idx) => ({
|
|
3270
|
+
...p,
|
|
3271
|
+
name: `Page ${idx + 1}`
|
|
3272
|
+
}));
|
|
3273
|
+
return {
|
|
3274
|
+
...prev,
|
|
3275
|
+
pages: renamedPages
|
|
3276
|
+
};
|
|
3277
|
+
});
|
|
3231
3278
|
if (currentPageId === pageId) {
|
|
3232
|
-
|
|
3279
|
+
const remainingPages = design.pages.filter((p) => p.id !== pageId);
|
|
3280
|
+
if (remainingPages.length > 0) {
|
|
3281
|
+
setCurrentPageId(remainingPages[0].id);
|
|
3282
|
+
}
|
|
3233
3283
|
}
|
|
3284
|
+
setTimeout(() => {
|
|
3285
|
+
const updatedDesign = {
|
|
3286
|
+
...design,
|
|
3287
|
+
pages: design.pages.filter((p) => p.id !== pageId).map((p, idx) => ({
|
|
3288
|
+
...p,
|
|
3289
|
+
name: `Page ${idx + 1}`
|
|
3290
|
+
}))
|
|
3291
|
+
};
|
|
3292
|
+
saveToHistory(updatedDesign);
|
|
3293
|
+
}, 0);
|
|
3234
3294
|
}
|
|
3235
|
-
}, [design.pages, currentPageId]);
|
|
3295
|
+
}, [design.pages, currentPageId, design, saveToHistory]);
|
|
3236
3296
|
const handleImageUpload = useCallback4((e) => {
|
|
3237
3297
|
const file = e.target.files?.[0];
|
|
3238
3298
|
if (file) {
|
|
@@ -3364,14 +3424,27 @@ var CanvasEditor = forwardRef(({
|
|
|
3364
3424
|
setUnsplashResults([]);
|
|
3365
3425
|
setUnsplashMode("element");
|
|
3366
3426
|
}, [currentPageId, saveToHistory, unsplashMode]);
|
|
3427
|
+
const calculateFitToScreenZoom = useCallback4((canvasWidth, canvasHeight) => {
|
|
3428
|
+
const viewportWidth = window.innerWidth - 320;
|
|
3429
|
+
const viewportHeight = window.innerHeight - 200;
|
|
3430
|
+
const scaleX = viewportWidth / canvasWidth;
|
|
3431
|
+
const scaleY = viewportHeight / canvasHeight;
|
|
3432
|
+
const optimalScale = Math.min(scaleX, scaleY, 1);
|
|
3433
|
+
return Math.max(0.1, Math.min(3, optimalScale));
|
|
3434
|
+
}, []);
|
|
3367
3435
|
const handleImportJSON = (event) => {
|
|
3368
3436
|
importFromJSON(event, (newDesign) => {
|
|
3369
3437
|
if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
|
|
3370
|
-
setDesign(newDesign);
|
|
3371
3438
|
setSelectedId(null);
|
|
3372
3439
|
setSelectedIds([]);
|
|
3440
|
+
setTool("select");
|
|
3441
|
+
setDesign(newDesign);
|
|
3373
3442
|
const firstPageId = newDesign.pages[0]?.id;
|
|
3374
3443
|
setCurrentPageId(firstPageId || "1");
|
|
3444
|
+
const optimalZoom = calculateFitToScreenZoom(newDesign.width, newDesign.height);
|
|
3445
|
+
setZoom(optimalZoom);
|
|
3446
|
+
setHistory([newDesign]);
|
|
3447
|
+
setHistoryIndex(0);
|
|
3375
3448
|
saveToHistory(newDesign);
|
|
3376
3449
|
} else {
|
|
3377
3450
|
alert("Invalid design structure in JSON file. Could not load.");
|
|
@@ -3387,6 +3460,40 @@ var CanvasEditor = forwardRef(({
|
|
|
3387
3460
|
jsonInputRef.current.value = "";
|
|
3388
3461
|
}
|
|
3389
3462
|
};
|
|
3463
|
+
const handleImportJSONData = () => {
|
|
3464
|
+
try {
|
|
3465
|
+
const jsonData = JSON.parse(jsonInputText);
|
|
3466
|
+
importFromJSONData(jsonData, (newDesign) => {
|
|
3467
|
+
if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
|
|
3468
|
+
setSelectedId(null);
|
|
3469
|
+
setSelectedIds([]);
|
|
3470
|
+
setTool("select");
|
|
3471
|
+
setDesign(newDesign);
|
|
3472
|
+
const firstPageId = newDesign.pages[0]?.id;
|
|
3473
|
+
setCurrentPageId(firstPageId || "1");
|
|
3474
|
+
const optimalZoom = calculateFitToScreenZoom(newDesign.width, newDesign.height);
|
|
3475
|
+
setZoom(optimalZoom);
|
|
3476
|
+
setHistory([newDesign]);
|
|
3477
|
+
setHistoryIndex(0);
|
|
3478
|
+
saveToHistory(newDesign);
|
|
3479
|
+
setShowJsonModal(false);
|
|
3480
|
+
setJsonInputText("");
|
|
3481
|
+
} else {
|
|
3482
|
+
alert("Invalid design structure in JSON data. Could not load.");
|
|
3483
|
+
}
|
|
3484
|
+
}, (errorMessage) => {
|
|
3485
|
+
alert(`Error importing JSON: ${errorMessage}`);
|
|
3486
|
+
}, (inputs, onComplete) => {
|
|
3487
|
+
setPendingInputs(inputs);
|
|
3488
|
+
setShowInputModal(true);
|
|
3489
|
+
window.__pendingImportComplete = onComplete;
|
|
3490
|
+
setShowJsonModal(false);
|
|
3491
|
+
setJsonInputText("");
|
|
3492
|
+
});
|
|
3493
|
+
} catch (error) {
|
|
3494
|
+
alert(`Invalid JSON format: ${error instanceof Error ? error.message : String(error)}`);
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3390
3497
|
const handleInputModalComplete = (values) => {
|
|
3391
3498
|
setShowInputModal(false);
|
|
3392
3499
|
const onComplete = window.__pendingImportComplete;
|
|
@@ -3493,7 +3600,8 @@ var CanvasEditor = forwardRef(({
|
|
|
3493
3600
|
exportToJPG(stageRef.current, design);
|
|
3494
3601
|
} : undefined,
|
|
3495
3602
|
onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
|
|
3496
|
-
onImportJSON: () => jsonInputRef.current?.click()
|
|
3603
|
+
onImportJSON: () => jsonInputRef.current?.click(),
|
|
3604
|
+
onLoadJSON: () => setShowJsonModal(true)
|
|
3497
3605
|
}
|
|
3498
3606
|
}
|
|
3499
3607
|
] : []
|
|
@@ -3570,7 +3678,7 @@ var CanvasEditor = forwardRef(({
|
|
|
3570
3678
|
onRedo: redo,
|
|
3571
3679
|
onZoomIn: () => setZoom(Math.min(3, zoom + 0.1)),
|
|
3572
3680
|
onZoomOut: () => setZoom(Math.max(0.1, zoom - 0.1)),
|
|
3573
|
-
onZoomReset: () => setZoom(
|
|
3681
|
+
onZoomReset: () => setZoom(calculateFitToScreenZoom(design.width, design.height)),
|
|
3574
3682
|
onSetActivePanel: setActivePanelId,
|
|
3575
3683
|
navbarConfig: config?.navbar
|
|
3576
3684
|
}), /* @__PURE__ */ React18.createElement("div", {
|
|
@@ -3597,6 +3705,7 @@ var CanvasEditor = forwardRef(({
|
|
|
3597
3705
|
transformOrigin: "center center"
|
|
3598
3706
|
}
|
|
3599
3707
|
}, /* @__PURE__ */ React18.createElement(Stage, {
|
|
3708
|
+
key: `canvas-${design.id || design.width}-${design.height}`,
|
|
3600
3709
|
ref: stageRef,
|
|
3601
3710
|
width: design.width,
|
|
3602
3711
|
height: design.height,
|
|
@@ -3650,11 +3759,19 @@ var CanvasEditor = forwardRef(({
|
|
|
3650
3759
|
}
|
|
3651
3760
|
}))))), config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
|
|
3652
3761
|
className: "absolute bottom-4 left-4 flex items-center space-x-2"
|
|
3653
|
-
}, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("
|
|
3762
|
+
}, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("div", {
|
|
3654
3763
|
key: page.id,
|
|
3764
|
+
className: "relative group"
|
|
3765
|
+
}, /* @__PURE__ */ React18.createElement("button", {
|
|
3655
3766
|
onClick: () => setCurrentPageId(page.id),
|
|
3656
3767
|
className: `px-3 py-1 rounded text-sm ${page.id === currentPageId ? "bg-blue-600 text-white" : "bg-gray-800 text-gray-300 hover:bg-gray-700"}`
|
|
3657
|
-
}, "Page ", index + 1)
|
|
3768
|
+
}, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React18.createElement("button", {
|
|
3769
|
+
onClick: () => deletePage(page.id),
|
|
3770
|
+
className: "absolute -top-1 -right-1 w-4 h-4 bg-red-500 text-white rounded-full flex items-center justify-center transition-opacity duration-200 hover:bg-red-600",
|
|
3771
|
+
title: `Delete Page ${index + 1}`
|
|
3772
|
+
}, /* @__PURE__ */ React18.createElement(X2, {
|
|
3773
|
+
className: "w-3 h-3"
|
|
3774
|
+
})))), /* @__PURE__ */ React18.createElement("button", {
|
|
3658
3775
|
onClick: addPage,
|
|
3659
3776
|
className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
|
|
3660
3777
|
title: "Add Page"
|
|
@@ -3733,7 +3850,31 @@ var CanvasEditor = forwardRef(({
|
|
|
3733
3850
|
className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
|
|
3734
3851
|
}))))) : /* @__PURE__ */ React18.createElement("div", {
|
|
3735
3852
|
className: "text-center text-gray-400 py-12"
|
|
3736
|
-
}, "Enter a search term to find images"))))
|
|
3853
|
+
}, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React18.createElement("div", {
|
|
3854
|
+
className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
|
|
3855
|
+
}, /* @__PURE__ */ React18.createElement("div", {
|
|
3856
|
+
className: "bg-gray-800 rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-auto"
|
|
3857
|
+
}, /* @__PURE__ */ React18.createElement("h2", {
|
|
3858
|
+
className: "text-white text-xl font-semibold mb-4"
|
|
3859
|
+
}, "Load JSON Data"), /* @__PURE__ */ React18.createElement("p", {
|
|
3860
|
+
className: "text-gray-300 mb-4"
|
|
3861
|
+
}, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React18.createElement("textarea", {
|
|
3862
|
+
value: jsonInputText,
|
|
3863
|
+
onChange: (e) => setJsonInputText(e.target.value),
|
|
3864
|
+
className: "w-full h-64 p-3 bg-gray-700 text-white border border-gray-600 rounded font-mono text-sm resize-none",
|
|
3865
|
+
placeholder: '{"width": 800, "height": 600, "pages": [...]}'
|
|
3866
|
+
}), /* @__PURE__ */ React18.createElement("div", {
|
|
3867
|
+
className: "flex justify-end space-x-3 mt-4"
|
|
3868
|
+
}, /* @__PURE__ */ React18.createElement("button", {
|
|
3869
|
+
onClick: () => {
|
|
3870
|
+
setShowJsonModal(false);
|
|
3871
|
+
setJsonInputText("");
|
|
3872
|
+
},
|
|
3873
|
+
className: "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
|
|
3874
|
+
}, "Cancel"), /* @__PURE__ */ React18.createElement("button", {
|
|
3875
|
+
onClick: handleImportJSONData,
|
|
3876
|
+
className: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
|
|
3877
|
+
}, "Load JSON")))));
|
|
3737
3878
|
});
|
|
3738
3879
|
var CanvasEditor_default = CanvasEditor;
|
|
3739
3880
|
// src/lib/index.ts
|
|
@@ -3741,6 +3882,7 @@ initJsxCompat();
|
|
|
3741
3882
|
export {
|
|
3742
3883
|
setUnsplashAccessKey,
|
|
3743
3884
|
replaceUserInputs,
|
|
3885
|
+
importFromJSONData,
|
|
3744
3886
|
importFromJSON,
|
|
3745
3887
|
getUnsplashAccessKey,
|
|
3746
3888
|
findRequiredInputs,
|
package/dist/lib/wordpress.js
CHANGED
|
@@ -26,7 +26,8 @@ function initJsxCompat() {
|
|
|
26
26
|
import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
|
|
27
27
|
import { Stage, Layer, Rect as Rect2 } from "react-konva";
|
|
28
28
|
import {
|
|
29
|
-
PlusCircle
|
|
29
|
+
PlusCircle,
|
|
30
|
+
X as X2
|
|
30
31
|
} from "lucide-react";
|
|
31
32
|
|
|
32
33
|
// src/elements/EditableTextElement.tsx
|
|
@@ -1964,7 +1965,8 @@ var ExportPanel = ({
|
|
|
1964
1965
|
onExportToPNG,
|
|
1965
1966
|
onExportToJPG,
|
|
1966
1967
|
onExportToJSON,
|
|
1967
|
-
onImportJSON
|
|
1968
|
+
onImportJSON,
|
|
1969
|
+
onLoadJSON
|
|
1968
1970
|
}) => {
|
|
1969
1971
|
return /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("h3", {
|
|
1970
1972
|
className: "text-white font-semibold mb-4"
|
|
@@ -1982,7 +1984,10 @@ var ExportPanel = ({
|
|
|
1982
1984
|
}, "Export as JSON"), /* @__PURE__ */ React15.createElement("button", {
|
|
1983
1985
|
onClick: onImportJSON,
|
|
1984
1986
|
className: "w-full p-3 bg-gray-700 text-white rounded hover:bg-gray-600"
|
|
1985
|
-
}, "Import JSON")
|
|
1987
|
+
}, "Import JSON"), onLoadJSON && /* @__PURE__ */ React15.createElement("button", {
|
|
1988
|
+
onClick: onLoadJSON,
|
|
1989
|
+
className: "w-full p-3 bg-green-600 text-white rounded hover:bg-green-700"
|
|
1990
|
+
}, "Load JSON")));
|
|
1986
1991
|
};
|
|
1987
1992
|
var ExportPanel_default = ExportPanel;
|
|
1988
1993
|
|
|
@@ -2161,6 +2166,12 @@ function convertTemplateToCanvasDesign(json) {
|
|
|
2161
2166
|
if (!converted.name) {
|
|
2162
2167
|
converted.name = json.name || "Imported Design";
|
|
2163
2168
|
}
|
|
2169
|
+
if (converted.width === "auto" || !converted.width) {
|
|
2170
|
+
converted.width = 800;
|
|
2171
|
+
}
|
|
2172
|
+
if (converted.height === "auto" || !converted.height) {
|
|
2173
|
+
converted.height = 600;
|
|
2174
|
+
}
|
|
2164
2175
|
if (!converted.fonts) {
|
|
2165
2176
|
converted.fonts = [];
|
|
2166
2177
|
}
|
|
@@ -2172,11 +2183,19 @@ function convertTemplateToCanvasDesign(json) {
|
|
|
2172
2183
|
}
|
|
2173
2184
|
if (converted.pages && Array.isArray(converted.pages)) {
|
|
2174
2185
|
converted.pages = converted.pages.map((page, index) => {
|
|
2186
|
+
const pageWidth = page.width === "auto" || !page.width ? converted.width : page.width;
|
|
2187
|
+
const pageHeight = page.height === "auto" || !page.height ? converted.height : page.height;
|
|
2175
2188
|
const elements = (page.elements || page.children || []).map((element) => {
|
|
2189
|
+
let elementType = element.type;
|
|
2190
|
+
let shapeType = element.shapeType;
|
|
2191
|
+
if (element.type === "figure" && element.subType) {
|
|
2192
|
+
elementType = "shape";
|
|
2193
|
+
shapeType = element.subType;
|
|
2194
|
+
}
|
|
2176
2195
|
return {
|
|
2177
2196
|
...element,
|
|
2178
2197
|
id: element.id || `${Date.now()}-${Math.random()}`,
|
|
2179
|
-
type:
|
|
2198
|
+
type: elementType || "text",
|
|
2180
2199
|
name: element.name || "Untitled",
|
|
2181
2200
|
x: element.x ?? 0,
|
|
2182
2201
|
y: element.y ?? 0,
|
|
@@ -2200,7 +2219,7 @@ function convertTemplateToCanvasDesign(json) {
|
|
|
2200
2219
|
cornerRadius: element.cornerRadius,
|
|
2201
2220
|
filters: element.filters,
|
|
2202
2221
|
mask: element.mask,
|
|
2203
|
-
shapeType
|
|
2222
|
+
shapeType,
|
|
2204
2223
|
align: element.align,
|
|
2205
2224
|
lineHeight: element.lineHeight,
|
|
2206
2225
|
letterSpacing: element.letterSpacing,
|
|
@@ -2435,6 +2454,9 @@ function replaceUserInputs(design, collectedInputs) {
|
|
|
2435
2454
|
return defaultSize;
|
|
2436
2455
|
};
|
|
2437
2456
|
unusedInputs.forEach(([inputId, value]) => {
|
|
2457
|
+
if (!value || value === "" || value === "undefined" || value === "null") {
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2438
2460
|
if ((inputId === "optionalImage" || inputId.toLowerCase().includes("image")) && typeof value === "string") {
|
|
2439
2461
|
const imageProps = processImageElement(value);
|
|
2440
2462
|
newElements.push({
|
|
@@ -2567,6 +2589,22 @@ var canvasToBlob = (stage, format = "png", options) => {
|
|
|
2567
2589
|
resolve(new Blob([arrayBuffer], { type: mimeType }));
|
|
2568
2590
|
});
|
|
2569
2591
|
};
|
|
2592
|
+
var importFromJSONData = (jsonData, onLoad, onError, onInputsRequired) => {
|
|
2593
|
+
try {
|
|
2594
|
+
const convertedDesign = convertTemplateToCanvasDesign(jsonData);
|
|
2595
|
+
const requiredInputs = findRequiredInputs(convertedDesign);
|
|
2596
|
+
if (requiredInputs.length > 0 && onInputsRequired) {
|
|
2597
|
+
onInputsRequired(requiredInputs, (collectedValues) => {
|
|
2598
|
+
const finalDesign = replaceUserInputs(convertedDesign, collectedValues);
|
|
2599
|
+
onLoad(finalDesign);
|
|
2600
|
+
});
|
|
2601
|
+
} else {
|
|
2602
|
+
onLoad(convertedDesign);
|
|
2603
|
+
}
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
onError(`Invalid JSON data: ${error instanceof Error ? error.message : String(error)}`);
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2570
2608
|
var importFromJSON = (event, onLoad, onError, onInputsRequired) => {
|
|
2571
2609
|
const file = event.target.files?.[0];
|
|
2572
2610
|
if (file) {
|
|
@@ -3019,6 +3057,8 @@ var CanvasEditor = forwardRef(({
|
|
|
3019
3057
|
const [historyIndex, setHistoryIndex] = useState3(-1);
|
|
3020
3058
|
const [showInputModal, setShowInputModal] = useState3(false);
|
|
3021
3059
|
const [pendingInputs, setPendingInputs] = useState3([]);
|
|
3060
|
+
const [showJsonModal, setShowJsonModal] = useState3(false);
|
|
3061
|
+
const [jsonInputText, setJsonInputText] = useState3("");
|
|
3022
3062
|
const stageRef = useRef5(null);
|
|
3023
3063
|
useImperativeHandle(ref, () => ({
|
|
3024
3064
|
stage: stageRef.current,
|
|
@@ -3224,15 +3264,35 @@ var CanvasEditor = forwardRef(({
|
|
|
3224
3264
|
}, [design.pages.length]);
|
|
3225
3265
|
const deletePage = useCallback4((pageId) => {
|
|
3226
3266
|
if (design.pages.length > 1) {
|
|
3227
|
-
setDesign((prev) =>
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3267
|
+
setDesign((prev) => {
|
|
3268
|
+
const filteredPages = prev.pages.filter((p) => p.id !== pageId);
|
|
3269
|
+
const renamedPages = filteredPages.map((p, idx) => ({
|
|
3270
|
+
...p,
|
|
3271
|
+
name: `Page ${idx + 1}`
|
|
3272
|
+
}));
|
|
3273
|
+
return {
|
|
3274
|
+
...prev,
|
|
3275
|
+
pages: renamedPages
|
|
3276
|
+
};
|
|
3277
|
+
});
|
|
3231
3278
|
if (currentPageId === pageId) {
|
|
3232
|
-
|
|
3279
|
+
const remainingPages = design.pages.filter((p) => p.id !== pageId);
|
|
3280
|
+
if (remainingPages.length > 0) {
|
|
3281
|
+
setCurrentPageId(remainingPages[0].id);
|
|
3282
|
+
}
|
|
3233
3283
|
}
|
|
3284
|
+
setTimeout(() => {
|
|
3285
|
+
const updatedDesign = {
|
|
3286
|
+
...design,
|
|
3287
|
+
pages: design.pages.filter((p) => p.id !== pageId).map((p, idx) => ({
|
|
3288
|
+
...p,
|
|
3289
|
+
name: `Page ${idx + 1}`
|
|
3290
|
+
}))
|
|
3291
|
+
};
|
|
3292
|
+
saveToHistory(updatedDesign);
|
|
3293
|
+
}, 0);
|
|
3234
3294
|
}
|
|
3235
|
-
}, [design.pages, currentPageId]);
|
|
3295
|
+
}, [design.pages, currentPageId, design, saveToHistory]);
|
|
3236
3296
|
const handleImageUpload = useCallback4((e) => {
|
|
3237
3297
|
const file = e.target.files?.[0];
|
|
3238
3298
|
if (file) {
|
|
@@ -3364,14 +3424,27 @@ var CanvasEditor = forwardRef(({
|
|
|
3364
3424
|
setUnsplashResults([]);
|
|
3365
3425
|
setUnsplashMode("element");
|
|
3366
3426
|
}, [currentPageId, saveToHistory, unsplashMode]);
|
|
3427
|
+
const calculateFitToScreenZoom = useCallback4((canvasWidth, canvasHeight) => {
|
|
3428
|
+
const viewportWidth = window.innerWidth - 320;
|
|
3429
|
+
const viewportHeight = window.innerHeight - 200;
|
|
3430
|
+
const scaleX = viewportWidth / canvasWidth;
|
|
3431
|
+
const scaleY = viewportHeight / canvasHeight;
|
|
3432
|
+
const optimalScale = Math.min(scaleX, scaleY, 1);
|
|
3433
|
+
return Math.max(0.1, Math.min(3, optimalScale));
|
|
3434
|
+
}, []);
|
|
3367
3435
|
const handleImportJSON = (event) => {
|
|
3368
3436
|
importFromJSON(event, (newDesign) => {
|
|
3369
3437
|
if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
|
|
3370
|
-
setDesign(newDesign);
|
|
3371
3438
|
setSelectedId(null);
|
|
3372
3439
|
setSelectedIds([]);
|
|
3440
|
+
setTool("select");
|
|
3441
|
+
setDesign(newDesign);
|
|
3373
3442
|
const firstPageId = newDesign.pages[0]?.id;
|
|
3374
3443
|
setCurrentPageId(firstPageId || "1");
|
|
3444
|
+
const optimalZoom = calculateFitToScreenZoom(newDesign.width, newDesign.height);
|
|
3445
|
+
setZoom(optimalZoom);
|
|
3446
|
+
setHistory([newDesign]);
|
|
3447
|
+
setHistoryIndex(0);
|
|
3375
3448
|
saveToHistory(newDesign);
|
|
3376
3449
|
} else {
|
|
3377
3450
|
alert("Invalid design structure in JSON file. Could not load.");
|
|
@@ -3387,6 +3460,40 @@ var CanvasEditor = forwardRef(({
|
|
|
3387
3460
|
jsonInputRef.current.value = "";
|
|
3388
3461
|
}
|
|
3389
3462
|
};
|
|
3463
|
+
const handleImportJSONData = () => {
|
|
3464
|
+
try {
|
|
3465
|
+
const jsonData = JSON.parse(jsonInputText);
|
|
3466
|
+
importFromJSONData(jsonData, (newDesign) => {
|
|
3467
|
+
if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
|
|
3468
|
+
setSelectedId(null);
|
|
3469
|
+
setSelectedIds([]);
|
|
3470
|
+
setTool("select");
|
|
3471
|
+
setDesign(newDesign);
|
|
3472
|
+
const firstPageId = newDesign.pages[0]?.id;
|
|
3473
|
+
setCurrentPageId(firstPageId || "1");
|
|
3474
|
+
const optimalZoom = calculateFitToScreenZoom(newDesign.width, newDesign.height);
|
|
3475
|
+
setZoom(optimalZoom);
|
|
3476
|
+
setHistory([newDesign]);
|
|
3477
|
+
setHistoryIndex(0);
|
|
3478
|
+
saveToHistory(newDesign);
|
|
3479
|
+
setShowJsonModal(false);
|
|
3480
|
+
setJsonInputText("");
|
|
3481
|
+
} else {
|
|
3482
|
+
alert("Invalid design structure in JSON data. Could not load.");
|
|
3483
|
+
}
|
|
3484
|
+
}, (errorMessage) => {
|
|
3485
|
+
alert(`Error importing JSON: ${errorMessage}`);
|
|
3486
|
+
}, (inputs, onComplete) => {
|
|
3487
|
+
setPendingInputs(inputs);
|
|
3488
|
+
setShowInputModal(true);
|
|
3489
|
+
window.__pendingImportComplete = onComplete;
|
|
3490
|
+
setShowJsonModal(false);
|
|
3491
|
+
setJsonInputText("");
|
|
3492
|
+
});
|
|
3493
|
+
} catch (error) {
|
|
3494
|
+
alert(`Invalid JSON format: ${error instanceof Error ? error.message : String(error)}`);
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3390
3497
|
const handleInputModalComplete = (values) => {
|
|
3391
3498
|
setShowInputModal(false);
|
|
3392
3499
|
const onComplete = window.__pendingImportComplete;
|
|
@@ -3493,7 +3600,8 @@ var CanvasEditor = forwardRef(({
|
|
|
3493
3600
|
exportToJPG(stageRef.current, design);
|
|
3494
3601
|
} : undefined,
|
|
3495
3602
|
onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
|
|
3496
|
-
onImportJSON: () => jsonInputRef.current?.click()
|
|
3603
|
+
onImportJSON: () => jsonInputRef.current?.click(),
|
|
3604
|
+
onLoadJSON: () => setShowJsonModal(true)
|
|
3497
3605
|
}
|
|
3498
3606
|
}
|
|
3499
3607
|
] : []
|
|
@@ -3570,7 +3678,7 @@ var CanvasEditor = forwardRef(({
|
|
|
3570
3678
|
onRedo: redo,
|
|
3571
3679
|
onZoomIn: () => setZoom(Math.min(3, zoom + 0.1)),
|
|
3572
3680
|
onZoomOut: () => setZoom(Math.max(0.1, zoom - 0.1)),
|
|
3573
|
-
onZoomReset: () => setZoom(
|
|
3681
|
+
onZoomReset: () => setZoom(calculateFitToScreenZoom(design.width, design.height)),
|
|
3574
3682
|
onSetActivePanel: setActivePanelId,
|
|
3575
3683
|
navbarConfig: config?.navbar
|
|
3576
3684
|
}), /* @__PURE__ */ React18.createElement("div", {
|
|
@@ -3597,6 +3705,7 @@ var CanvasEditor = forwardRef(({
|
|
|
3597
3705
|
transformOrigin: "center center"
|
|
3598
3706
|
}
|
|
3599
3707
|
}, /* @__PURE__ */ React18.createElement(Stage, {
|
|
3708
|
+
key: `canvas-${design.id || design.width}-${design.height}`,
|
|
3600
3709
|
ref: stageRef,
|
|
3601
3710
|
width: design.width,
|
|
3602
3711
|
height: design.height,
|
|
@@ -3650,11 +3759,19 @@ var CanvasEditor = forwardRef(({
|
|
|
3650
3759
|
}
|
|
3651
3760
|
}))))), config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
|
|
3652
3761
|
className: "absolute bottom-4 left-4 flex items-center space-x-2"
|
|
3653
|
-
}, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("
|
|
3762
|
+
}, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("div", {
|
|
3654
3763
|
key: page.id,
|
|
3764
|
+
className: "relative group"
|
|
3765
|
+
}, /* @__PURE__ */ React18.createElement("button", {
|
|
3655
3766
|
onClick: () => setCurrentPageId(page.id),
|
|
3656
3767
|
className: `px-3 py-1 rounded text-sm ${page.id === currentPageId ? "bg-blue-600 text-white" : "bg-gray-800 text-gray-300 hover:bg-gray-700"}`
|
|
3657
|
-
}, "Page ", index + 1)
|
|
3768
|
+
}, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React18.createElement("button", {
|
|
3769
|
+
onClick: () => deletePage(page.id),
|
|
3770
|
+
className: "absolute -top-1 -right-1 w-4 h-4 bg-red-500 text-white rounded-full flex items-center justify-center transition-opacity duration-200 hover:bg-red-600",
|
|
3771
|
+
title: `Delete Page ${index + 1}`
|
|
3772
|
+
}, /* @__PURE__ */ React18.createElement(X2, {
|
|
3773
|
+
className: "w-3 h-3"
|
|
3774
|
+
})))), /* @__PURE__ */ React18.createElement("button", {
|
|
3658
3775
|
onClick: addPage,
|
|
3659
3776
|
className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
|
|
3660
3777
|
title: "Add Page"
|
|
@@ -3733,7 +3850,31 @@ var CanvasEditor = forwardRef(({
|
|
|
3733
3850
|
className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
|
|
3734
3851
|
}))))) : /* @__PURE__ */ React18.createElement("div", {
|
|
3735
3852
|
className: "text-center text-gray-400 py-12"
|
|
3736
|
-
}, "Enter a search term to find images"))))
|
|
3853
|
+
}, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React18.createElement("div", {
|
|
3854
|
+
className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
|
|
3855
|
+
}, /* @__PURE__ */ React18.createElement("div", {
|
|
3856
|
+
className: "bg-gray-800 rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-auto"
|
|
3857
|
+
}, /* @__PURE__ */ React18.createElement("h2", {
|
|
3858
|
+
className: "text-white text-xl font-semibold mb-4"
|
|
3859
|
+
}, "Load JSON Data"), /* @__PURE__ */ React18.createElement("p", {
|
|
3860
|
+
className: "text-gray-300 mb-4"
|
|
3861
|
+
}, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React18.createElement("textarea", {
|
|
3862
|
+
value: jsonInputText,
|
|
3863
|
+
onChange: (e) => setJsonInputText(e.target.value),
|
|
3864
|
+
className: "w-full h-64 p-3 bg-gray-700 text-white border border-gray-600 rounded font-mono text-sm resize-none",
|
|
3865
|
+
placeholder: '{"width": 800, "height": 600, "pages": [...]}'
|
|
3866
|
+
}), /* @__PURE__ */ React18.createElement("div", {
|
|
3867
|
+
className: "flex justify-end space-x-3 mt-4"
|
|
3868
|
+
}, /* @__PURE__ */ React18.createElement("button", {
|
|
3869
|
+
onClick: () => {
|
|
3870
|
+
setShowJsonModal(false);
|
|
3871
|
+
setJsonInputText("");
|
|
3872
|
+
},
|
|
3873
|
+
className: "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
|
|
3874
|
+
}, "Cancel"), /* @__PURE__ */ React18.createElement("button", {
|
|
3875
|
+
onClick: handleImportJSONData,
|
|
3876
|
+
className: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
|
|
3877
|
+
}, "Load JSON")))));
|
|
3737
3878
|
});
|
|
3738
3879
|
var CanvasEditor_default = CanvasEditor;
|
|
3739
3880
|
// src/lib/index.ts
|
|
@@ -3794,6 +3935,7 @@ export {
|
|
|
3794
3935
|
setUnsplashAccessKey,
|
|
3795
3936
|
replaceUserInputs,
|
|
3796
3937
|
initWordPressCanvasEditor,
|
|
3938
|
+
importFromJSONData,
|
|
3797
3939
|
importFromJSON,
|
|
3798
3940
|
getUnsplashAccessKey,
|
|
3799
3941
|
findRequiredInputs,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CanvasEditor.d.ts","sourceRoot":"","sources":["../../src/CanvasEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoF,MAAM,OAAO,CAAC;AAGzG,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"CanvasEditor.d.ts","sourceRoot":"","sources":["../../src/CanvasEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoF,MAAM,OAAO,CAAC;AAGzG,OAAO,KAAK,MAAM,OAAO,CAAC;AA0C1B,OAAO,EAEL,YAAY,EAKb,MAAM,SAAS,CAAC;AAiCjB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGxC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,YAAY,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY;UAAuC,MAAM;aAAW,MAAM;yCA6nC9E,CAAC;AAEH,eAAe,YAAY,CAAC"}
|
|
@@ -13,7 +13,8 @@ export interface CanvasEditorRef {
|
|
|
13
13
|
}
|
|
14
14
|
export { default as CanvasEditor } from '../CanvasEditor';
|
|
15
15
|
export * from '../types';
|
|
16
|
-
export { exportToPNG, exportToJPG, exportToJSON, importFromJSON,
|
|
16
|
+
export { exportToPNG, exportToJPG, exportToJSON, importFromJSON, importFromJSONData, // New: Import JSON data directly (no file needed)
|
|
17
|
+
findRequiredInputs, replaceUserInputs, convertTemplateToCanvasDesign, canvasToBlob, } from '../utils/exportImportUtils';
|
|
17
18
|
export * from '../elements';
|
|
18
19
|
export { FONT_FAMILIES, DEFAULT_COLORS, CANVAS_PRESETS } from '../constants';
|
|
19
20
|
export { setUnsplashAccessKey, getUnsplashAccessKey } from '../config';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AASxC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,YAAY,CAAC;CAC/B;AAGD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG1D,cAAc,UAAU,CAAC;AAGzB,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,YAAY,GACb,MAAM,4BAA4B,CAAC;AAGpC,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG7E,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AASxC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,YAAY,CAAC;CAC/B;AAGD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG1D,cAAc,UAAU,CAAC;AAGzB,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,kBAAkB,EAAE,kDAAkD;AACtE,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,YAAY,GACb,MAAM,4BAA4B,CAAC;AAGpC,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG7E,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportPanel.d.ts","sourceRoot":"","sources":["../../../src/panels/ExportPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,gBAAgB;IACxB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ExportPanel.d.ts","sourceRoot":"","sources":["../../../src/panels/ExportPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,gBAAgB;IACxB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA8C3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -31,5 +31,101 @@ export declare const canvasToBlob: (stage: Konva.Stage, format?: "png" | "jpg",
|
|
|
31
31
|
quality?: number;
|
|
32
32
|
pixelRatio?: number;
|
|
33
33
|
}) => Promise<Blob>;
|
|
34
|
+
/**
|
|
35
|
+
* Import a canvas design from JSON data directly (without file reading)
|
|
36
|
+
*
|
|
37
|
+
* This function allows programmatic import of template data from any source
|
|
38
|
+
* (API calls, database, hardcoded templates, etc.) and processes it through
|
|
39
|
+
* the same pipeline as file-based imports.
|
|
40
|
+
*
|
|
41
|
+
* @param jsonData - The raw JSON template data to import
|
|
42
|
+
* @param onLoad - Callback function called when the design is successfully loaded
|
|
43
|
+
* @param onError - Callback function called when an error occurs during import
|
|
44
|
+
* @param onInputsRequired - Optional callback for handling user input collection
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* // Basic usage - no user inputs required
|
|
49
|
+
* importFromJSONData(
|
|
50
|
+
* {
|
|
51
|
+
* width: 800,
|
|
52
|
+
* height: 600,
|
|
53
|
+
* pages: [{
|
|
54
|
+
* id: "1",
|
|
55
|
+
* name: "Page 1",
|
|
56
|
+
* elements: [
|
|
57
|
+
* {
|
|
58
|
+
* type: "text",
|
|
59
|
+
* text: "Hello World",
|
|
60
|
+
* x: 100,
|
|
61
|
+
* y: 100,
|
|
62
|
+
* fontSize: 24
|
|
63
|
+
* }
|
|
64
|
+
* ],
|
|
65
|
+
* background: "white"
|
|
66
|
+
* }]
|
|
67
|
+
* },
|
|
68
|
+
* (design) => {
|
|
69
|
+
* console.log('Design loaded:', design);
|
|
70
|
+
* // Use the design in CanvasEditor
|
|
71
|
+
* },
|
|
72
|
+
* (error) => {
|
|
73
|
+
* console.error('Import failed:', error);
|
|
74
|
+
* }
|
|
75
|
+
* );
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* // With user inputs collection
|
|
81
|
+
* importFromJSONData(
|
|
82
|
+
* templateData,
|
|
83
|
+
* (design) => {
|
|
84
|
+
* // Design loaded with user inputs applied
|
|
85
|
+
* setDesign(design);
|
|
86
|
+
* },
|
|
87
|
+
* (error) => {
|
|
88
|
+
* alert('Import failed: ' + error);
|
|
89
|
+
* },
|
|
90
|
+
* (inputs, onComplete) => {
|
|
91
|
+
* // Show custom input modal
|
|
92
|
+
* showInputModal(inputs, (values) => {
|
|
93
|
+
* onComplete(values);
|
|
94
|
+
* });
|
|
95
|
+
* }
|
|
96
|
+
* );
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* // Import from API response
|
|
102
|
+
* async function loadTemplateFromAPI(templateId: string) {
|
|
103
|
+
* try {
|
|
104
|
+
* const response = await fetch(`/api/templates/${templateId}`);
|
|
105
|
+
* const templateData = await response.json();
|
|
106
|
+
*
|
|
107
|
+
* importFromJSONData(
|
|
108
|
+
* templateData,
|
|
109
|
+
* (design) => {
|
|
110
|
+
* // Template loaded successfully
|
|
111
|
+
* canvasEditorRef.current?.setDesign(design);
|
|
112
|
+
* },
|
|
113
|
+
* (error) => {
|
|
114
|
+
* alert('Failed to load template: ' + error);
|
|
115
|
+
* }
|
|
116
|
+
* );
|
|
117
|
+
* } catch (error) {
|
|
118
|
+
* console.error('API error:', error);
|
|
119
|
+
* }
|
|
120
|
+
* }
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @since 1.0.0
|
|
124
|
+
* @see importFromJSON - File-based version of this function
|
|
125
|
+
* @see convertTemplateToCanvasDesign - Template conversion logic
|
|
126
|
+
* @see findRequiredInputs - User input detection
|
|
127
|
+
* @see replaceUserInputs - Input replacement logic
|
|
128
|
+
*/
|
|
129
|
+
export declare const importFromJSONData: (jsonData: any, onLoad: (design: CanvasDesign) => void, onError: (message: string) => void, onInputsRequired?: (inputs: UserInputItem[], onComplete: (values: Record<string, any>) => void) => void) => void;
|
|
34
130
|
export declare const importFromJSON: (event: React.ChangeEvent<HTMLInputElement>, onLoad: (design: CanvasDesign) => void, onError: (message: string) => void, onInputsRequired?: (inputs: UserInputItem[], onComplete: (values: Record<string, any>) => void) => void) => void;
|
|
35
131
|
//# sourceMappingURL=exportImportUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exportImportUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/exportImportUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,GAAG,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"exportImportUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/exportImportUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,GAAG,GAAG,YAAY,CAuHrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,EAAE,CAsHxE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACrC,YAAY,CA6Nd;AAGD,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,CAAC,KAAK,EAAE,QAAQ,YAAY,SAanE,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,CAAC,KAAK,EAAE,QAAQ,YAAY,SAiBnE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,YAAY,SAWhD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GACrB,OAAO,KAAK,CAAC,KAAK,EAClB,SAAQ,KAAK,GAAG,KAAa,EAC7B,UAAU;IACN,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB,KACF,OAAO,CAAC,IAAI,CAsCd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,eAAO,MAAM,kBAAkB,GAC3B,UAAU,GAAG,EACb,QAAQ,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,EACtC,SAAS,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,KAAK,IAAI,SAuB1G,CAAC;AAEF,eAAO,MAAM,cAAc,GACvB,OAAO,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAC1C,QAAQ,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,EACtC,SAAS,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,KAAK,IAAI,SA0C1G,CAAC"}
|