labellife-design-tool 1.0.9 → 1.1.1

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 CHANGED
@@ -54,6 +54,103 @@ function App() {
54
54
 
55
55
  **Note on CSS**: The CSS is pre-processed and ready to use. Simply import it - no Tailwind configuration needed!
56
56
 
57
+ ### Panel Configuration (Built-in + Custom)
58
+
59
+ Control which panels appear in the left sidebar and their order using a **single list** via `config.panels`. You can mix built-in panel ids and custom panel objects in one array.
60
+
61
+ #### Available Built-in Panels
62
+
63
+ | Panel ID | Description |
64
+ |---|---|
65
+ | `"text"` | Add and edit text elements |
66
+ | `"elements"` | Add shapes (rect, circle, star, polygon, etc.) |
67
+ | `"image"` | Upload images, use Unsplash, crop/mask/filter |
68
+ | `"design"` | Canvas size, presets, design settings |
69
+ | `"background"` | Page background color/image |
70
+ | `"export"` | Export to PNG/JPG/JSON (requires `config.export`) |
71
+ | `"variables"` | Template variables (requires `config.variables`) |
72
+
73
+ #### Show Only Selected Built-in Panels
74
+
75
+ Omit any panel id to hide it. The order you list them is the order they appear:
76
+
77
+ ```tsx
78
+ <CanvasEditor
79
+ name="Limited Editor"
80
+ config={{
81
+ panels: ["text", "elements", "image", "background"],
82
+ }}
83
+ />
84
+ ```
85
+
86
+ This hides Design, Export, and Variables — only Text, Elements, Images, and Background are shown.
87
+
88
+ #### Add a Custom Panel
89
+
90
+ Create your own panel component and include it in the same list:
91
+
92
+ ```tsx
93
+ import { Sparkles } from "lucide-react";
94
+
95
+ // Your custom panel component — receives whatever props you pass
96
+ const MyAssetsPanel = ({ category }: { category: string }) => {
97
+ return (
98
+ <div style={{ padding: 16, color: "white" }}>
99
+ <h3>My Assets</h3>
100
+ <p>Showing assets for: {category}</p>
101
+ </div>
102
+ );
103
+ };
104
+
105
+ function App() {
106
+ return (
107
+ <CanvasEditor
108
+ name="Custom Panel Editor"
109
+ config={{
110
+ export: { png: true, jpg: true, json: true },
111
+ panels: [
112
+ "text",
113
+ "elements",
114
+ {
115
+ id: "my-assets",
116
+ title: "My Assets",
117
+ tooltip: "Browse my assets",
118
+ icon: <Sparkles className="w-5 h-5" />,
119
+ component: MyAssetsPanel,
120
+ props: { category: "stickers" },
121
+ },
122
+ "image",
123
+ "background",
124
+ "export",
125
+ ],
126
+ }}
127
+ />
128
+ );
129
+ }
130
+ ```
131
+
132
+ #### Custom Panel Definition
133
+
134
+ ```typescript
135
+ interface CustomPanelDefinition {
136
+ id: string; // Unique panel id
137
+ title: string; // Panel title
138
+ tooltip?: string; // Tooltip on hover (defaults to title)
139
+ icon: React.ReactElement; // Icon shown in the left sidebar
140
+ component: React.ComponentType<any>; // Your panel React component
141
+ props?: Record<string, any>; // Props passed to your component
142
+ actionType?: "setPanel" | "setToolAndPanel"; // Click behavior (default: "setPanel")
143
+ toolValue?: ToolType; // Tool to activate (if actionType is "setToolAndPanel")
144
+ }
145
+ ```
146
+
147
+ #### Default Behavior
148
+
149
+ If `config.panels` is **not provided**, the editor shows the default set:
150
+ - `text`, `elements`, `image`, `design`, `background`
151
+ - Plus `variables` if `config.variables` is set
152
+ - Plus `export` if `config.export` is set
153
+
57
154
  ### Configure Unsplash API Key
58
155
 
59
156
  ```tsx
@@ -119,6 +216,31 @@ The `CanvasEditorRef` interface provides the following properties and methods:
119
216
  - `setCanvasSize(width, height)`: Set the canvas dimensions programmatically
120
217
  - `loadDesign(jsonData)`: Load a design from JSON data (Promise-based)
121
218
 
219
+ ### Export Helpers (JSON object + Base64)
220
+
221
+ In addition to the UI download helpers, the library also provides functions that return data directly (no file download):
222
+
223
+ ```ts
224
+ import { exportToJSONObject, canvasToDataURL } from 'labellife-design-tool';
225
+ ```
226
+
227
+ #### Get a JSON-safe design object
228
+
229
+ ```ts
230
+ const designObject = exportToJSONObject(editorRef.current.getDesign());
231
+ // designObject is a plain JSON-compatible object you can send to an API
232
+ ```
233
+
234
+ #### Get a base64 data URL of the canvas
235
+
236
+ ```ts
237
+ const stage = editorRef.current.stage;
238
+ if (stage) {
239
+ const dataUrl = canvasToDataURL(stage, 'png', { pixelRatio: 2 });
240
+ // dataUrl is like: "data:image/png;base64,iVBORw0..."
241
+ }
242
+ ```
243
+
122
244
  ### Canvas Size Management
123
245
 
124
246
  The `setCanvasSize` method allows you to programmatically change the canvas dimensions. This is useful for responsive designs, template switching, or custom size inputs.
@@ -23,7 +23,7 @@ function initJsxCompat() {
23
23
  }
24
24
 
25
25
  // src/CanvasEditor.tsx
26
- import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
26
+ import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useMemo, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
27
27
  import { Stage, Layer, Rect as Rect2 } from "react-konva";
28
28
  import {
29
29
  PlusCircle,
@@ -1092,7 +1092,97 @@ var Header_default = Header;
1092
1092
 
1093
1093
  // src/components/LeftMenu.tsx
1094
1094
  import React8 from "react";
1095
- import { Type, Square, Image as ImageIcon, Palette, Download, Layers, Variable } from "lucide-react";
1095
+ import {
1096
+ Type,
1097
+ Square,
1098
+ Image as ImageIcon,
1099
+ Palette,
1100
+ Download,
1101
+ Layers,
1102
+ Variable
1103
+ } from "lucide-react";
1104
+ var BUILT_IN_MENU_ITEMS = {
1105
+ text: {
1106
+ id: "text",
1107
+ tooltip: "Text",
1108
+ icon: /* @__PURE__ */ React8.createElement(Type, {
1109
+ className: "w-5 h-5"
1110
+ }),
1111
+ actionType: "setToolAndPanel",
1112
+ toolValue: "text",
1113
+ panelValue: "text"
1114
+ },
1115
+ elements: {
1116
+ id: "elements",
1117
+ tooltip: "Elements",
1118
+ icon: /* @__PURE__ */ React8.createElement(Square, {
1119
+ className: "w-5 h-5"
1120
+ }),
1121
+ actionType: "setToolAndPanel",
1122
+ panelValue: "elements",
1123
+ toolValue: "shape"
1124
+ },
1125
+ image: {
1126
+ id: "image",
1127
+ tooltip: "Images",
1128
+ icon: /* @__PURE__ */ React8.createElement(ImageIcon, {
1129
+ className: "w-5 h-5"
1130
+ }),
1131
+ actionType: "setPanel",
1132
+ panelValue: "image"
1133
+ },
1134
+ design: {
1135
+ id: "design",
1136
+ tooltip: "Design",
1137
+ icon: /* @__PURE__ */ React8.createElement(Palette, {
1138
+ className: "w-5 h-5"
1139
+ }),
1140
+ actionType: "setPanel",
1141
+ panelValue: "design"
1142
+ },
1143
+ background: {
1144
+ id: "background",
1145
+ tooltip: "Background",
1146
+ icon: /* @__PURE__ */ React8.createElement(Layers, {
1147
+ className: "w-5 h-5"
1148
+ }),
1149
+ actionType: "setPanel",
1150
+ panelValue: "background"
1151
+ },
1152
+ export: {
1153
+ id: "export",
1154
+ tooltip: "Export",
1155
+ icon: /* @__PURE__ */ React8.createElement(Download, {
1156
+ className: "w-5 h-5"
1157
+ }),
1158
+ actionType: "setPanel",
1159
+ panelValue: "export"
1160
+ },
1161
+ variables: {
1162
+ id: "variables",
1163
+ tooltip: "Variables",
1164
+ icon: /* @__PURE__ */ React8.createElement(Variable, {
1165
+ className: "w-5 h-5"
1166
+ }),
1167
+ actionType: "setPanel",
1168
+ panelValue: "variables"
1169
+ }
1170
+ };
1171
+ var isCustomPanel = (panel) => typeof panel === "object" && panel !== null;
1172
+ var getDefaultPanelOrder = (config) => {
1173
+ const defaults = [
1174
+ "text",
1175
+ "elements",
1176
+ "image",
1177
+ "design",
1178
+ "background"
1179
+ ];
1180
+ if (config?.variables)
1181
+ defaults.push("variables");
1182
+ if (config?.export)
1183
+ defaults.push("export");
1184
+ return defaults;
1185
+ };
1096
1186
  var LeftMenu = ({
1097
1187
  tool,
1098
1188
  activePanel,
@@ -1100,77 +1190,32 @@ var LeftMenu = ({
1100
1190
  onSetActivePanel,
1101
1191
  config
1102
1192
  }) => {
1103
- const menuItems = [
1104
- {
1105
- id: "text",
1106
- tooltip: "Text",
1107
- icon: /* @__PURE__ */ React8.createElement(Type, {
1108
- className: "w-5 h-5"
1109
- }),
1110
- actionType: "setToolAndPanel",
1111
- toolValue: "text",
1112
- panelValue: "text"
1113
- },
1114
- {
1115
- id: "elements",
1116
- tooltip: "Elements",
1117
- icon: /* @__PURE__ */ React8.createElement(Square, {
1118
- className: "w-5 h-5"
1119
- }),
1120
- actionType: "setToolAndPanel",
1121
- panelValue: "elements",
1122
- toolValue: "shape"
1123
- },
1124
- {
1125
- id: "image",
1126
- tooltip: "Images",
1127
- icon: /* @__PURE__ */ React8.createElement(ImageIcon, {
1128
- className: "w-5 h-5"
1129
- }),
1130
- actionType: "setPanel",
1131
- panelValue: "image"
1132
- },
1133
- {
1134
- id: "design",
1135
- tooltip: "Design",
1136
- icon: /* @__PURE__ */ React8.createElement(Palette, {
1137
- className: "w-5 h-5"
1138
- }),
1139
- actionType: "setPanel",
1140
- panelValue: "design"
1193
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : getDefaultPanelOrder(config);
1194
+ const seenIds = new Set;
1195
+ const menuItems = requestedPanels.map((panel) => {
1196
+ if (typeof panel === "string") {
1197
+ if (panel === "variables" && !config?.variables)
1198
+ return null;
1199
+ const builtIn = BUILT_IN_MENU_ITEMS[panel];
1200
+ return builtIn || null;
1141
1201
  }
1142
- ];
1143
- if (config?.export) {
1144
- menuItems.push({
1145
- id: "export",
1146
- tooltip: "Export",
1147
- icon: /* @__PURE__ */ React8.createElement(Download, {
1148
- className: "w-5 h-5"
1149
- }),
1150
- actionType: "setPanel",
1151
- panelValue: "export"
1152
- });
1153
- }
1154
- menuItems.push({
1155
- id: "background",
1156
- tooltip: "Background",
1157
- icon: /* @__PURE__ */ React8.createElement(Layers, {
1158
- className: "w-5 h-5"
1159
- }),
1160
- actionType: "setPanel",
1161
- panelValue: "background"
1202
+ if (isCustomPanel(panel)) {
1203
+ return {
1204
+ id: panel.id,
1205
+ tooltip: panel.tooltip || panel.title,
1206
+ icon: panel.icon,
1207
+ actionType: panel.actionType || "setPanel",
1208
+ toolValue: panel.toolValue,
1209
+ panelValue: panel.id
1210
+ };
1211
+ }
1212
+ return null;
1213
+ }).filter((item) => !!item).filter((item) => {
1214
+ if (seenIds.has(item.id))
1215
+ return false;
1216
+ seenIds.add(item.id);
1217
+ return true;
1162
1218
  });
1163
- if (config?.variables) {
1164
- menuItems.push({
1165
- id: "variables",
1166
- tooltip: "Variables",
1167
- icon: /* @__PURE__ */ React8.createElement(Variable, {
1168
- className: "w-5 h-5"
1169
- }),
1170
- actionType: "setPanel",
1171
- panelValue: "variables"
1172
- });
1173
- }
1174
1219
  const handleItemClick = (item) => {
1175
1220
  if (item.actionType === "setTool" && item.toolValue) {
1176
1221
  onSetTool(item.toolValue);
@@ -2552,6 +2597,9 @@ var exportToJPG = (stage, design) => {
2552
2597
  document.body.removeChild(link);
2553
2598
  }
2554
2599
  };
2600
+ var exportToJSONObject = (design) => {
2601
+ return JSON.parse(JSON.stringify(design));
2602
+ };
2555
2603
  var exportToJSON = (design) => {
2556
2604
  const json = JSON.stringify(design, null, 2);
2557
2605
  const blob = new Blob([json], { type: "application/json" });
@@ -2564,6 +2612,22 @@ var exportToJSON = (design) => {
2564
2612
  document.body.removeChild(link);
2565
2613
  URL.revokeObjectURL(url);
2566
2614
  };
2615
+ var canvasToDataURL = (stage, format = "png", options) => {
2616
+ if (!stage) {
2617
+ throw new Error("Stage is required");
2618
+ }
2619
+ const oldScale = stage.scaleX();
2620
+ stage.scale({ x: 1, y: 1 });
2621
+ const pixelRatio = options?.pixelRatio ?? 2;
2622
+ const quality = options?.quality ?? 0.9;
2623
+ const dataUrl = stage.toDataURL({
2624
+ pixelRatio,
2625
+ mimeType: format === "jpg" ? "image/jpeg" : "image/png",
2626
+ quality: format === "jpg" ? quality : undefined
2627
+ });
2628
+ stage.scale({ x: oldScale, y: oldScale });
2629
+ return dataUrl;
2630
+ };
2567
2631
  var canvasToBlob = (stage, format = "png", options) => {
2568
2632
  if (!stage) {
2569
2633
  return Promise.reject(new Error("Stage is required"));
@@ -3547,73 +3611,73 @@ var CanvasEditor = forwardRef(({
3547
3611
  delete window.__pendingImportReject;
3548
3612
  }
3549
3613
  };
3550
- const panelConfigs = [
3551
- {
3552
- id: "elements",
3553
- title: "Elements",
3554
- component: ElementPanel_default,
3555
- props: { onAddShape: addShape }
3556
- },
3557
- {
3558
- id: "text",
3559
- title: "Text",
3560
- component: TextPanel_default,
3561
- props: {
3562
- selectedElement,
3563
- updateElement,
3564
- setTool,
3565
- onAddText: addText
3566
- }
3567
- },
3568
- {
3569
- id: "image",
3570
- title: "Images",
3571
- component: ImagePanel_default,
3572
- props: {
3573
- selectedElement,
3574
- updateElement,
3575
- onUploadClick: () => fileInputRef.current?.click(),
3576
- onUnsplashClick: () => {
3577
- setShowUnsplash(true);
3578
- setUnsplashMode("element");
3579
- },
3580
- canvasWidth: design.width,
3581
- canvasHeight: design.height
3582
- }
3583
- },
3584
- {
3585
- id: "design",
3586
- title: "Design",
3587
- component: DesignPanel_default,
3588
- props: {
3589
- design,
3590
- currentPage,
3591
- selectedElement,
3592
- setDesign,
3593
- updateElement,
3594
- onSetUnsplashBackground: () => {
3595
- setShowUnsplash(true);
3596
- setUnsplashMode("background");
3597
- },
3598
- config
3599
- }
3600
- },
3601
- {
3602
- id: "background",
3603
- title: "Background",
3604
- component: BackgroundPanel_default,
3605
- props: {
3606
- design,
3607
- currentPage,
3608
- setDesign,
3609
- onSetUnsplashBackground: () => {
3610
- setShowUnsplash(true);
3611
- setUnsplashMode("background");
3614
+ const panelConfigs = useMemo(() => {
3615
+ const builtInConfigs = {
3616
+ elements: {
3617
+ id: "elements",
3618
+ title: "Elements",
3619
+ component: ElementPanel_default,
3620
+ props: { onAddShape: addShape }
3621
+ },
3622
+ text: {
3623
+ id: "text",
3624
+ title: "Text",
3625
+ component: TextPanel_default,
3626
+ props: {
3627
+ selectedElement,
3628
+ updateElement,
3629
+ setTool,
3630
+ onAddText: addText
3612
3631
  }
3613
- }
3614
- },
3615
- ...config?.variables ? [
3616
- {
3632
+ },
3633
+ image: {
3634
+ id: "image",
3635
+ title: "Images",
3636
+ component: ImagePanel_default,
3637
+ props: {
3638
+ selectedElement,
3639
+ updateElement,
3640
+ onUploadClick: () => fileInputRef.current?.click(),
3641
+ onUnsplashClick: () => {
3642
+ setShowUnsplash(true);
3643
+ setUnsplashMode("element");
3644
+ },
3645
+ canvasWidth: design.width,
3646
+ canvasHeight: design.height
3647
+ }
3648
+ },
3649
+ design: {
3650
+ id: "design",
3651
+ title: "Design",
3652
+ component: DesignPanel_default,
3653
+ props: {
3654
+ design,
3655
+ currentPage,
3656
+ selectedElement,
3657
+ setDesign,
3658
+ updateElement,
3659
+ onSetUnsplashBackground: () => {
3660
+ setShowUnsplash(true);
3661
+ setUnsplashMode("background");
3662
+ },
3663
+ config
3664
+ }
3665
+ },
3666
+ background: {
3667
+ id: "background",
3668
+ title: "Background",
3669
+ component: BackgroundPanel_default,
3670
+ props: {
3671
+ design,
3672
+ currentPage,
3673
+ setDesign,
3674
+ onSetUnsplashBackground: () => {
3675
+ setShowUnsplash(true);
3676
+ setUnsplashMode("background");
3677
+ }
3678
+ }
3679
+ },
3680
+ variables: config?.variables ? {
3617
3681
  id: "variables",
3618
3682
  title: "Variables",
3619
3683
  component: VariablesPanel_default,
@@ -3622,29 +3686,81 @@ var CanvasEditor = forwardRef(({
3622
3686
  design,
3623
3687
  setDesign
3624
3688
  }
3625
- }
3626
- ] : [],
3627
- ...config?.export ? [
3628
- {
3689
+ } : null,
3690
+ export: {
3629
3691
  id: "export",
3630
3692
  title: "Export",
3631
3693
  component: ExportPanel_default,
3632
3694
  props: {
3633
- onExportToPNG: config.export?.png ? () => {
3695
+ onExportToPNG: config?.export?.png ? () => {
3634
3696
  if (stageRef.current)
3635
3697
  exportToPNG(stageRef.current, design);
3636
3698
  } : undefined,
3637
- onExportToJPG: config.export?.jpg ? () => {
3699
+ onExportToJPG: config?.export?.jpg ? () => {
3638
3700
  if (stageRef.current)
3639
3701
  exportToJPG(stageRef.current, design);
3640
3702
  } : undefined,
3641
- onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
3703
+ onExportToJSON: config?.export?.json ? () => exportToJSON(design) : undefined,
3642
3704
  onImportJSON: () => jsonInputRef.current?.click(),
3643
3705
  onLoadJSON: () => setShowJsonModal(true)
3644
3706
  }
3645
3707
  }
3646
- ] : []
3647
- ];
3708
+ };
3709
+ const defaultPanels = [
3710
+ "text",
3711
+ "elements",
3712
+ "image",
3713
+ "design",
3714
+ "background",
3715
+ ...config?.variables ? ["variables"] : [],
3716
+ ...config?.export ? ["export"] : []
3717
+ ];
3718
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : defaultPanels;
3719
+ const seen = new Set;
3720
+ const ordered = [];
3721
+ requestedPanels.forEach((panel) => {
3722
+ if (typeof panel === "string") {
3723
+ const builtIn = builtInConfigs[panel];
3724
+ if (!builtIn)
3725
+ return;
3726
+ if (seen.has(builtIn.id))
3727
+ return;
3728
+ seen.add(builtIn.id);
3729
+ ordered.push(builtIn);
3730
+ return;
3731
+ }
3732
+ const custom = panel;
3733
+ if (!custom?.id || !custom?.component)
3734
+ return;
3735
+ if (seen.has(custom.id))
3736
+ return;
3737
+ seen.add(custom.id);
3738
+ ordered.push({
3739
+ id: custom.id,
3740
+ title: custom.title,
3741
+ component: custom.component,
3742
+ props: custom.props || {}
3743
+ });
3744
+ });
3745
+ return ordered;
3746
+ }, [
3747
+ addShape,
3748
+ addText,
3749
+ config,
3750
+ currentPage,
3751
+ design,
3752
+ selectedElement,
3753
+ setTool,
3754
+ updateElement
3755
+ ]);
3756
+ useEffect4(() => {
3757
+ if (!panelConfigs.length)
3758
+ return;
3759
+ const exists = panelConfigs.some((panel) => panel.id === activePanelId);
3760
+ if (!exists) {
3761
+ setActivePanelId(panelConfigs[0].id);
3762
+ }
3763
+ }, [panelConfigs, activePanelId]);
3648
3764
  const DynamicPanelRenderer = () => {
3649
3765
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3650
3766
  if (!activePanelConfig) {
@@ -3927,9 +4043,11 @@ export {
3927
4043
  getUnsplashAccessKey,
3928
4044
  findRequiredInputs,
3929
4045
  exportToPNG,
4046
+ exportToJSONObject,
3930
4047
  exportToJSON,
3931
4048
  exportToJPG,
3932
4049
  convertTemplateToCanvasDesign,
4050
+ canvasToDataURL,
3933
4051
  canvasToBlob,
3934
4052
  UrlImageElement,
3935
4053
  ShapeElement,
@@ -23,7 +23,7 @@ function initJsxCompat() {
23
23
  }
24
24
 
25
25
  // src/CanvasEditor.tsx
26
- import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
26
+ import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useMemo, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
27
27
  import { Stage, Layer, Rect as Rect2 } from "react-konva";
28
28
  import {
29
29
  PlusCircle,
@@ -1092,7 +1092,97 @@ var Header_default = Header;
1092
1092
 
1093
1093
  // src/components/LeftMenu.tsx
1094
1094
  import React8 from "react";
1095
- import { Type, Square, Image as ImageIcon, Palette, Download, Layers, Variable } from "lucide-react";
1095
+ import {
1096
+ Type,
1097
+ Square,
1098
+ Image as ImageIcon,
1099
+ Palette,
1100
+ Download,
1101
+ Layers,
1102
+ Variable
1103
+ } from "lucide-react";
1104
+ var BUILT_IN_MENU_ITEMS = {
1105
+ text: {
1106
+ id: "text",
1107
+ tooltip: "Text",
1108
+ icon: /* @__PURE__ */ React8.createElement(Type, {
1109
+ className: "w-5 h-5"
1110
+ }),
1111
+ actionType: "setToolAndPanel",
1112
+ toolValue: "text",
1113
+ panelValue: "text"
1114
+ },
1115
+ elements: {
1116
+ id: "elements",
1117
+ tooltip: "Elements",
1118
+ icon: /* @__PURE__ */ React8.createElement(Square, {
1119
+ className: "w-5 h-5"
1120
+ }),
1121
+ actionType: "setToolAndPanel",
1122
+ panelValue: "elements",
1123
+ toolValue: "shape"
1124
+ },
1125
+ image: {
1126
+ id: "image",
1127
+ tooltip: "Images",
1128
+ icon: /* @__PURE__ */ React8.createElement(ImageIcon, {
1129
+ className: "w-5 h-5"
1130
+ }),
1131
+ actionType: "setPanel",
1132
+ panelValue: "image"
1133
+ },
1134
+ design: {
1135
+ id: "design",
1136
+ tooltip: "Design",
1137
+ icon: /* @__PURE__ */ React8.createElement(Palette, {
1138
+ className: "w-5 h-5"
1139
+ }),
1140
+ actionType: "setPanel",
1141
+ panelValue: "design"
1142
+ },
1143
+ background: {
1144
+ id: "background",
1145
+ tooltip: "Background",
1146
+ icon: /* @__PURE__ */ React8.createElement(Layers, {
1147
+ className: "w-5 h-5"
1148
+ }),
1149
+ actionType: "setPanel",
1150
+ panelValue: "background"
1151
+ },
1152
+ export: {
1153
+ id: "export",
1154
+ tooltip: "Export",
1155
+ icon: /* @__PURE__ */ React8.createElement(Download, {
1156
+ className: "w-5 h-5"
1157
+ }),
1158
+ actionType: "setPanel",
1159
+ panelValue: "export"
1160
+ },
1161
+ variables: {
1162
+ id: "variables",
1163
+ tooltip: "Variables",
1164
+ icon: /* @__PURE__ */ React8.createElement(Variable, {
1165
+ className: "w-5 h-5"
1166
+ }),
1167
+ actionType: "setPanel",
1168
+ panelValue: "variables"
1169
+ }
1170
+ };
1171
+ var isCustomPanel = (panel) => typeof panel === "object" && panel !== null;
1172
+ var getDefaultPanelOrder = (config) => {
1173
+ const defaults = [
1174
+ "text",
1175
+ "elements",
1176
+ "image",
1177
+ "design",
1178
+ "background"
1179
+ ];
1180
+ if (config?.variables)
1181
+ defaults.push("variables");
1182
+ if (config?.export)
1183
+ defaults.push("export");
1184
+ return defaults;
1185
+ };
1096
1186
  var LeftMenu = ({
1097
1187
  tool,
1098
1188
  activePanel,
@@ -1100,77 +1190,32 @@ var LeftMenu = ({
1100
1190
  onSetActivePanel,
1101
1191
  config
1102
1192
  }) => {
1103
- const menuItems = [
1104
- {
1105
- id: "text",
1106
- tooltip: "Text",
1107
- icon: /* @__PURE__ */ React8.createElement(Type, {
1108
- className: "w-5 h-5"
1109
- }),
1110
- actionType: "setToolAndPanel",
1111
- toolValue: "text",
1112
- panelValue: "text"
1113
- },
1114
- {
1115
- id: "elements",
1116
- tooltip: "Elements",
1117
- icon: /* @__PURE__ */ React8.createElement(Square, {
1118
- className: "w-5 h-5"
1119
- }),
1120
- actionType: "setToolAndPanel",
1121
- panelValue: "elements",
1122
- toolValue: "shape"
1123
- },
1124
- {
1125
- id: "image",
1126
- tooltip: "Images",
1127
- icon: /* @__PURE__ */ React8.createElement(ImageIcon, {
1128
- className: "w-5 h-5"
1129
- }),
1130
- actionType: "setPanel",
1131
- panelValue: "image"
1132
- },
1133
- {
1134
- id: "design",
1135
- tooltip: "Design",
1136
- icon: /* @__PURE__ */ React8.createElement(Palette, {
1137
- className: "w-5 h-5"
1138
- }),
1139
- actionType: "setPanel",
1140
- panelValue: "design"
1193
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : getDefaultPanelOrder(config);
1194
+ const seenIds = new Set;
1195
+ const menuItems = requestedPanels.map((panel) => {
1196
+ if (typeof panel === "string") {
1197
+ if (panel === "variables" && !config?.variables)
1198
+ return null;
1199
+ const builtIn = BUILT_IN_MENU_ITEMS[panel];
1200
+ return builtIn || null;
1141
1201
  }
1142
- ];
1143
- if (config?.export) {
1144
- menuItems.push({
1145
- id: "export",
1146
- tooltip: "Export",
1147
- icon: /* @__PURE__ */ React8.createElement(Download, {
1148
- className: "w-5 h-5"
1149
- }),
1150
- actionType: "setPanel",
1151
- panelValue: "export"
1152
- });
1153
- }
1154
- menuItems.push({
1155
- id: "background",
1156
- tooltip: "Background",
1157
- icon: /* @__PURE__ */ React8.createElement(Layers, {
1158
- className: "w-5 h-5"
1159
- }),
1160
- actionType: "setPanel",
1161
- panelValue: "background"
1202
+ if (isCustomPanel(panel)) {
1203
+ return {
1204
+ id: panel.id,
1205
+ tooltip: panel.tooltip || panel.title,
1206
+ icon: panel.icon,
1207
+ actionType: panel.actionType || "setPanel",
1208
+ toolValue: panel.toolValue,
1209
+ panelValue: panel.id
1210
+ };
1211
+ }
1212
+ return null;
1213
+ }).filter((item) => !!item).filter((item) => {
1214
+ if (seenIds.has(item.id))
1215
+ return false;
1216
+ seenIds.add(item.id);
1217
+ return true;
1162
1218
  });
1163
- if (config?.variables) {
1164
- menuItems.push({
1165
- id: "variables",
1166
- tooltip: "Variables",
1167
- icon: /* @__PURE__ */ React8.createElement(Variable, {
1168
- className: "w-5 h-5"
1169
- }),
1170
- actionType: "setPanel",
1171
- panelValue: "variables"
1172
- });
1173
- }
1174
1219
  const handleItemClick = (item) => {
1175
1220
  if (item.actionType === "setTool" && item.toolValue) {
1176
1221
  onSetTool(item.toolValue);
@@ -2552,6 +2597,9 @@ var exportToJPG = (stage, design) => {
2552
2597
  document.body.removeChild(link);
2553
2598
  }
2554
2599
  };
2600
+ var exportToJSONObject = (design) => {
2601
+ return JSON.parse(JSON.stringify(design));
2602
+ };
2555
2603
  var exportToJSON = (design) => {
2556
2604
  const json = JSON.stringify(design, null, 2);
2557
2605
  const blob = new Blob([json], { type: "application/json" });
@@ -2564,6 +2612,22 @@ var exportToJSON = (design) => {
2564
2612
  document.body.removeChild(link);
2565
2613
  URL.revokeObjectURL(url);
2566
2614
  };
2615
+ var canvasToDataURL = (stage, format = "png", options) => {
2616
+ if (!stage) {
2617
+ throw new Error("Stage is required");
2618
+ }
2619
+ const oldScale = stage.scaleX();
2620
+ stage.scale({ x: 1, y: 1 });
2621
+ const pixelRatio = options?.pixelRatio ?? 2;
2622
+ const quality = options?.quality ?? 0.9;
2623
+ const dataUrl = stage.toDataURL({
2624
+ pixelRatio,
2625
+ mimeType: format === "jpg" ? "image/jpeg" : "image/png",
2626
+ quality: format === "jpg" ? quality : undefined
2627
+ });
2628
+ stage.scale({ x: oldScale, y: oldScale });
2629
+ return dataUrl;
2630
+ };
2567
2631
  var canvasToBlob = (stage, format = "png", options) => {
2568
2632
  if (!stage) {
2569
2633
  return Promise.reject(new Error("Stage is required"));
@@ -3547,73 +3611,73 @@ var CanvasEditor = forwardRef(({
3547
3611
  delete window.__pendingImportReject;
3548
3612
  }
3549
3613
  };
3550
- const panelConfigs = [
3551
- {
3552
- id: "elements",
3553
- title: "Elements",
3554
- component: ElementPanel_default,
3555
- props: { onAddShape: addShape }
3556
- },
3557
- {
3558
- id: "text",
3559
- title: "Text",
3560
- component: TextPanel_default,
3561
- props: {
3562
- selectedElement,
3563
- updateElement,
3564
- setTool,
3565
- onAddText: addText
3566
- }
3567
- },
3568
- {
3569
- id: "image",
3570
- title: "Images",
3571
- component: ImagePanel_default,
3572
- props: {
3573
- selectedElement,
3574
- updateElement,
3575
- onUploadClick: () => fileInputRef.current?.click(),
3576
- onUnsplashClick: () => {
3577
- setShowUnsplash(true);
3578
- setUnsplashMode("element");
3579
- },
3580
- canvasWidth: design.width,
3581
- canvasHeight: design.height
3582
- }
3583
- },
3584
- {
3585
- id: "design",
3586
- title: "Design",
3587
- component: DesignPanel_default,
3588
- props: {
3589
- design,
3590
- currentPage,
3591
- selectedElement,
3592
- setDesign,
3593
- updateElement,
3594
- onSetUnsplashBackground: () => {
3595
- setShowUnsplash(true);
3596
- setUnsplashMode("background");
3597
- },
3598
- config
3599
- }
3600
- },
3601
- {
3602
- id: "background",
3603
- title: "Background",
3604
- component: BackgroundPanel_default,
3605
- props: {
3606
- design,
3607
- currentPage,
3608
- setDesign,
3609
- onSetUnsplashBackground: () => {
3610
- setShowUnsplash(true);
3611
- setUnsplashMode("background");
3614
+ const panelConfigs = useMemo(() => {
3615
+ const builtInConfigs = {
3616
+ elements: {
3617
+ id: "elements",
3618
+ title: "Elements",
3619
+ component: ElementPanel_default,
3620
+ props: { onAddShape: addShape }
3621
+ },
3622
+ text: {
3623
+ id: "text",
3624
+ title: "Text",
3625
+ component: TextPanel_default,
3626
+ props: {
3627
+ selectedElement,
3628
+ updateElement,
3629
+ setTool,
3630
+ onAddText: addText
3612
3631
  }
3613
- }
3614
- },
3615
- ...config?.variables ? [
3616
- {
3632
+ },
3633
+ image: {
3634
+ id: "image",
3635
+ title: "Images",
3636
+ component: ImagePanel_default,
3637
+ props: {
3638
+ selectedElement,
3639
+ updateElement,
3640
+ onUploadClick: () => fileInputRef.current?.click(),
3641
+ onUnsplashClick: () => {
3642
+ setShowUnsplash(true);
3643
+ setUnsplashMode("element");
3644
+ },
3645
+ canvasWidth: design.width,
3646
+ canvasHeight: design.height
3647
+ }
3648
+ },
3649
+ design: {
3650
+ id: "design",
3651
+ title: "Design",
3652
+ component: DesignPanel_default,
3653
+ props: {
3654
+ design,
3655
+ currentPage,
3656
+ selectedElement,
3657
+ setDesign,
3658
+ updateElement,
3659
+ onSetUnsplashBackground: () => {
3660
+ setShowUnsplash(true);
3661
+ setUnsplashMode("background");
3662
+ },
3663
+ config
3664
+ }
3665
+ },
3666
+ background: {
3667
+ id: "background",
3668
+ title: "Background",
3669
+ component: BackgroundPanel_default,
3670
+ props: {
3671
+ design,
3672
+ currentPage,
3673
+ setDesign,
3674
+ onSetUnsplashBackground: () => {
3675
+ setShowUnsplash(true);
3676
+ setUnsplashMode("background");
3677
+ }
3678
+ }
3679
+ },
3680
+ variables: config?.variables ? {
3617
3681
  id: "variables",
3618
3682
  title: "Variables",
3619
3683
  component: VariablesPanel_default,
@@ -3622,29 +3686,81 @@ var CanvasEditor = forwardRef(({
3622
3686
  design,
3623
3687
  setDesign
3624
3688
  }
3625
- }
3626
- ] : [],
3627
- ...config?.export ? [
3628
- {
3689
+ } : null,
3690
+ export: {
3629
3691
  id: "export",
3630
3692
  title: "Export",
3631
3693
  component: ExportPanel_default,
3632
3694
  props: {
3633
- onExportToPNG: config.export?.png ? () => {
3695
+ onExportToPNG: config?.export?.png ? () => {
3634
3696
  if (stageRef.current)
3635
3697
  exportToPNG(stageRef.current, design);
3636
3698
  } : undefined,
3637
- onExportToJPG: config.export?.jpg ? () => {
3699
+ onExportToJPG: config?.export?.jpg ? () => {
3638
3700
  if (stageRef.current)
3639
3701
  exportToJPG(stageRef.current, design);
3640
3702
  } : undefined,
3641
- onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
3703
+ onExportToJSON: config?.export?.json ? () => exportToJSON(design) : undefined,
3642
3704
  onImportJSON: () => jsonInputRef.current?.click(),
3643
3705
  onLoadJSON: () => setShowJsonModal(true)
3644
3706
  }
3645
3707
  }
3646
- ] : []
3647
- ];
3708
+ };
3709
+ const defaultPanels = [
3710
+ "text",
3711
+ "elements",
3712
+ "image",
3713
+ "design",
3714
+ "background",
3715
+ ...config?.variables ? ["variables"] : [],
3716
+ ...config?.export ? ["export"] : []
3717
+ ];
3718
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : defaultPanels;
3719
+ const seen = new Set;
3720
+ const ordered = [];
3721
+ requestedPanels.forEach((panel) => {
3722
+ if (typeof panel === "string") {
3723
+ const builtIn = builtInConfigs[panel];
3724
+ if (!builtIn)
3725
+ return;
3726
+ if (seen.has(builtIn.id))
3727
+ return;
3728
+ seen.add(builtIn.id);
3729
+ ordered.push(builtIn);
3730
+ return;
3731
+ }
3732
+ const custom = panel;
3733
+ if (!custom?.id || !custom?.component)
3734
+ return;
3735
+ if (seen.has(custom.id))
3736
+ return;
3737
+ seen.add(custom.id);
3738
+ ordered.push({
3739
+ id: custom.id,
3740
+ title: custom.title,
3741
+ component: custom.component,
3742
+ props: custom.props || {}
3743
+ });
3744
+ });
3745
+ return ordered;
3746
+ }, [
3747
+ addShape,
3748
+ addText,
3749
+ config,
3750
+ currentPage,
3751
+ design,
3752
+ selectedElement,
3753
+ setTool,
3754
+ updateElement
3755
+ ]);
3756
+ useEffect4(() => {
3757
+ if (!panelConfigs.length)
3758
+ return;
3759
+ const exists = panelConfigs.some((panel) => panel.id === activePanelId);
3760
+ if (!exists) {
3761
+ setActivePanelId(panelConfigs[0].id);
3762
+ }
3763
+ }, [panelConfigs, activePanelId]);
3648
3764
  const DynamicPanelRenderer = () => {
3649
3765
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3650
3766
  if (!activePanelConfig) {
@@ -3980,9 +4096,11 @@ export {
3980
4096
  getUnsplashAccessKey,
3981
4097
  findRequiredInputs,
3982
4098
  exportToPNG,
4099
+ exportToJSONObject,
3983
4100
  exportToJSON,
3984
4101
  exportToJPG,
3985
4102
  convertTemplateToCanvasDesign,
4103
+ canvasToDataURL,
3986
4104
  canvasToBlob,
3987
4105
  UrlImageElement,
3988
4106
  ShapeElement,
@@ -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;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;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD;AAED,QAAA,MAAM,YAAY;UAAuC,MAAM;aAAW,MAAM;yCAwqC9E,CAAC;AAEH,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"CanvasEditor.d.ts","sourceRoot":"","sources":["../../src/CanvasEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6F,MAAM,OAAO,CAAC;AAGlH,OAAO,KAAK,MAAM,OAAO,CAAC;AA0C1B,OAAO,EAEL,YAAY,EAKb,MAAM,SAAS,CAAC;AAiCjB,OAAO,EAAkB,MAAM,EAA0C,MAAM,gBAAgB,CAAC;AAGhG,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;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD;AAED,QAAA,MAAM,YAAY;UAAuC,MAAM;aAAW,MAAM;yCAguC9E,CAAC;AAEH,eAAe,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"LeftMenu.d.ts","sourceRoot":"","sources":["../../../src/components/LeftMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAWzC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,aAAa,CAAC;IAC3B,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,gBAAgB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAqH5C,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"LeftMenu.d.ts","sourceRoot":"","sources":["../../../src/components/LeftMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAEL,MAAM,EAGP,MAAM,iBAAiB,CAAC;AAWzB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,aAAa,CAAC;IAC3B,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,gBAAgB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA2ED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA2F5C,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -15,9 +15,10 @@ export interface CanvasEditorRef {
15
15
  }
16
16
  export { default as CanvasEditor } from '../CanvasEditor';
17
17
  export * from '../types';
18
- export { exportToPNG, exportToJPG, exportToJSON, importFromJSON, importFromJSONData, // Import JSON data directly (no file needed)
18
+ export type { BuiltInPanelId, CustomPanelDefinition, PanelDefinition, } from '../types/Config';
19
+ export { exportToPNG, exportToJPG, exportToJSON, exportToJSONObject, importFromJSON, importFromJSONData, // Import JSON data directly (no file needed)
19
20
  loadTemplateFromJSON, // Simplified template loading utility
20
- findRequiredInputs, replaceUserInputs, convertTemplateToCanvasDesign, canvasToBlob, } from '../utils/exportImportUtils';
21
+ findRequiredInputs, replaceUserInputs, convertTemplateToCanvasDesign, canvasToDataURL, canvasToBlob, } from '../utils/exportImportUtils';
21
22
  export * from '../elements';
22
23
  export { FONT_FAMILIES, DEFAULT_COLORS, CANVAS_PRESETS } from '../constants';
23
24
  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;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,UAAU,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;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,6CAA6C;AACjE,oBAAoB,EAAE,sCAAsC;AAC5D,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;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,UAAU,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAGD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG1D,cAAc,UAAU,CAAC;AAGzB,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAAE,6CAA6C;AACjE,oBAAoB,EAAE,sCAAsC;AAC5D,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,eAAe,EACf,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,3 +1,17 @@
1
+ import React from "react";
2
+ import { ToolType } from "./ToolType";
3
+ export type BuiltInPanelId = "elements" | "design" | "text" | "image" | "background" | "export" | "variables";
4
+ export interface CustomPanelDefinition {
5
+ id: string;
6
+ title: string;
7
+ tooltip?: string;
8
+ icon: React.ReactElement<React.ComponentProps<any>>;
9
+ component: React.ComponentType<any>;
10
+ props?: Record<string, any>;
11
+ actionType?: "setPanel" | "setToolAndPanel";
12
+ toolValue?: ToolType;
13
+ }
14
+ export type PanelDefinition = BuiltInPanelId | CustomPanelDefinition;
1
15
  export interface NavbarSection {
2
16
  id: string;
3
17
  type: 'default' | 'custom';
@@ -36,5 +50,13 @@ export interface Config {
36
50
  variable: string;
37
51
  }[];
38
52
  navbar?: NavbarConfig;
53
+ /**
54
+ * Single source of truth for left-panel order/visibility and custom panels.
55
+ *
56
+ * Built-in panel ids: "text", "elements", "image", "design", "background", "export", "variables"
57
+ * Custom panel objects can be mixed in this same list.
58
+ * If not provided, defaults to all built-in panels.
59
+ */
60
+ panels?: PanelDefinition[];
39
61
  }
40
62
  //# sourceMappingURL=Config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/types/Config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IAEjC,eAAe,CAAC,EAAE;QAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;KACvC,CAAC;CACH;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,CAAC,EAAE;QACP,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB"}
1
+ {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/types/Config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,MAAM,cAAc,GACtB,UAAU,GACV,QAAQ,GACR,MAAM,GACN,OAAO,GACP,YAAY,GACZ,QAAQ,GACR,WAAW,CAAC;AAEhB,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,UAAU,CAAC,EAAE,UAAU,GAAG,iBAAiB,CAAC;IAC5C,SAAS,CAAC,EAAE,QAAQ,CAAC;CACtB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,qBAAqB,CAAC;AAErE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IAEjC,eAAe,CAAC,EAAE;QAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;KACvC,CAAC;CACH;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,CAAC,EAAE;QACP,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B"}
@@ -20,6 +20,7 @@ export declare function findRequiredInputs(design: CanvasDesign): UserInputItem[
20
20
  export declare function replaceUserInputs(design: CanvasDesign, collectedInputs: Record<string, any>): CanvasDesign;
21
21
  export declare const exportToPNG: (stage: Konva.Stage, design: CanvasDesign) => void;
22
22
  export declare const exportToJPG: (stage: Konva.Stage, design: CanvasDesign) => void;
23
+ export declare const exportToJSONObject: (design: CanvasDesign) => CanvasDesign;
23
24
  export declare const exportToJSON: (design: CanvasDesign) => void;
24
25
  /**
25
26
  * Converts the canvas to a Blob that can be used for various purposes
@@ -28,6 +29,10 @@ export declare const exportToJSON: (design: CanvasDesign) => void;
28
29
  * @param options - Additional options for conversion
29
30
  * @returns Promise that resolves with a Blob
30
31
  */
32
+ export declare const canvasToDataURL: (stage: Konva.Stage, format?: "png" | "jpg", options?: {
33
+ quality?: number;
34
+ pixelRatio?: number;
35
+ }) => string;
31
36
  export declare const canvasToBlob: (stage: Konva.Stage, format?: "png" | "jpg", options?: {
32
37
  quality?: number;
33
38
  pixelRatio?: number;
@@ -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,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC9C,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,iBAAiB,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,EACjD,UAAU,GAAG,KACZ,OAAO,CAAC,IAAI,CAMd,CAAC;AAEF,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"}
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,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC9C,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,kBAAkB,GAAI,QAAQ,YAAY,KAAG,YAEzD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,YAAY,SAWhD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GACxB,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,MAoBF,CAAC;AAEF,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,iBAAiB,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,EACjD,UAAU,GAAG,KACZ,OAAO,CAAC,IAAI,CAMd,CAAC;AAEF,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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "labellife-design-tool",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "Professional canvas editor built with React, TypeScript, and Konva",
5
- "main": "./dist/lib/index.js",
6
- "module": "./dist/lib/index.js",
7
- "types": "./dist/lib/index.d.ts",
5
+ "main": "./dist/lib/lib/index.js",
6
+ "module": "./dist/lib/lib/index.js",
7
+ "types": "./dist/lib/lib/index.d.ts",
8
8
  "type": "module",
9
9
  "exports": {
10
10
  ".": {
11
- "import": "./dist/lib/index.js",
12
- "types": "./dist/lib/index.d.ts"
11
+ "import": "./dist/lib/lib/index.js",
12
+ "types": "./dist/lib/lib/index.d.ts"
13
13
  },
14
14
  "./wordpress": {
15
15
  "import": "./dist/lib/wordpress.js",