labellife-design-tool 1.1.3 → 1.1.5

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
@@ -146,7 +146,71 @@ interface CustomPanelDefinition {
146
146
 
147
147
  #### Add Elements from a Custom Panel
148
148
 
149
- Every panel (built-in or custom) receives a `store` prop with a Polotno-like API:
149
+ **Option 1: Use the `useCanvasStore` hook (recommended)**
150
+
151
+ Any component inside `CanvasEditor` can access the store using the hook:
152
+
153
+ ```tsx
154
+ import { useCanvasStore } from 'labellife-design-tool';
155
+
156
+ const MyComponent = () => {
157
+ const store = useCanvasStore();
158
+
159
+ const handleAddImage = () => {
160
+ store.activePage.addElement({
161
+ type: "image",
162
+ src: "https://example.com/img.jpg",
163
+ x: 100,
164
+ y: 100,
165
+ width: 200,
166
+ height: 200,
167
+ });
168
+ };
169
+
170
+ const handleLoadTemplate = async () => {
171
+ try {
172
+ const templateData = {
173
+ name: "My Template",
174
+ width: 800,
175
+ height: 600,
176
+ pages: [
177
+ {
178
+ id: "page-1",
179
+ name: "Page 1",
180
+ elements: [
181
+ {
182
+ type: "text",
183
+ text: "Hello World",
184
+ x: 100,
185
+ y: 100,
186
+ fontSize: 24,
187
+ },
188
+ ],
189
+ },
190
+ ],
191
+ };
192
+
193
+ await store.loadJSON(templateData);
194
+ console.log("Template loaded successfully!");
195
+ } catch (error) {
196
+ console.error("Failed to load template:", error);
197
+ }
198
+ };
199
+
200
+ return (
201
+ <div style={{ color: "white", padding: 16 }}>
202
+ <p>Current page: {store.activePage.id}</p>
203
+ <p>Canvas size: {store.width} × {store.height}</p>
204
+ <button onClick={handleAddImage}>Add Image</button>
205
+ <button onClick={handleLoadTemplate}>Load Template</button>
206
+ </div>
207
+ );
208
+ };
209
+ ```
210
+
211
+ **Option 2: Panel prop approach**
212
+
213
+ Every panel (built-in or custom) also receives a `store` prop with a Polotno-like API:
150
214
 
151
215
  ```tsx
152
216
  // Your custom panel component
@@ -192,6 +256,7 @@ const MyImagesPanel = ({ store }) => {
192
256
  ```typescript
193
257
  interface CanvasStore {
194
258
  activePage: {
259
+ id: string;
195
260
  addElement: (element: {
196
261
  type: string;
197
262
  src?: string;
@@ -204,6 +269,8 @@ interface CanvasStore {
204
269
  width: number;
205
270
  height: number;
206
271
  openSidePanel: (panelId: string | null) => void;
272
+ deletePages: (pageIds: string[]) => void;
273
+ loadJSON: (jsonData: any) => Promise<void>;
207
274
  }
208
275
  ```
209
276
 
@@ -216,12 +283,21 @@ const MyPanel = ({ store }) => {
216
283
  const closeAllPanels = () => store.openSidePanel(null);
217
284
  const tryOpenUnknown = () => store.openSidePanel("nonexistent"); // closes all panels
218
285
 
286
+ const deletePage1 = () => store.deletePages(["page-1"]);
287
+ const deleteMultiplePages = () => store.deletePages(["page-1", "page-2", "page-3"]);
288
+
219
289
  return (
220
290
  <div style={{ color: "white", padding: 16 }}>
291
+ <p>Current page ID: {store.activePage.id}</p>
292
+ <p>Canvas size: {store.width} × {store.height}</p>
293
+
221
294
  <button onClick={openTextPanel}>Open Text Panel</button>
222
295
  <button onClick={openCustomPanel}>Open Custom Panel</button>
223
296
  <button onClick={closeAllPanels}>Close All Panels</button>
224
297
  <button onClick={tryOpenUnknown}>Try Unknown Panel (closes all)</button>
298
+
299
+ <button onClick={deletePage1}>Delete Page 1</button>
300
+ <button onClick={deleteMultiplePages}>Delete Multiple Pages</button>
225
301
  </div>
226
302
  );
227
303
  };
@@ -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, useMemo, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
26
+ import React19, { 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,
@@ -3091,6 +3091,17 @@ var TemplateInputModal = ({
3091
3091
  };
3092
3092
  var TemplateInputModal_default = TemplateInputModal;
3093
3093
 
3094
+ // src/context/CanvasStoreContext.tsx
3095
+ import { createContext, useContext } from "react";
3096
+ var CanvasStoreContext = createContext(null);
3097
+ var useCanvasStore = () => {
3098
+ const store = useContext(CanvasStoreContext);
3099
+ if (!store) {
3100
+ throw new Error("useCanvasStore must be used within a CanvasEditor component");
3101
+ }
3102
+ return store;
3103
+ };
3104
+
3094
3105
  // src/CanvasEditor.tsx
3095
3106
  var CanvasEditor = forwardRef(({
3096
3107
  name,
@@ -3613,6 +3624,7 @@ var CanvasEditor = forwardRef(({
3613
3624
  };
3614
3625
  const store = useMemo(() => ({
3615
3626
  activePage: {
3627
+ id: currentPage.id,
3616
3628
  addElement: (element) => {
3617
3629
  const newElement = {
3618
3630
  id: `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
@@ -3656,6 +3668,42 @@ var CanvasEditor = forwardRef(({
3656
3668
  } else {
3657
3669
  setActivePanelId(null);
3658
3670
  }
3671
+ },
3672
+ deletePages: (pageIds) => {
3673
+ setDesign((prev) => {
3674
+ const remainingPages = prev.pages.filter((page) => !pageIds.includes(page.id));
3675
+ if (remainingPages.length === 0) {
3676
+ console.warn("Cannot delete all pages. At least one page must remain.");
3677
+ return prev;
3678
+ }
3679
+ const currentPageWasDeleted = pageIds.includes(currentPage.id);
3680
+ const newCurrentPageId = currentPageWasDeleted ? remainingPages[0].id : currentPage.id;
3681
+ if (currentPageWasDeleted) {
3682
+ setTimeout(() => {
3683
+ const newCurrentPage = remainingPages[0];
3684
+ }, 0);
3685
+ }
3686
+ return {
3687
+ ...prev,
3688
+ pages: remainingPages,
3689
+ currentPageId: newCurrentPageId
3690
+ };
3691
+ });
3692
+ },
3693
+ loadJSON: async (jsonData) => {
3694
+ return new Promise((resolve, reject) => {
3695
+ importFromJSONData(jsonData, (loadedDesign) => {
3696
+ setDesign(loadedDesign);
3697
+ resolve();
3698
+ }, (errorMessage) => {
3699
+ console.error("Failed to load JSON:", errorMessage);
3700
+ reject(new Error(errorMessage));
3701
+ }, (inputs, onComplete) => {
3702
+ setPendingInputs(inputs);
3703
+ setShowInputModal(true);
3704
+ window.__pendingImportComplete = onComplete;
3705
+ });
3706
+ });
3659
3707
  }
3660
3708
  }), [currentPage.id, design.width, design.height, config, setActivePanelId]);
3661
3709
  const panelConfigs = useMemo(() => {
@@ -3818,12 +3866,12 @@ var CanvasEditor = forwardRef(({
3818
3866
  const DynamicPanelRenderer = () => {
3819
3867
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3820
3868
  if (!activePanelConfig) {
3821
- return /* @__PURE__ */ React18.createElement("div", {
3869
+ return /* @__PURE__ */ React19.createElement("div", {
3822
3870
  className: "text-white"
3823
3871
  }, "Panel not found");
3824
3872
  }
3825
3873
  const PanelComponent = activePanelConfig.component;
3826
- return /* @__PURE__ */ React18.createElement(PanelComponent, {
3874
+ return /* @__PURE__ */ React19.createElement(PanelComponent, {
3827
3875
  ...activePanelConfig.props
3828
3876
  });
3829
3877
  };
@@ -3876,9 +3924,11 @@ var CanvasEditor = forwardRef(({
3876
3924
  setHistoryIndex(0);
3877
3925
  }
3878
3926
  }, []);
3879
- return /* @__PURE__ */ React18.createElement("div", {
3927
+ return /* @__PURE__ */ React19.createElement(CanvasStoreContext.Provider, {
3928
+ value: store
3929
+ }, /* @__PURE__ */ React19.createElement("div", {
3880
3930
  className: "h-screen flex flex-col bg-gray-900"
3881
- }, /* @__PURE__ */ React18.createElement(Header_default, {
3931
+ }, /* @__PURE__ */ React19.createElement(Header_default, {
3882
3932
  name,
3883
3933
  zoom,
3884
3934
  historyIndex,
@@ -3890,37 +3940,37 @@ var CanvasEditor = forwardRef(({
3890
3940
  onZoomReset: () => setZoom(calculateFitToScreenZoom(design.width, design.height)),
3891
3941
  onSetActivePanel: setActivePanelId,
3892
3942
  navbarConfig: config?.navbar
3893
- }), /* @__PURE__ */ React18.createElement("div", {
3943
+ }), /* @__PURE__ */ React19.createElement("div", {
3894
3944
  className: "flex-1 flex overflow-hidden"
3895
- }, /* @__PURE__ */ React18.createElement("div", {
3945
+ }, /* @__PURE__ */ React19.createElement("div", {
3896
3946
  className: "w-80 bg-gray-800 border-r border-gray-700 flex"
3897
- }, /* @__PURE__ */ React18.createElement(LeftMenu_default, {
3947
+ }, /* @__PURE__ */ React19.createElement(LeftMenu_default, {
3898
3948
  tool,
3899
3949
  activePanel: activePanelId,
3900
3950
  onSetTool: setTool,
3901
3951
  onSetActivePanel: setActivePanelId,
3902
3952
  config
3903
- }), /* @__PURE__ */ React18.createElement("div", {
3953
+ }), /* @__PURE__ */ React19.createElement("div", {
3904
3954
  className: "flex-1 p-4 overflow-y-auto"
3905
- }, /* @__PURE__ */ React18.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React18.createElement("div", {
3955
+ }, /* @__PURE__ */ React19.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React19.createElement("div", {
3906
3956
  className: "flex-1 bg-gray-700 overflow-hidden relative",
3907
3957
  ref: containerRef
3908
- }, /* @__PURE__ */ React18.createElement("div", {
3958
+ }, /* @__PURE__ */ React19.createElement("div", {
3909
3959
  className: "absolute inset-0 flex items-center justify-center"
3910
- }, /* @__PURE__ */ React18.createElement("div", {
3960
+ }, /* @__PURE__ */ React19.createElement("div", {
3911
3961
  className: "bg-white shadow-2xl",
3912
3962
  style: {
3913
3963
  transform: `scale(${zoom})`,
3914
3964
  transformOrigin: "center center"
3915
3965
  }
3916
- }, /* @__PURE__ */ React18.createElement(Stage, {
3966
+ }, /* @__PURE__ */ React19.createElement(Stage, {
3917
3967
  key: `canvas-${design.id || design.width}-${design.height}`,
3918
3968
  ref: stageRef,
3919
3969
  width: design.width,
3920
3970
  height: design.height,
3921
3971
  onClick: handleStageClick,
3922
3972
  onTap: handleStageClick
3923
- }, /* @__PURE__ */ React18.createElement(Layer, null, /* @__PURE__ */ React18.createElement(Rect2, {
3973
+ }, /* @__PURE__ */ React19.createElement(Layer, null, /* @__PURE__ */ React19.createElement(Rect2, {
3924
3974
  x: 0,
3925
3975
  y: 0,
3926
3976
  width: design.width,
@@ -3931,7 +3981,7 @@ var CanvasEditor = forwardRef(({
3931
3981
  }), currentPage.elements.map((element) => {
3932
3982
  switch (element.type) {
3933
3983
  case "text":
3934
- return React18.createElement(EditableTextElement, {
3984
+ return React19.createElement(EditableTextElement, {
3935
3985
  key: element.id,
3936
3986
  element,
3937
3987
  isSelected: element.id === selectedId,
@@ -3942,7 +3992,7 @@ var CanvasEditor = forwardRef(({
3942
3992
  onChange: (attrs) => updateElement(element.id, attrs)
3943
3993
  });
3944
3994
  case "image":
3945
- return React18.createElement(UrlImageElement, {
3995
+ return React19.createElement(UrlImageElement, {
3946
3996
  key: element.id,
3947
3997
  element,
3948
3998
  isSelected: element.id === selectedId,
@@ -3953,7 +4003,7 @@ var CanvasEditor = forwardRef(({
3953
4003
  onChange: (attrs) => updateElement(element.id, attrs)
3954
4004
  });
3955
4005
  case "shape":
3956
- return React18.createElement(ShapeElement, {
4006
+ return React19.createElement(ShapeElement, {
3957
4007
  key: element.id,
3958
4008
  element,
3959
4009
  isSelected: element.id === selectedId,
@@ -3966,27 +4016,27 @@ var CanvasEditor = forwardRef(({
3966
4016
  default:
3967
4017
  return null;
3968
4018
  }
3969
- }))))), config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
4019
+ }))))), config?.multiPage && /* @__PURE__ */ React19.createElement("div", {
3970
4020
  className: "absolute bottom-4 left-4 flex items-center space-x-2"
3971
- }, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("div", {
4021
+ }, design.pages.map((page, index) => /* @__PURE__ */ React19.createElement("div", {
3972
4022
  key: page.id,
3973
4023
  className: "relative group"
3974
- }, /* @__PURE__ */ React18.createElement("button", {
4024
+ }, /* @__PURE__ */ React19.createElement("button", {
3975
4025
  onClick: () => setCurrentPageId(page.id),
3976
4026
  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"}`
3977
- }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React18.createElement("button", {
4027
+ }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React19.createElement("button", {
3978
4028
  onClick: () => deletePage(page.id),
3979
4029
  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",
3980
4030
  title: `Delete Page ${index + 1}`
3981
- }, /* @__PURE__ */ React18.createElement(X2, {
4031
+ }, /* @__PURE__ */ React19.createElement(X2, {
3982
4032
  className: "w-3 h-3"
3983
- })))), /* @__PURE__ */ React18.createElement("button", {
4033
+ })))), /* @__PURE__ */ React19.createElement("button", {
3984
4034
  onClick: addPage,
3985
4035
  className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
3986
4036
  title: "Add Page"
3987
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4037
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
3988
4038
  className: "w-4 h-4"
3989
- })))), /* @__PURE__ */ React18.createElement(RightSidebar_default, {
4039
+ })))), /* @__PURE__ */ React19.createElement(RightSidebar_default, {
3990
4040
  currentPageElements: currentPage.elements,
3991
4041
  selectedElement,
3992
4042
  selectedId,
@@ -3996,34 +4046,34 @@ var CanvasEditor = forwardRef(({
3996
4046
  onMoveElementUp: moveElementUp,
3997
4047
  onMoveElementDown: moveElementDown,
3998
4048
  onDeleteSelected: deleteSelected
3999
- })), /* @__PURE__ */ React18.createElement("input", {
4049
+ })), /* @__PURE__ */ React19.createElement("input", {
4000
4050
  ref: fileInputRef,
4001
4051
  type: "file",
4002
4052
  accept: "image/*",
4003
4053
  onChange: handleImageUpload,
4004
4054
  className: "hidden",
4005
4055
  multiple: true
4006
- }), /* @__PURE__ */ React18.createElement("input", {
4056
+ }), /* @__PURE__ */ React19.createElement("input", {
4007
4057
  ref: jsonInputRef,
4008
4058
  type: "file",
4009
4059
  accept: ".json",
4010
4060
  onChange: handleImportJSON,
4011
4061
  className: "hidden"
4012
- }), showInputModal && /* @__PURE__ */ React18.createElement(TemplateInputModal_default, {
4062
+ }), showInputModal && /* @__PURE__ */ React19.createElement(TemplateInputModal_default, {
4013
4063
  inputs: pendingInputs,
4014
4064
  onComplete: handleInputModalComplete,
4015
4065
  onCancel: handleInputModalCancel
4016
- }), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
4066
+ }), showUnsplash && /* @__PURE__ */ React19.createElement("div", {
4017
4067
  className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
4018
- }, /* @__PURE__ */ React18.createElement("div", {
4068
+ }, /* @__PURE__ */ React19.createElement("div", {
4019
4069
  className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
4020
- }, /* @__PURE__ */ React18.createElement("div", {
4070
+ }, /* @__PURE__ */ React19.createElement("div", {
4021
4071
  className: "p-6 border-b border-gray-700"
4022
- }, /* @__PURE__ */ React18.createElement("h3", {
4072
+ }, /* @__PURE__ */ React19.createElement("h3", {
4023
4073
  className: "text-xl font-semibold text-white mb-4"
4024
- }, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
4074
+ }, "Search Unsplash"), /* @__PURE__ */ React19.createElement("div", {
4025
4075
  className: "flex space-x-4"
4026
- }, /* @__PURE__ */ React18.createElement("input", {
4076
+ }, /* @__PURE__ */ React19.createElement("input", {
4027
4077
  type: "text",
4028
4078
  value: unsplashQuery,
4029
4079
  onChange: (e) => setUnsplashQuery(e.target.value),
@@ -4031,64 +4081,65 @@ var CanvasEditor = forwardRef(({
4031
4081
  placeholder: "Search for images...",
4032
4082
  className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
4033
4083
  autoFocus: true
4034
- }), /* @__PURE__ */ React18.createElement("button", {
4084
+ }), /* @__PURE__ */ React19.createElement("button", {
4035
4085
  onClick: searchUnsplash,
4036
4086
  className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
4037
- }, "Search"), /* @__PURE__ */ React18.createElement("button", {
4087
+ }, "Search"), /* @__PURE__ */ React19.createElement("button", {
4038
4088
  onClick: () => {
4039
4089
  setShowUnsplash(false);
4040
4090
  setUnsplashQuery("");
4041
4091
  setUnsplashResults([]);
4042
4092
  },
4043
4093
  className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
4044
- }, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
4094
+ }, "Cancel"))), /* @__PURE__ */ React19.createElement("div", {
4045
4095
  className: "flex-1 overflow-y-auto p-6"
4046
- }, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
4096
+ }, unsplashResults.length > 0 ? /* @__PURE__ */ React19.createElement("div", {
4047
4097
  className: "grid grid-cols-3 gap-4"
4048
- }, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
4098
+ }, unsplashResults.map((result) => /* @__PURE__ */ React19.createElement("button", {
4049
4099
  key: result.id,
4050
4100
  onClick: () => addUnsplashImage(result.urls.regular),
4051
4101
  className: "relative group overflow-hidden rounded-lg aspect-square"
4052
- }, /* @__PURE__ */ React18.createElement("img", {
4102
+ }, /* @__PURE__ */ React19.createElement("img", {
4053
4103
  src: result.urls.thumb,
4054
4104
  alt: "",
4055
4105
  className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
4056
- }), /* @__PURE__ */ React18.createElement("div", {
4106
+ }), /* @__PURE__ */ React19.createElement("div", {
4057
4107
  className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
4058
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4108
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
4059
4109
  className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
4060
- }))))) : /* @__PURE__ */ React18.createElement("div", {
4110
+ }))))) : /* @__PURE__ */ React19.createElement("div", {
4061
4111
  className: "text-center text-gray-400 py-12"
4062
- }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React18.createElement("div", {
4112
+ }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React19.createElement("div", {
4063
4113
  className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
4064
- }, /* @__PURE__ */ React18.createElement("div", {
4114
+ }, /* @__PURE__ */ React19.createElement("div", {
4065
4115
  className: "bg-gray-800 rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-auto"
4066
- }, /* @__PURE__ */ React18.createElement("h2", {
4116
+ }, /* @__PURE__ */ React19.createElement("h2", {
4067
4117
  className: "text-white text-xl font-semibold mb-4"
4068
- }, "Load JSON Data"), /* @__PURE__ */ React18.createElement("p", {
4118
+ }, "Load JSON Data"), /* @__PURE__ */ React19.createElement("p", {
4069
4119
  className: "text-gray-300 mb-4"
4070
- }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React18.createElement("textarea", {
4120
+ }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React19.createElement("textarea", {
4071
4121
  value: jsonInputText,
4072
4122
  onChange: (e) => setJsonInputText(e.target.value),
4073
4123
  className: "w-full h-64 p-3 bg-gray-700 text-white border border-gray-600 rounded font-mono text-sm resize-none",
4074
4124
  placeholder: '{"width": 800, "height": 600, "pages": [...]}'
4075
- }), /* @__PURE__ */ React18.createElement("div", {
4125
+ }), /* @__PURE__ */ React19.createElement("div", {
4076
4126
  className: "flex justify-end space-x-3 mt-4"
4077
- }, /* @__PURE__ */ React18.createElement("button", {
4127
+ }, /* @__PURE__ */ React19.createElement("button", {
4078
4128
  onClick: () => {
4079
4129
  setShowJsonModal(false);
4080
4130
  setJsonInputText("");
4081
4131
  },
4082
4132
  className: "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
4083
- }, "Cancel"), /* @__PURE__ */ React18.createElement("button", {
4133
+ }, "Cancel"), /* @__PURE__ */ React19.createElement("button", {
4084
4134
  onClick: handleImportJSONData,
4085
4135
  className: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
4086
- }, "Load JSON")))));
4136
+ }, "Load JSON"))))));
4087
4137
  });
4088
4138
  var CanvasEditor_default = CanvasEditor;
4089
4139
  // src/lib/index.ts
4090
4140
  initJsxCompat();
4091
4141
  export {
4142
+ useCanvasStore,
4092
4143
  setUnsplashAccessKey,
4093
4144
  replaceUserInputs,
4094
4145
  loadTemplateFromJSON,
@@ -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, useMemo, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
26
+ import React19, { 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,
@@ -3091,6 +3091,17 @@ var TemplateInputModal = ({
3091
3091
  };
3092
3092
  var TemplateInputModal_default = TemplateInputModal;
3093
3093
 
3094
+ // src/context/CanvasStoreContext.tsx
3095
+ import { createContext, useContext } from "react";
3096
+ var CanvasStoreContext = createContext(null);
3097
+ var useCanvasStore = () => {
3098
+ const store = useContext(CanvasStoreContext);
3099
+ if (!store) {
3100
+ throw new Error("useCanvasStore must be used within a CanvasEditor component");
3101
+ }
3102
+ return store;
3103
+ };
3104
+
3094
3105
  // src/CanvasEditor.tsx
3095
3106
  var CanvasEditor = forwardRef(({
3096
3107
  name,
@@ -3613,6 +3624,7 @@ var CanvasEditor = forwardRef(({
3613
3624
  };
3614
3625
  const store = useMemo(() => ({
3615
3626
  activePage: {
3627
+ id: currentPage.id,
3616
3628
  addElement: (element) => {
3617
3629
  const newElement = {
3618
3630
  id: `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
@@ -3656,6 +3668,42 @@ var CanvasEditor = forwardRef(({
3656
3668
  } else {
3657
3669
  setActivePanelId(null);
3658
3670
  }
3671
+ },
3672
+ deletePages: (pageIds) => {
3673
+ setDesign((prev) => {
3674
+ const remainingPages = prev.pages.filter((page) => !pageIds.includes(page.id));
3675
+ if (remainingPages.length === 0) {
3676
+ console.warn("Cannot delete all pages. At least one page must remain.");
3677
+ return prev;
3678
+ }
3679
+ const currentPageWasDeleted = pageIds.includes(currentPage.id);
3680
+ const newCurrentPageId = currentPageWasDeleted ? remainingPages[0].id : currentPage.id;
3681
+ if (currentPageWasDeleted) {
3682
+ setTimeout(() => {
3683
+ const newCurrentPage = remainingPages[0];
3684
+ }, 0);
3685
+ }
3686
+ return {
3687
+ ...prev,
3688
+ pages: remainingPages,
3689
+ currentPageId: newCurrentPageId
3690
+ };
3691
+ });
3692
+ },
3693
+ loadJSON: async (jsonData) => {
3694
+ return new Promise((resolve, reject) => {
3695
+ importFromJSONData(jsonData, (loadedDesign) => {
3696
+ setDesign(loadedDesign);
3697
+ resolve();
3698
+ }, (errorMessage) => {
3699
+ console.error("Failed to load JSON:", errorMessage);
3700
+ reject(new Error(errorMessage));
3701
+ }, (inputs, onComplete) => {
3702
+ setPendingInputs(inputs);
3703
+ setShowInputModal(true);
3704
+ window.__pendingImportComplete = onComplete;
3705
+ });
3706
+ });
3659
3707
  }
3660
3708
  }), [currentPage.id, design.width, design.height, config, setActivePanelId]);
3661
3709
  const panelConfigs = useMemo(() => {
@@ -3818,12 +3866,12 @@ var CanvasEditor = forwardRef(({
3818
3866
  const DynamicPanelRenderer = () => {
3819
3867
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3820
3868
  if (!activePanelConfig) {
3821
- return /* @__PURE__ */ React18.createElement("div", {
3869
+ return /* @__PURE__ */ React19.createElement("div", {
3822
3870
  className: "text-white"
3823
3871
  }, "Panel not found");
3824
3872
  }
3825
3873
  const PanelComponent = activePanelConfig.component;
3826
- return /* @__PURE__ */ React18.createElement(PanelComponent, {
3874
+ return /* @__PURE__ */ React19.createElement(PanelComponent, {
3827
3875
  ...activePanelConfig.props
3828
3876
  });
3829
3877
  };
@@ -3876,9 +3924,11 @@ var CanvasEditor = forwardRef(({
3876
3924
  setHistoryIndex(0);
3877
3925
  }
3878
3926
  }, []);
3879
- return /* @__PURE__ */ React18.createElement("div", {
3927
+ return /* @__PURE__ */ React19.createElement(CanvasStoreContext.Provider, {
3928
+ value: store
3929
+ }, /* @__PURE__ */ React19.createElement("div", {
3880
3930
  className: "h-screen flex flex-col bg-gray-900"
3881
- }, /* @__PURE__ */ React18.createElement(Header_default, {
3931
+ }, /* @__PURE__ */ React19.createElement(Header_default, {
3882
3932
  name,
3883
3933
  zoom,
3884
3934
  historyIndex,
@@ -3890,37 +3940,37 @@ var CanvasEditor = forwardRef(({
3890
3940
  onZoomReset: () => setZoom(calculateFitToScreenZoom(design.width, design.height)),
3891
3941
  onSetActivePanel: setActivePanelId,
3892
3942
  navbarConfig: config?.navbar
3893
- }), /* @__PURE__ */ React18.createElement("div", {
3943
+ }), /* @__PURE__ */ React19.createElement("div", {
3894
3944
  className: "flex-1 flex overflow-hidden"
3895
- }, /* @__PURE__ */ React18.createElement("div", {
3945
+ }, /* @__PURE__ */ React19.createElement("div", {
3896
3946
  className: "w-80 bg-gray-800 border-r border-gray-700 flex"
3897
- }, /* @__PURE__ */ React18.createElement(LeftMenu_default, {
3947
+ }, /* @__PURE__ */ React19.createElement(LeftMenu_default, {
3898
3948
  tool,
3899
3949
  activePanel: activePanelId,
3900
3950
  onSetTool: setTool,
3901
3951
  onSetActivePanel: setActivePanelId,
3902
3952
  config
3903
- }), /* @__PURE__ */ React18.createElement("div", {
3953
+ }), /* @__PURE__ */ React19.createElement("div", {
3904
3954
  className: "flex-1 p-4 overflow-y-auto"
3905
- }, /* @__PURE__ */ React18.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React18.createElement("div", {
3955
+ }, /* @__PURE__ */ React19.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React19.createElement("div", {
3906
3956
  className: "flex-1 bg-gray-700 overflow-hidden relative",
3907
3957
  ref: containerRef
3908
- }, /* @__PURE__ */ React18.createElement("div", {
3958
+ }, /* @__PURE__ */ React19.createElement("div", {
3909
3959
  className: "absolute inset-0 flex items-center justify-center"
3910
- }, /* @__PURE__ */ React18.createElement("div", {
3960
+ }, /* @__PURE__ */ React19.createElement("div", {
3911
3961
  className: "bg-white shadow-2xl",
3912
3962
  style: {
3913
3963
  transform: `scale(${zoom})`,
3914
3964
  transformOrigin: "center center"
3915
3965
  }
3916
- }, /* @__PURE__ */ React18.createElement(Stage, {
3966
+ }, /* @__PURE__ */ React19.createElement(Stage, {
3917
3967
  key: `canvas-${design.id || design.width}-${design.height}`,
3918
3968
  ref: stageRef,
3919
3969
  width: design.width,
3920
3970
  height: design.height,
3921
3971
  onClick: handleStageClick,
3922
3972
  onTap: handleStageClick
3923
- }, /* @__PURE__ */ React18.createElement(Layer, null, /* @__PURE__ */ React18.createElement(Rect2, {
3973
+ }, /* @__PURE__ */ React19.createElement(Layer, null, /* @__PURE__ */ React19.createElement(Rect2, {
3924
3974
  x: 0,
3925
3975
  y: 0,
3926
3976
  width: design.width,
@@ -3931,7 +3981,7 @@ var CanvasEditor = forwardRef(({
3931
3981
  }), currentPage.elements.map((element) => {
3932
3982
  switch (element.type) {
3933
3983
  case "text":
3934
- return React18.createElement(EditableTextElement, {
3984
+ return React19.createElement(EditableTextElement, {
3935
3985
  key: element.id,
3936
3986
  element,
3937
3987
  isSelected: element.id === selectedId,
@@ -3942,7 +3992,7 @@ var CanvasEditor = forwardRef(({
3942
3992
  onChange: (attrs) => updateElement(element.id, attrs)
3943
3993
  });
3944
3994
  case "image":
3945
- return React18.createElement(UrlImageElement, {
3995
+ return React19.createElement(UrlImageElement, {
3946
3996
  key: element.id,
3947
3997
  element,
3948
3998
  isSelected: element.id === selectedId,
@@ -3953,7 +4003,7 @@ var CanvasEditor = forwardRef(({
3953
4003
  onChange: (attrs) => updateElement(element.id, attrs)
3954
4004
  });
3955
4005
  case "shape":
3956
- return React18.createElement(ShapeElement, {
4006
+ return React19.createElement(ShapeElement, {
3957
4007
  key: element.id,
3958
4008
  element,
3959
4009
  isSelected: element.id === selectedId,
@@ -3966,27 +4016,27 @@ var CanvasEditor = forwardRef(({
3966
4016
  default:
3967
4017
  return null;
3968
4018
  }
3969
- }))))), config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
4019
+ }))))), config?.multiPage && /* @__PURE__ */ React19.createElement("div", {
3970
4020
  className: "absolute bottom-4 left-4 flex items-center space-x-2"
3971
- }, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("div", {
4021
+ }, design.pages.map((page, index) => /* @__PURE__ */ React19.createElement("div", {
3972
4022
  key: page.id,
3973
4023
  className: "relative group"
3974
- }, /* @__PURE__ */ React18.createElement("button", {
4024
+ }, /* @__PURE__ */ React19.createElement("button", {
3975
4025
  onClick: () => setCurrentPageId(page.id),
3976
4026
  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"}`
3977
- }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React18.createElement("button", {
4027
+ }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React19.createElement("button", {
3978
4028
  onClick: () => deletePage(page.id),
3979
4029
  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",
3980
4030
  title: `Delete Page ${index + 1}`
3981
- }, /* @__PURE__ */ React18.createElement(X2, {
4031
+ }, /* @__PURE__ */ React19.createElement(X2, {
3982
4032
  className: "w-3 h-3"
3983
- })))), /* @__PURE__ */ React18.createElement("button", {
4033
+ })))), /* @__PURE__ */ React19.createElement("button", {
3984
4034
  onClick: addPage,
3985
4035
  className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
3986
4036
  title: "Add Page"
3987
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4037
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
3988
4038
  className: "w-4 h-4"
3989
- })))), /* @__PURE__ */ React18.createElement(RightSidebar_default, {
4039
+ })))), /* @__PURE__ */ React19.createElement(RightSidebar_default, {
3990
4040
  currentPageElements: currentPage.elements,
3991
4041
  selectedElement,
3992
4042
  selectedId,
@@ -3996,34 +4046,34 @@ var CanvasEditor = forwardRef(({
3996
4046
  onMoveElementUp: moveElementUp,
3997
4047
  onMoveElementDown: moveElementDown,
3998
4048
  onDeleteSelected: deleteSelected
3999
- })), /* @__PURE__ */ React18.createElement("input", {
4049
+ })), /* @__PURE__ */ React19.createElement("input", {
4000
4050
  ref: fileInputRef,
4001
4051
  type: "file",
4002
4052
  accept: "image/*",
4003
4053
  onChange: handleImageUpload,
4004
4054
  className: "hidden",
4005
4055
  multiple: true
4006
- }), /* @__PURE__ */ React18.createElement("input", {
4056
+ }), /* @__PURE__ */ React19.createElement("input", {
4007
4057
  ref: jsonInputRef,
4008
4058
  type: "file",
4009
4059
  accept: ".json",
4010
4060
  onChange: handleImportJSON,
4011
4061
  className: "hidden"
4012
- }), showInputModal && /* @__PURE__ */ React18.createElement(TemplateInputModal_default, {
4062
+ }), showInputModal && /* @__PURE__ */ React19.createElement(TemplateInputModal_default, {
4013
4063
  inputs: pendingInputs,
4014
4064
  onComplete: handleInputModalComplete,
4015
4065
  onCancel: handleInputModalCancel
4016
- }), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
4066
+ }), showUnsplash && /* @__PURE__ */ React19.createElement("div", {
4017
4067
  className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
4018
- }, /* @__PURE__ */ React18.createElement("div", {
4068
+ }, /* @__PURE__ */ React19.createElement("div", {
4019
4069
  className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
4020
- }, /* @__PURE__ */ React18.createElement("div", {
4070
+ }, /* @__PURE__ */ React19.createElement("div", {
4021
4071
  className: "p-6 border-b border-gray-700"
4022
- }, /* @__PURE__ */ React18.createElement("h3", {
4072
+ }, /* @__PURE__ */ React19.createElement("h3", {
4023
4073
  className: "text-xl font-semibold text-white mb-4"
4024
- }, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
4074
+ }, "Search Unsplash"), /* @__PURE__ */ React19.createElement("div", {
4025
4075
  className: "flex space-x-4"
4026
- }, /* @__PURE__ */ React18.createElement("input", {
4076
+ }, /* @__PURE__ */ React19.createElement("input", {
4027
4077
  type: "text",
4028
4078
  value: unsplashQuery,
4029
4079
  onChange: (e) => setUnsplashQuery(e.target.value),
@@ -4031,59 +4081,59 @@ var CanvasEditor = forwardRef(({
4031
4081
  placeholder: "Search for images...",
4032
4082
  className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
4033
4083
  autoFocus: true
4034
- }), /* @__PURE__ */ React18.createElement("button", {
4084
+ }), /* @__PURE__ */ React19.createElement("button", {
4035
4085
  onClick: searchUnsplash,
4036
4086
  className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
4037
- }, "Search"), /* @__PURE__ */ React18.createElement("button", {
4087
+ }, "Search"), /* @__PURE__ */ React19.createElement("button", {
4038
4088
  onClick: () => {
4039
4089
  setShowUnsplash(false);
4040
4090
  setUnsplashQuery("");
4041
4091
  setUnsplashResults([]);
4042
4092
  },
4043
4093
  className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
4044
- }, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
4094
+ }, "Cancel"))), /* @__PURE__ */ React19.createElement("div", {
4045
4095
  className: "flex-1 overflow-y-auto p-6"
4046
- }, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
4096
+ }, unsplashResults.length > 0 ? /* @__PURE__ */ React19.createElement("div", {
4047
4097
  className: "grid grid-cols-3 gap-4"
4048
- }, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
4098
+ }, unsplashResults.map((result) => /* @__PURE__ */ React19.createElement("button", {
4049
4099
  key: result.id,
4050
4100
  onClick: () => addUnsplashImage(result.urls.regular),
4051
4101
  className: "relative group overflow-hidden rounded-lg aspect-square"
4052
- }, /* @__PURE__ */ React18.createElement("img", {
4102
+ }, /* @__PURE__ */ React19.createElement("img", {
4053
4103
  src: result.urls.thumb,
4054
4104
  alt: "",
4055
4105
  className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
4056
- }), /* @__PURE__ */ React18.createElement("div", {
4106
+ }), /* @__PURE__ */ React19.createElement("div", {
4057
4107
  className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
4058
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4108
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
4059
4109
  className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
4060
- }))))) : /* @__PURE__ */ React18.createElement("div", {
4110
+ }))))) : /* @__PURE__ */ React19.createElement("div", {
4061
4111
  className: "text-center text-gray-400 py-12"
4062
- }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React18.createElement("div", {
4112
+ }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React19.createElement("div", {
4063
4113
  className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
4064
- }, /* @__PURE__ */ React18.createElement("div", {
4114
+ }, /* @__PURE__ */ React19.createElement("div", {
4065
4115
  className: "bg-gray-800 rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-auto"
4066
- }, /* @__PURE__ */ React18.createElement("h2", {
4116
+ }, /* @__PURE__ */ React19.createElement("h2", {
4067
4117
  className: "text-white text-xl font-semibold mb-4"
4068
- }, "Load JSON Data"), /* @__PURE__ */ React18.createElement("p", {
4118
+ }, "Load JSON Data"), /* @__PURE__ */ React19.createElement("p", {
4069
4119
  className: "text-gray-300 mb-4"
4070
- }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React18.createElement("textarea", {
4120
+ }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React19.createElement("textarea", {
4071
4121
  value: jsonInputText,
4072
4122
  onChange: (e) => setJsonInputText(e.target.value),
4073
4123
  className: "w-full h-64 p-3 bg-gray-700 text-white border border-gray-600 rounded font-mono text-sm resize-none",
4074
4124
  placeholder: '{"width": 800, "height": 600, "pages": [...]}'
4075
- }), /* @__PURE__ */ React18.createElement("div", {
4125
+ }), /* @__PURE__ */ React19.createElement("div", {
4076
4126
  className: "flex justify-end space-x-3 mt-4"
4077
- }, /* @__PURE__ */ React18.createElement("button", {
4127
+ }, /* @__PURE__ */ React19.createElement("button", {
4078
4128
  onClick: () => {
4079
4129
  setShowJsonModal(false);
4080
4130
  setJsonInputText("");
4081
4131
  },
4082
4132
  className: "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
4083
- }, "Cancel"), /* @__PURE__ */ React18.createElement("button", {
4133
+ }, "Cancel"), /* @__PURE__ */ React19.createElement("button", {
4084
4134
  onClick: handleImportJSONData,
4085
4135
  className: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
4086
- }, "Load JSON")))));
4136
+ }, "Load JSON"))))));
4087
4137
  });
4088
4138
  var CanvasEditor_default = CanvasEditor;
4089
4139
  // src/lib/index.ts
@@ -4141,6 +4191,7 @@ function initWordPressCanvasEditor(containerId, props) {
4141
4191
  return false;
4142
4192
  }
4143
4193
  export {
4194
+ useCanvasStore,
4144
4195
  setUnsplashAccessKey,
4145
4196
  replaceUserInputs,
4146
4197
  loadTemplateFromJSON,
@@ -1 +1 @@
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;yCA4yC9E,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;AAkCjB,OAAO,EAA+B,MAAM,EAA0C,MAAM,gBAAgB,CAAC;AAI7G,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;yCAw2C9E,CAAC;AAEH,eAAe,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { CanvasStore } from "../types/Config";
3
+ declare const CanvasStoreContext: React.Context<CanvasStore>;
4
+ /**
5
+ * Hook to access the CanvasStore from any component inside CanvasEditor
6
+ * @throws Error if used outside CanvasEditor
7
+ */
8
+ export declare const useCanvasStore: () => CanvasStore;
9
+ export { CanvasStoreContext };
10
+ //# sourceMappingURL=CanvasStoreContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CanvasStoreContext.d.ts","sourceRoot":"","sources":["../../../src/context/CanvasStoreContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,QAAA,MAAM,kBAAkB,4BAA0C,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,WAMjC,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -16,6 +16,7 @@ export interface CanvasEditorRef {
16
16
  export { default as CanvasEditor } from '../CanvasEditor';
17
17
  export * from '../types';
18
18
  export type { BuiltInPanelId, CanvasStore, CustomPanelDefinition, PanelDefinition, } from '../types/Config';
19
+ export { useCanvasStore } from '../context/CanvasStoreContext';
19
20
  export { exportToPNG, exportToJPG, exportToJSON, exportToJSONObject, importFromJSON, importFromJSONData, // Import JSON data directly (no file needed)
20
21
  loadTemplateFromJSON, // Simplified template loading utility
21
22
  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,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
+ {"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,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAG/D,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"}
@@ -14,6 +14,7 @@ export interface CustomPanelDefinition {
14
14
  export type PanelDefinition = BuiltInPanelId | CustomPanelDefinition;
15
15
  export interface CanvasStore {
16
16
  activePage: {
17
+ id: string;
17
18
  addElement: (element: {
18
19
  type: string;
19
20
  src?: string;
@@ -26,6 +27,8 @@ export interface CanvasStore {
26
27
  width: number;
27
28
  height: number;
28
29
  openSidePanel: (panelId: string | null) => void;
30
+ deletePages: (pageIds: string[]) => void;
31
+ loadJSON: (jsonData: any) => Promise<void>;
29
32
  }
30
33
  export interface NavbarSection {
31
34
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/types/Config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/types/Config.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "labellife-design-tool",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Professional canvas editor built with React, TypeScript, and Konva",
5
5
  "main": "./dist/lib/lib/index.js",
6
6
  "module": "./dist/lib/lib/index.js",