labellife-design-tool 1.1.0 → 1.1.2

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,165 @@ 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
+ #### Add Elements from a Custom Panel
148
+
149
+ Every panel (built-in or custom) receives a `store` prop with a Polotno-like API:
150
+
151
+ ```tsx
152
+ // Your custom panel component
153
+ const MyImagesPanel = ({ store }) => {
154
+ const handleAddImage = (url: string) => {
155
+ store.activePage?.addElement({
156
+ type: "image",
157
+ src: url,
158
+ x: 100,
159
+ y: 100,
160
+ width: 200,
161
+ height: 200,
162
+ });
163
+ };
164
+
165
+ return (
166
+ <div style={{ color: "white", padding: 16 }}>
167
+ <h3>My Images</h3>
168
+ <button onClick={() => handleAddImage("https://example.com/img.jpg")}>
169
+ Add Image
170
+ </button>
171
+ <p>Canvas size: {store.width} × {store.height}</p>
172
+ </div>
173
+ );
174
+ };
175
+
176
+ // Register the panel
177
+ <CanvasEditor
178
+ config={{
179
+ panels: [
180
+ "text",
181
+ "elements",
182
+ { id: "my-images", title: "My Images", icon: <MyIcon />, component: MyImagesPanel },
183
+ "image",
184
+ "background",
185
+ ],
186
+ }}
187
+ />
188
+ ```
189
+
190
+ **CanvasStore interface**
191
+
192
+ ```typescript
193
+ interface CanvasStore {
194
+ activePage: {
195
+ addElement: (element: {
196
+ type: string;
197
+ src?: string;
198
+ x: number;
199
+ y: number;
200
+ width: number;
201
+ height: number;
202
+ }) => void;
203
+ };
204
+ width: number;
205
+ height: number;
206
+ }
207
+ ```
208
+
209
+ #### Default Behavior
210
+
211
+ If `config.panels` is **not provided**, the editor shows the default set:
212
+ - `text`, `elements`, `image`, `design`, `background`
213
+ - Plus `variables` if `config.variables` is set
214
+ - Plus `export` if `config.export` is set
215
+
57
216
  ### Configure Unsplash API Key
58
217
 
59
218
  ```tsx
@@ -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);
@@ -3566,104 +3611,189 @@ var CanvasEditor = forwardRef(({
3566
3611
  delete window.__pendingImportReject;
3567
3612
  }
3568
3613
  };
3569
- const panelConfigs = [
3570
- {
3571
- id: "elements",
3572
- title: "Elements",
3573
- component: ElementPanel_default,
3574
- props: { onAddShape: addShape }
3575
- },
3576
- {
3577
- id: "text",
3578
- title: "Text",
3579
- component: TextPanel_default,
3580
- props: {
3581
- selectedElement,
3582
- updateElement,
3583
- setTool,
3584
- onAddText: addText
3585
- }
3586
- },
3587
- {
3588
- id: "image",
3589
- title: "Images",
3590
- component: ImagePanel_default,
3591
- props: {
3592
- selectedElement,
3593
- updateElement,
3594
- onUploadClick: () => fileInputRef.current?.click(),
3595
- onUnsplashClick: () => {
3596
- setShowUnsplash(true);
3597
- setUnsplashMode("element");
3598
- },
3599
- canvasWidth: design.width,
3600
- canvasHeight: design.height
3601
- }
3602
- },
3603
- {
3604
- id: "design",
3605
- title: "Design",
3606
- component: DesignPanel_default,
3607
- props: {
3608
- design,
3609
- currentPage,
3610
- selectedElement,
3611
- setDesign,
3612
- updateElement,
3613
- onSetUnsplashBackground: () => {
3614
- setShowUnsplash(true);
3615
- setUnsplashMode("background");
3616
- },
3617
- config
3614
+ const store = useMemo(() => ({
3615
+ activePage: {
3616
+ addElement: (element) => {
3617
+ const newElement = {
3618
+ id: `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
3619
+ type: element.type,
3620
+ name: `${element.type} element`,
3621
+ x: element.x,
3622
+ y: element.y,
3623
+ width: element.width,
3624
+ height: element.height,
3625
+ rotation: 0,
3626
+ visible: true,
3627
+ locked: false,
3628
+ opacity: 1,
3629
+ ...element.src && { src: element.src }
3630
+ };
3631
+ setDesign((prev) => ({
3632
+ ...prev,
3633
+ pages: prev.pages.map((page) => page.id === currentPage.id ? { ...page, elements: [...page.elements, newElement] } : page)
3634
+ }));
3618
3635
  }
3619
3636
  },
3620
- {
3621
- id: "background",
3622
- title: "Background",
3623
- component: BackgroundPanel_default,
3624
- props: {
3625
- design,
3626
- currentPage,
3627
- setDesign,
3628
- onSetUnsplashBackground: () => {
3629
- setShowUnsplash(true);
3630
- setUnsplashMode("background");
3637
+ width: design.width,
3638
+ height: design.height
3639
+ }), [currentPage.id, design.width, design.height]);
3640
+ const panelConfigs = useMemo(() => {
3641
+ const builtInConfigs = {
3642
+ elements: {
3643
+ id: "elements",
3644
+ title: "Elements",
3645
+ component: ElementPanel_default,
3646
+ props: { onAddShape: addShape, store }
3647
+ },
3648
+ text: {
3649
+ id: "text",
3650
+ title: "Text",
3651
+ component: TextPanel_default,
3652
+ props: {
3653
+ selectedElement,
3654
+ updateElement,
3655
+ setTool,
3656
+ onAddText: addText,
3657
+ store
3631
3658
  }
3632
- }
3633
- },
3634
- ...config?.variables ? [
3635
- {
3659
+ },
3660
+ image: {
3661
+ id: "image",
3662
+ title: "Images",
3663
+ component: ImagePanel_default,
3664
+ props: {
3665
+ selectedElement,
3666
+ updateElement,
3667
+ onUploadClick: () => fileInputRef.current?.click(),
3668
+ onUnsplashClick: () => {
3669
+ setShowUnsplash(true);
3670
+ setUnsplashMode("element");
3671
+ },
3672
+ canvasWidth: design.width,
3673
+ canvasHeight: design.height,
3674
+ store
3675
+ }
3676
+ },
3677
+ design: {
3678
+ id: "design",
3679
+ title: "Design",
3680
+ component: DesignPanel_default,
3681
+ props: {
3682
+ design,
3683
+ currentPage,
3684
+ selectedElement,
3685
+ setDesign,
3686
+ updateElement,
3687
+ onSetUnsplashBackground: () => {
3688
+ setShowUnsplash(true);
3689
+ setUnsplashMode("background");
3690
+ },
3691
+ config,
3692
+ store
3693
+ }
3694
+ },
3695
+ background: {
3696
+ id: "background",
3697
+ title: "Background",
3698
+ component: BackgroundPanel_default,
3699
+ props: {
3700
+ design,
3701
+ currentPage,
3702
+ setDesign,
3703
+ onSetUnsplashBackground: () => {
3704
+ setShowUnsplash(true);
3705
+ setUnsplashMode("background");
3706
+ },
3707
+ store
3708
+ }
3709
+ },
3710
+ variables: config?.variables ? {
3636
3711
  id: "variables",
3637
3712
  title: "Variables",
3638
3713
  component: VariablesPanel_default,
3639
3714
  props: {
3640
3715
  config,
3641
3716
  design,
3642
- setDesign
3717
+ setDesign,
3718
+ store
3643
3719
  }
3644
- }
3645
- ] : [],
3646
- ...config?.export ? [
3647
- {
3720
+ } : null,
3721
+ export: {
3648
3722
  id: "export",
3649
3723
  title: "Export",
3650
3724
  component: ExportPanel_default,
3651
3725
  props: {
3652
- onExportToPNG: config.export?.png ? () => {
3726
+ onExportToPNG: config?.export?.png ? () => {
3653
3727
  if (stageRef.current)
3654
3728
  exportToPNG(stageRef.current, design);
3655
3729
  } : undefined,
3656
- onExportToJPG: config.export?.jpg ? () => {
3730
+ onExportToJPG: config?.export?.jpg ? () => {
3657
3731
  if (stageRef.current)
3658
3732
  exportToJPG(stageRef.current, design);
3659
3733
  } : undefined,
3660
- onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
3734
+ onExportToJSON: config?.export?.json ? () => exportToJSON(design) : undefined,
3661
3735
  onImportJSON: () => jsonInputRef.current?.click(),
3662
- onLoadJSON: () => setShowJsonModal(true)
3736
+ onLoadJSON: () => setShowJsonModal(true),
3737
+ store
3663
3738
  }
3664
3739
  }
3665
- ] : []
3666
- ];
3740
+ };
3741
+ const defaultPanels = [
3742
+ "text",
3743
+ "elements",
3744
+ "image",
3745
+ "design",
3746
+ "background",
3747
+ ...config?.variables ? ["variables"] : [],
3748
+ ...config?.export ? ["export"] : []
3749
+ ];
3750
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : defaultPanels;
3751
+ const seen = new Set;
3752
+ const ordered = [];
3753
+ requestedPanels.forEach((panel) => {
3754
+ if (typeof panel === "string") {
3755
+ const builtIn = builtInConfigs[panel];
3756
+ if (!builtIn)
3757
+ return;
3758
+ if (seen.has(builtIn.id))
3759
+ return;
3760
+ seen.add(builtIn.id);
3761
+ ordered.push(builtIn);
3762
+ return;
3763
+ }
3764
+ const custom = panel;
3765
+ if (!custom?.id || !custom?.component)
3766
+ return;
3767
+ if (seen.has(custom.id))
3768
+ return;
3769
+ seen.add(custom.id);
3770
+ ordered.push({
3771
+ id: custom.id,
3772
+ title: custom.title,
3773
+ component: custom.component,
3774
+ props: { ...custom.props, store }
3775
+ });
3776
+ });
3777
+ return ordered;
3778
+ }, [
3779
+ addShape,
3780
+ addText,
3781
+ config,
3782
+ currentPage,
3783
+ design,
3784
+ selectedElement,
3785
+ setTool,
3786
+ updateElement,
3787
+ store
3788
+ ]);
3789
+ useEffect4(() => {
3790
+ if (!panelConfigs.length)
3791
+ return;
3792
+ const exists = panelConfigs.some((panel) => panel.id === activePanelId);
3793
+ if (!exists) {
3794
+ setActivePanelId(panelConfigs[0].id);
3795
+ }
3796
+ }, [panelConfigs, activePanelId]);
3667
3797
  const DynamicPanelRenderer = () => {
3668
3798
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3669
3799
  if (!activePanelConfig) {
@@ -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);
@@ -3566,104 +3611,189 @@ var CanvasEditor = forwardRef(({
3566
3611
  delete window.__pendingImportReject;
3567
3612
  }
3568
3613
  };
3569
- const panelConfigs = [
3570
- {
3571
- id: "elements",
3572
- title: "Elements",
3573
- component: ElementPanel_default,
3574
- props: { onAddShape: addShape }
3575
- },
3576
- {
3577
- id: "text",
3578
- title: "Text",
3579
- component: TextPanel_default,
3580
- props: {
3581
- selectedElement,
3582
- updateElement,
3583
- setTool,
3584
- onAddText: addText
3585
- }
3586
- },
3587
- {
3588
- id: "image",
3589
- title: "Images",
3590
- component: ImagePanel_default,
3591
- props: {
3592
- selectedElement,
3593
- updateElement,
3594
- onUploadClick: () => fileInputRef.current?.click(),
3595
- onUnsplashClick: () => {
3596
- setShowUnsplash(true);
3597
- setUnsplashMode("element");
3598
- },
3599
- canvasWidth: design.width,
3600
- canvasHeight: design.height
3601
- }
3602
- },
3603
- {
3604
- id: "design",
3605
- title: "Design",
3606
- component: DesignPanel_default,
3607
- props: {
3608
- design,
3609
- currentPage,
3610
- selectedElement,
3611
- setDesign,
3612
- updateElement,
3613
- onSetUnsplashBackground: () => {
3614
- setShowUnsplash(true);
3615
- setUnsplashMode("background");
3616
- },
3617
- config
3614
+ const store = useMemo(() => ({
3615
+ activePage: {
3616
+ addElement: (element) => {
3617
+ const newElement = {
3618
+ id: `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
3619
+ type: element.type,
3620
+ name: `${element.type} element`,
3621
+ x: element.x,
3622
+ y: element.y,
3623
+ width: element.width,
3624
+ height: element.height,
3625
+ rotation: 0,
3626
+ visible: true,
3627
+ locked: false,
3628
+ opacity: 1,
3629
+ ...element.src && { src: element.src }
3630
+ };
3631
+ setDesign((prev) => ({
3632
+ ...prev,
3633
+ pages: prev.pages.map((page) => page.id === currentPage.id ? { ...page, elements: [...page.elements, newElement] } : page)
3634
+ }));
3618
3635
  }
3619
3636
  },
3620
- {
3621
- id: "background",
3622
- title: "Background",
3623
- component: BackgroundPanel_default,
3624
- props: {
3625
- design,
3626
- currentPage,
3627
- setDesign,
3628
- onSetUnsplashBackground: () => {
3629
- setShowUnsplash(true);
3630
- setUnsplashMode("background");
3637
+ width: design.width,
3638
+ height: design.height
3639
+ }), [currentPage.id, design.width, design.height]);
3640
+ const panelConfigs = useMemo(() => {
3641
+ const builtInConfigs = {
3642
+ elements: {
3643
+ id: "elements",
3644
+ title: "Elements",
3645
+ component: ElementPanel_default,
3646
+ props: { onAddShape: addShape, store }
3647
+ },
3648
+ text: {
3649
+ id: "text",
3650
+ title: "Text",
3651
+ component: TextPanel_default,
3652
+ props: {
3653
+ selectedElement,
3654
+ updateElement,
3655
+ setTool,
3656
+ onAddText: addText,
3657
+ store
3631
3658
  }
3632
- }
3633
- },
3634
- ...config?.variables ? [
3635
- {
3659
+ },
3660
+ image: {
3661
+ id: "image",
3662
+ title: "Images",
3663
+ component: ImagePanel_default,
3664
+ props: {
3665
+ selectedElement,
3666
+ updateElement,
3667
+ onUploadClick: () => fileInputRef.current?.click(),
3668
+ onUnsplashClick: () => {
3669
+ setShowUnsplash(true);
3670
+ setUnsplashMode("element");
3671
+ },
3672
+ canvasWidth: design.width,
3673
+ canvasHeight: design.height,
3674
+ store
3675
+ }
3676
+ },
3677
+ design: {
3678
+ id: "design",
3679
+ title: "Design",
3680
+ component: DesignPanel_default,
3681
+ props: {
3682
+ design,
3683
+ currentPage,
3684
+ selectedElement,
3685
+ setDesign,
3686
+ updateElement,
3687
+ onSetUnsplashBackground: () => {
3688
+ setShowUnsplash(true);
3689
+ setUnsplashMode("background");
3690
+ },
3691
+ config,
3692
+ store
3693
+ }
3694
+ },
3695
+ background: {
3696
+ id: "background",
3697
+ title: "Background",
3698
+ component: BackgroundPanel_default,
3699
+ props: {
3700
+ design,
3701
+ currentPage,
3702
+ setDesign,
3703
+ onSetUnsplashBackground: () => {
3704
+ setShowUnsplash(true);
3705
+ setUnsplashMode("background");
3706
+ },
3707
+ store
3708
+ }
3709
+ },
3710
+ variables: config?.variables ? {
3636
3711
  id: "variables",
3637
3712
  title: "Variables",
3638
3713
  component: VariablesPanel_default,
3639
3714
  props: {
3640
3715
  config,
3641
3716
  design,
3642
- setDesign
3717
+ setDesign,
3718
+ store
3643
3719
  }
3644
- }
3645
- ] : [],
3646
- ...config?.export ? [
3647
- {
3720
+ } : null,
3721
+ export: {
3648
3722
  id: "export",
3649
3723
  title: "Export",
3650
3724
  component: ExportPanel_default,
3651
3725
  props: {
3652
- onExportToPNG: config.export?.png ? () => {
3726
+ onExportToPNG: config?.export?.png ? () => {
3653
3727
  if (stageRef.current)
3654
3728
  exportToPNG(stageRef.current, design);
3655
3729
  } : undefined,
3656
- onExportToJPG: config.export?.jpg ? () => {
3730
+ onExportToJPG: config?.export?.jpg ? () => {
3657
3731
  if (stageRef.current)
3658
3732
  exportToJPG(stageRef.current, design);
3659
3733
  } : undefined,
3660
- onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
3734
+ onExportToJSON: config?.export?.json ? () => exportToJSON(design) : undefined,
3661
3735
  onImportJSON: () => jsonInputRef.current?.click(),
3662
- onLoadJSON: () => setShowJsonModal(true)
3736
+ onLoadJSON: () => setShowJsonModal(true),
3737
+ store
3663
3738
  }
3664
3739
  }
3665
- ] : []
3666
- ];
3740
+ };
3741
+ const defaultPanels = [
3742
+ "text",
3743
+ "elements",
3744
+ "image",
3745
+ "design",
3746
+ "background",
3747
+ ...config?.variables ? ["variables"] : [],
3748
+ ...config?.export ? ["export"] : []
3749
+ ];
3750
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : defaultPanels;
3751
+ const seen = new Set;
3752
+ const ordered = [];
3753
+ requestedPanels.forEach((panel) => {
3754
+ if (typeof panel === "string") {
3755
+ const builtIn = builtInConfigs[panel];
3756
+ if (!builtIn)
3757
+ return;
3758
+ if (seen.has(builtIn.id))
3759
+ return;
3760
+ seen.add(builtIn.id);
3761
+ ordered.push(builtIn);
3762
+ return;
3763
+ }
3764
+ const custom = panel;
3765
+ if (!custom?.id || !custom?.component)
3766
+ return;
3767
+ if (seen.has(custom.id))
3768
+ return;
3769
+ seen.add(custom.id);
3770
+ ordered.push({
3771
+ id: custom.id,
3772
+ title: custom.title,
3773
+ component: custom.component,
3774
+ props: { ...custom.props, store }
3775
+ });
3776
+ });
3777
+ return ordered;
3778
+ }, [
3779
+ addShape,
3780
+ addText,
3781
+ config,
3782
+ currentPage,
3783
+ design,
3784
+ selectedElement,
3785
+ setTool,
3786
+ updateElement,
3787
+ store
3788
+ ]);
3789
+ useEffect4(() => {
3790
+ if (!panelConfigs.length)
3791
+ return;
3792
+ const exists = panelConfigs.some((panel) => panel.id === activePanelId);
3793
+ if (!exists) {
3794
+ setActivePanelId(panelConfigs[0].id);
3795
+ }
3796
+ }, [panelConfigs, activePanelId]);
3667
3797
  const DynamicPanelRenderer = () => {
3668
3798
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3669
3799
  if (!activePanelConfig) {
@@ -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,EAA+B,MAAM,EAA0C,MAAM,gBAAgB,CAAC;AAG7G,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;yCA4wC9E,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,6 +15,7 @@ export interface CanvasEditorRef {
15
15
  }
16
16
  export { default as CanvasEditor } from '../CanvasEditor';
17
17
  export * from '../types';
18
+ export type { BuiltInPanelId, CanvasStore, CustomPanelDefinition, PanelDefinition, } from '../types/Config';
18
19
  export { exportToPNG, exportToJPG, exportToJSON, exportToJSONObject, importFromJSON, importFromJSONData, // Import JSON data directly (no file needed)
19
20
  loadTemplateFromJSON, // Simplified template loading utility
20
21
  findRequiredInputs, replaceUserInputs, convertTemplateToCanvasDesign, canvasToDataURL, canvasToBlob, } from '../utils/exportImportUtils';
@@ -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,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
+ {"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,WAAW,EACX,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,31 @@
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;
15
+ export interface CanvasStore {
16
+ activePage: {
17
+ addElement: (element: {
18
+ type: string;
19
+ src?: string;
20
+ x: number;
21
+ y: number;
22
+ width: number;
23
+ height: number;
24
+ }) => void;
25
+ };
26
+ width: number;
27
+ height: number;
28
+ }
1
29
  export interface NavbarSection {
2
30
  id: string;
3
31
  type: 'default' | 'custom';
@@ -36,5 +64,13 @@ export interface Config {
36
64
  variable: string;
37
65
  }[];
38
66
  navbar?: NavbarConfig;
67
+ /**
68
+ * Single source of truth for left-panel order/visibility and custom panels.
69
+ *
70
+ * Built-in panel ids: "text", "elements", "image", "design", "background", "export", "variables"
71
+ * Custom panel objects can be mixed in this same list.
72
+ * If not provided, defaults to all built-in panels.
73
+ */
74
+ panels?: PanelDefinition[];
39
75
  }
40
76
  //# 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":"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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "labellife-design-tool",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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",