labellife-design-tool 1.1.2 → 1.1.4

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,40 @@ 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
+ return (
171
+ <div style={{ color: "white", padding: 16 }}>
172
+ <p>Current page: {store.activePage.id}</p>
173
+ <p>Canvas size: {store.width} × {store.height}</p>
174
+ <button onClick={handleAddImage}>Add Image</button>
175
+ </div>
176
+ );
177
+ };
178
+ ```
179
+
180
+ **Option 2: Panel prop approach**
181
+
182
+ Every panel (built-in or custom) also receives a `store` prop with a Polotno-like API:
150
183
 
151
184
  ```tsx
152
185
  // Your custom panel component
@@ -192,6 +225,7 @@ const MyImagesPanel = ({ store }) => {
192
225
  ```typescript
193
226
  interface CanvasStore {
194
227
  activePage: {
228
+ id: string;
195
229
  addElement: (element: {
196
230
  type: string;
197
231
  src?: string;
@@ -203,9 +237,40 @@ interface CanvasStore {
203
237
  };
204
238
  width: number;
205
239
  height: number;
240
+ openSidePanel: (panelId: string | null) => void;
241
+ deletePages: (pageIds: string[]) => void;
206
242
  }
207
243
  ```
208
244
 
245
+ **Open panels programmatically**
246
+
247
+ ```tsx
248
+ const MyPanel = ({ store }) => {
249
+ const openTextPanel = () => store.openSidePanel("text");
250
+ const openCustomPanel = () => store.openSidePanel("my-custom-panel");
251
+ const closeAllPanels = () => store.openSidePanel(null);
252
+ const tryOpenUnknown = () => store.openSidePanel("nonexistent"); // closes all panels
253
+
254
+ const deletePage1 = () => store.deletePages(["page-1"]);
255
+ const deleteMultiplePages = () => store.deletePages(["page-1", "page-2", "page-3"]);
256
+
257
+ return (
258
+ <div style={{ color: "white", padding: 16 }}>
259
+ <p>Current page ID: {store.activePage.id}</p>
260
+ <p>Canvas size: {store.width} × {store.height}</p>
261
+
262
+ <button onClick={openTextPanel}>Open Text Panel</button>
263
+ <button onClick={openCustomPanel}>Open Custom Panel</button>
264
+ <button onClick={closeAllPanels}>Close All Panels</button>
265
+ <button onClick={tryOpenUnknown}>Try Unknown Panel (closes all)</button>
266
+
267
+ <button onClick={deletePage1}>Delete Page 1</button>
268
+ <button onClick={deleteMultiplePages}>Delete Multiple Pages</button>
269
+ </div>
270
+ );
271
+ };
272
+ ```
273
+
209
274
  #### Default Behavior
210
275
 
211
276
  If `config.panels` is **not provided**, the editor shows the default set:
@@ -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)}`,
@@ -3635,8 +3647,50 @@ var CanvasEditor = forwardRef(({
3635
3647
  }
3636
3648
  },
3637
3649
  width: design.width,
3638
- height: design.height
3639
- }), [currentPage.id, design.width, design.height]);
3650
+ height: design.height,
3651
+ openSidePanel: (panelId) => {
3652
+ if (!panelId) {
3653
+ setActivePanelId(null);
3654
+ return;
3655
+ }
3656
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : [
3657
+ "text",
3658
+ "elements",
3659
+ "image",
3660
+ "design",
3661
+ "background",
3662
+ ...config?.variables ? ["variables"] : [],
3663
+ ...config?.export ? ["export"] : []
3664
+ ];
3665
+ const panelExists = requestedPanels.some((p) => typeof p === "string" ? p === panelId : p.id === panelId);
3666
+ if (panelExists) {
3667
+ setActivePanelId(panelId);
3668
+ } else {
3669
+ setActivePanelId(null);
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
+ }), [currentPage.id, design.width, design.height, config, setActivePanelId]);
3640
3694
  const panelConfigs = useMemo(() => {
3641
3695
  const builtInConfigs = {
3642
3696
  elements: {
@@ -3797,12 +3851,12 @@ var CanvasEditor = forwardRef(({
3797
3851
  const DynamicPanelRenderer = () => {
3798
3852
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3799
3853
  if (!activePanelConfig) {
3800
- return /* @__PURE__ */ React18.createElement("div", {
3854
+ return /* @__PURE__ */ React19.createElement("div", {
3801
3855
  className: "text-white"
3802
3856
  }, "Panel not found");
3803
3857
  }
3804
3858
  const PanelComponent = activePanelConfig.component;
3805
- return /* @__PURE__ */ React18.createElement(PanelComponent, {
3859
+ return /* @__PURE__ */ React19.createElement(PanelComponent, {
3806
3860
  ...activePanelConfig.props
3807
3861
  });
3808
3862
  };
@@ -3855,9 +3909,11 @@ var CanvasEditor = forwardRef(({
3855
3909
  setHistoryIndex(0);
3856
3910
  }
3857
3911
  }, []);
3858
- return /* @__PURE__ */ React18.createElement("div", {
3912
+ return /* @__PURE__ */ React19.createElement(CanvasStoreContext.Provider, {
3913
+ value: store
3914
+ }, /* @__PURE__ */ React19.createElement("div", {
3859
3915
  className: "h-screen flex flex-col bg-gray-900"
3860
- }, /* @__PURE__ */ React18.createElement(Header_default, {
3916
+ }, /* @__PURE__ */ React19.createElement(Header_default, {
3861
3917
  name,
3862
3918
  zoom,
3863
3919
  historyIndex,
@@ -3869,37 +3925,37 @@ var CanvasEditor = forwardRef(({
3869
3925
  onZoomReset: () => setZoom(calculateFitToScreenZoom(design.width, design.height)),
3870
3926
  onSetActivePanel: setActivePanelId,
3871
3927
  navbarConfig: config?.navbar
3872
- }), /* @__PURE__ */ React18.createElement("div", {
3928
+ }), /* @__PURE__ */ React19.createElement("div", {
3873
3929
  className: "flex-1 flex overflow-hidden"
3874
- }, /* @__PURE__ */ React18.createElement("div", {
3930
+ }, /* @__PURE__ */ React19.createElement("div", {
3875
3931
  className: "w-80 bg-gray-800 border-r border-gray-700 flex"
3876
- }, /* @__PURE__ */ React18.createElement(LeftMenu_default, {
3932
+ }, /* @__PURE__ */ React19.createElement(LeftMenu_default, {
3877
3933
  tool,
3878
3934
  activePanel: activePanelId,
3879
3935
  onSetTool: setTool,
3880
3936
  onSetActivePanel: setActivePanelId,
3881
3937
  config
3882
- }), /* @__PURE__ */ React18.createElement("div", {
3938
+ }), /* @__PURE__ */ React19.createElement("div", {
3883
3939
  className: "flex-1 p-4 overflow-y-auto"
3884
- }, /* @__PURE__ */ React18.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React18.createElement("div", {
3940
+ }, /* @__PURE__ */ React19.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React19.createElement("div", {
3885
3941
  className: "flex-1 bg-gray-700 overflow-hidden relative",
3886
3942
  ref: containerRef
3887
- }, /* @__PURE__ */ React18.createElement("div", {
3943
+ }, /* @__PURE__ */ React19.createElement("div", {
3888
3944
  className: "absolute inset-0 flex items-center justify-center"
3889
- }, /* @__PURE__ */ React18.createElement("div", {
3945
+ }, /* @__PURE__ */ React19.createElement("div", {
3890
3946
  className: "bg-white shadow-2xl",
3891
3947
  style: {
3892
3948
  transform: `scale(${zoom})`,
3893
3949
  transformOrigin: "center center"
3894
3950
  }
3895
- }, /* @__PURE__ */ React18.createElement(Stage, {
3951
+ }, /* @__PURE__ */ React19.createElement(Stage, {
3896
3952
  key: `canvas-${design.id || design.width}-${design.height}`,
3897
3953
  ref: stageRef,
3898
3954
  width: design.width,
3899
3955
  height: design.height,
3900
3956
  onClick: handleStageClick,
3901
3957
  onTap: handleStageClick
3902
- }, /* @__PURE__ */ React18.createElement(Layer, null, /* @__PURE__ */ React18.createElement(Rect2, {
3958
+ }, /* @__PURE__ */ React19.createElement(Layer, null, /* @__PURE__ */ React19.createElement(Rect2, {
3903
3959
  x: 0,
3904
3960
  y: 0,
3905
3961
  width: design.width,
@@ -3910,7 +3966,7 @@ var CanvasEditor = forwardRef(({
3910
3966
  }), currentPage.elements.map((element) => {
3911
3967
  switch (element.type) {
3912
3968
  case "text":
3913
- return React18.createElement(EditableTextElement, {
3969
+ return React19.createElement(EditableTextElement, {
3914
3970
  key: element.id,
3915
3971
  element,
3916
3972
  isSelected: element.id === selectedId,
@@ -3921,7 +3977,7 @@ var CanvasEditor = forwardRef(({
3921
3977
  onChange: (attrs) => updateElement(element.id, attrs)
3922
3978
  });
3923
3979
  case "image":
3924
- return React18.createElement(UrlImageElement, {
3980
+ return React19.createElement(UrlImageElement, {
3925
3981
  key: element.id,
3926
3982
  element,
3927
3983
  isSelected: element.id === selectedId,
@@ -3932,7 +3988,7 @@ var CanvasEditor = forwardRef(({
3932
3988
  onChange: (attrs) => updateElement(element.id, attrs)
3933
3989
  });
3934
3990
  case "shape":
3935
- return React18.createElement(ShapeElement, {
3991
+ return React19.createElement(ShapeElement, {
3936
3992
  key: element.id,
3937
3993
  element,
3938
3994
  isSelected: element.id === selectedId,
@@ -3945,27 +4001,27 @@ var CanvasEditor = forwardRef(({
3945
4001
  default:
3946
4002
  return null;
3947
4003
  }
3948
- }))))), config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
4004
+ }))))), config?.multiPage && /* @__PURE__ */ React19.createElement("div", {
3949
4005
  className: "absolute bottom-4 left-4 flex items-center space-x-2"
3950
- }, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("div", {
4006
+ }, design.pages.map((page, index) => /* @__PURE__ */ React19.createElement("div", {
3951
4007
  key: page.id,
3952
4008
  className: "relative group"
3953
- }, /* @__PURE__ */ React18.createElement("button", {
4009
+ }, /* @__PURE__ */ React19.createElement("button", {
3954
4010
  onClick: () => setCurrentPageId(page.id),
3955
4011
  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"}`
3956
- }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React18.createElement("button", {
4012
+ }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React19.createElement("button", {
3957
4013
  onClick: () => deletePage(page.id),
3958
4014
  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",
3959
4015
  title: `Delete Page ${index + 1}`
3960
- }, /* @__PURE__ */ React18.createElement(X2, {
4016
+ }, /* @__PURE__ */ React19.createElement(X2, {
3961
4017
  className: "w-3 h-3"
3962
- })))), /* @__PURE__ */ React18.createElement("button", {
4018
+ })))), /* @__PURE__ */ React19.createElement("button", {
3963
4019
  onClick: addPage,
3964
4020
  className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
3965
4021
  title: "Add Page"
3966
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4022
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
3967
4023
  className: "w-4 h-4"
3968
- })))), /* @__PURE__ */ React18.createElement(RightSidebar_default, {
4024
+ })))), /* @__PURE__ */ React19.createElement(RightSidebar_default, {
3969
4025
  currentPageElements: currentPage.elements,
3970
4026
  selectedElement,
3971
4027
  selectedId,
@@ -3975,34 +4031,34 @@ var CanvasEditor = forwardRef(({
3975
4031
  onMoveElementUp: moveElementUp,
3976
4032
  onMoveElementDown: moveElementDown,
3977
4033
  onDeleteSelected: deleteSelected
3978
- })), /* @__PURE__ */ React18.createElement("input", {
4034
+ })), /* @__PURE__ */ React19.createElement("input", {
3979
4035
  ref: fileInputRef,
3980
4036
  type: "file",
3981
4037
  accept: "image/*",
3982
4038
  onChange: handleImageUpload,
3983
4039
  className: "hidden",
3984
4040
  multiple: true
3985
- }), /* @__PURE__ */ React18.createElement("input", {
4041
+ }), /* @__PURE__ */ React19.createElement("input", {
3986
4042
  ref: jsonInputRef,
3987
4043
  type: "file",
3988
4044
  accept: ".json",
3989
4045
  onChange: handleImportJSON,
3990
4046
  className: "hidden"
3991
- }), showInputModal && /* @__PURE__ */ React18.createElement(TemplateInputModal_default, {
4047
+ }), showInputModal && /* @__PURE__ */ React19.createElement(TemplateInputModal_default, {
3992
4048
  inputs: pendingInputs,
3993
4049
  onComplete: handleInputModalComplete,
3994
4050
  onCancel: handleInputModalCancel
3995
- }), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
4051
+ }), showUnsplash && /* @__PURE__ */ React19.createElement("div", {
3996
4052
  className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
3997
- }, /* @__PURE__ */ React18.createElement("div", {
4053
+ }, /* @__PURE__ */ React19.createElement("div", {
3998
4054
  className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
3999
- }, /* @__PURE__ */ React18.createElement("div", {
4055
+ }, /* @__PURE__ */ React19.createElement("div", {
4000
4056
  className: "p-6 border-b border-gray-700"
4001
- }, /* @__PURE__ */ React18.createElement("h3", {
4057
+ }, /* @__PURE__ */ React19.createElement("h3", {
4002
4058
  className: "text-xl font-semibold text-white mb-4"
4003
- }, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
4059
+ }, "Search Unsplash"), /* @__PURE__ */ React19.createElement("div", {
4004
4060
  className: "flex space-x-4"
4005
- }, /* @__PURE__ */ React18.createElement("input", {
4061
+ }, /* @__PURE__ */ React19.createElement("input", {
4006
4062
  type: "text",
4007
4063
  value: unsplashQuery,
4008
4064
  onChange: (e) => setUnsplashQuery(e.target.value),
@@ -4010,64 +4066,65 @@ var CanvasEditor = forwardRef(({
4010
4066
  placeholder: "Search for images...",
4011
4067
  className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
4012
4068
  autoFocus: true
4013
- }), /* @__PURE__ */ React18.createElement("button", {
4069
+ }), /* @__PURE__ */ React19.createElement("button", {
4014
4070
  onClick: searchUnsplash,
4015
4071
  className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
4016
- }, "Search"), /* @__PURE__ */ React18.createElement("button", {
4072
+ }, "Search"), /* @__PURE__ */ React19.createElement("button", {
4017
4073
  onClick: () => {
4018
4074
  setShowUnsplash(false);
4019
4075
  setUnsplashQuery("");
4020
4076
  setUnsplashResults([]);
4021
4077
  },
4022
4078
  className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
4023
- }, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
4079
+ }, "Cancel"))), /* @__PURE__ */ React19.createElement("div", {
4024
4080
  className: "flex-1 overflow-y-auto p-6"
4025
- }, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
4081
+ }, unsplashResults.length > 0 ? /* @__PURE__ */ React19.createElement("div", {
4026
4082
  className: "grid grid-cols-3 gap-4"
4027
- }, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
4083
+ }, unsplashResults.map((result) => /* @__PURE__ */ React19.createElement("button", {
4028
4084
  key: result.id,
4029
4085
  onClick: () => addUnsplashImage(result.urls.regular),
4030
4086
  className: "relative group overflow-hidden rounded-lg aspect-square"
4031
- }, /* @__PURE__ */ React18.createElement("img", {
4087
+ }, /* @__PURE__ */ React19.createElement("img", {
4032
4088
  src: result.urls.thumb,
4033
4089
  alt: "",
4034
4090
  className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
4035
- }), /* @__PURE__ */ React18.createElement("div", {
4091
+ }), /* @__PURE__ */ React19.createElement("div", {
4036
4092
  className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
4037
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4093
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
4038
4094
  className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
4039
- }))))) : /* @__PURE__ */ React18.createElement("div", {
4095
+ }))))) : /* @__PURE__ */ React19.createElement("div", {
4040
4096
  className: "text-center text-gray-400 py-12"
4041
- }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React18.createElement("div", {
4097
+ }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React19.createElement("div", {
4042
4098
  className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
4043
- }, /* @__PURE__ */ React18.createElement("div", {
4099
+ }, /* @__PURE__ */ React19.createElement("div", {
4044
4100
  className: "bg-gray-800 rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-auto"
4045
- }, /* @__PURE__ */ React18.createElement("h2", {
4101
+ }, /* @__PURE__ */ React19.createElement("h2", {
4046
4102
  className: "text-white text-xl font-semibold mb-4"
4047
- }, "Load JSON Data"), /* @__PURE__ */ React18.createElement("p", {
4103
+ }, "Load JSON Data"), /* @__PURE__ */ React19.createElement("p", {
4048
4104
  className: "text-gray-300 mb-4"
4049
- }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React18.createElement("textarea", {
4105
+ }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React19.createElement("textarea", {
4050
4106
  value: jsonInputText,
4051
4107
  onChange: (e) => setJsonInputText(e.target.value),
4052
4108
  className: "w-full h-64 p-3 bg-gray-700 text-white border border-gray-600 rounded font-mono text-sm resize-none",
4053
4109
  placeholder: '{"width": 800, "height": 600, "pages": [...]}'
4054
- }), /* @__PURE__ */ React18.createElement("div", {
4110
+ }), /* @__PURE__ */ React19.createElement("div", {
4055
4111
  className: "flex justify-end space-x-3 mt-4"
4056
- }, /* @__PURE__ */ React18.createElement("button", {
4112
+ }, /* @__PURE__ */ React19.createElement("button", {
4057
4113
  onClick: () => {
4058
4114
  setShowJsonModal(false);
4059
4115
  setJsonInputText("");
4060
4116
  },
4061
4117
  className: "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
4062
- }, "Cancel"), /* @__PURE__ */ React18.createElement("button", {
4118
+ }, "Cancel"), /* @__PURE__ */ React19.createElement("button", {
4063
4119
  onClick: handleImportJSONData,
4064
4120
  className: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
4065
- }, "Load JSON")))));
4121
+ }, "Load JSON"))))));
4066
4122
  });
4067
4123
  var CanvasEditor_default = CanvasEditor;
4068
4124
  // src/lib/index.ts
4069
4125
  initJsxCompat();
4070
4126
  export {
4127
+ useCanvasStore,
4071
4128
  setUnsplashAccessKey,
4072
4129
  replaceUserInputs,
4073
4130
  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)}`,
@@ -3635,8 +3647,50 @@ var CanvasEditor = forwardRef(({
3635
3647
  }
3636
3648
  },
3637
3649
  width: design.width,
3638
- height: design.height
3639
- }), [currentPage.id, design.width, design.height]);
3650
+ height: design.height,
3651
+ openSidePanel: (panelId) => {
3652
+ if (!panelId) {
3653
+ setActivePanelId(null);
3654
+ return;
3655
+ }
3656
+ const requestedPanels = config?.panels && config.panels.length > 0 ? config.panels : [
3657
+ "text",
3658
+ "elements",
3659
+ "image",
3660
+ "design",
3661
+ "background",
3662
+ ...config?.variables ? ["variables"] : [],
3663
+ ...config?.export ? ["export"] : []
3664
+ ];
3665
+ const panelExists = requestedPanels.some((p) => typeof p === "string" ? p === panelId : p.id === panelId);
3666
+ if (panelExists) {
3667
+ setActivePanelId(panelId);
3668
+ } else {
3669
+ setActivePanelId(null);
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
+ }), [currentPage.id, design.width, design.height, config, setActivePanelId]);
3640
3694
  const panelConfigs = useMemo(() => {
3641
3695
  const builtInConfigs = {
3642
3696
  elements: {
@@ -3797,12 +3851,12 @@ var CanvasEditor = forwardRef(({
3797
3851
  const DynamicPanelRenderer = () => {
3798
3852
  const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3799
3853
  if (!activePanelConfig) {
3800
- return /* @__PURE__ */ React18.createElement("div", {
3854
+ return /* @__PURE__ */ React19.createElement("div", {
3801
3855
  className: "text-white"
3802
3856
  }, "Panel not found");
3803
3857
  }
3804
3858
  const PanelComponent = activePanelConfig.component;
3805
- return /* @__PURE__ */ React18.createElement(PanelComponent, {
3859
+ return /* @__PURE__ */ React19.createElement(PanelComponent, {
3806
3860
  ...activePanelConfig.props
3807
3861
  });
3808
3862
  };
@@ -3855,9 +3909,11 @@ var CanvasEditor = forwardRef(({
3855
3909
  setHistoryIndex(0);
3856
3910
  }
3857
3911
  }, []);
3858
- return /* @__PURE__ */ React18.createElement("div", {
3912
+ return /* @__PURE__ */ React19.createElement(CanvasStoreContext.Provider, {
3913
+ value: store
3914
+ }, /* @__PURE__ */ React19.createElement("div", {
3859
3915
  className: "h-screen flex flex-col bg-gray-900"
3860
- }, /* @__PURE__ */ React18.createElement(Header_default, {
3916
+ }, /* @__PURE__ */ React19.createElement(Header_default, {
3861
3917
  name,
3862
3918
  zoom,
3863
3919
  historyIndex,
@@ -3869,37 +3925,37 @@ var CanvasEditor = forwardRef(({
3869
3925
  onZoomReset: () => setZoom(calculateFitToScreenZoom(design.width, design.height)),
3870
3926
  onSetActivePanel: setActivePanelId,
3871
3927
  navbarConfig: config?.navbar
3872
- }), /* @__PURE__ */ React18.createElement("div", {
3928
+ }), /* @__PURE__ */ React19.createElement("div", {
3873
3929
  className: "flex-1 flex overflow-hidden"
3874
- }, /* @__PURE__ */ React18.createElement("div", {
3930
+ }, /* @__PURE__ */ React19.createElement("div", {
3875
3931
  className: "w-80 bg-gray-800 border-r border-gray-700 flex"
3876
- }, /* @__PURE__ */ React18.createElement(LeftMenu_default, {
3932
+ }, /* @__PURE__ */ React19.createElement(LeftMenu_default, {
3877
3933
  tool,
3878
3934
  activePanel: activePanelId,
3879
3935
  onSetTool: setTool,
3880
3936
  onSetActivePanel: setActivePanelId,
3881
3937
  config
3882
- }), /* @__PURE__ */ React18.createElement("div", {
3938
+ }), /* @__PURE__ */ React19.createElement("div", {
3883
3939
  className: "flex-1 p-4 overflow-y-auto"
3884
- }, /* @__PURE__ */ React18.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React18.createElement("div", {
3940
+ }, /* @__PURE__ */ React19.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React19.createElement("div", {
3885
3941
  className: "flex-1 bg-gray-700 overflow-hidden relative",
3886
3942
  ref: containerRef
3887
- }, /* @__PURE__ */ React18.createElement("div", {
3943
+ }, /* @__PURE__ */ React19.createElement("div", {
3888
3944
  className: "absolute inset-0 flex items-center justify-center"
3889
- }, /* @__PURE__ */ React18.createElement("div", {
3945
+ }, /* @__PURE__ */ React19.createElement("div", {
3890
3946
  className: "bg-white shadow-2xl",
3891
3947
  style: {
3892
3948
  transform: `scale(${zoom})`,
3893
3949
  transformOrigin: "center center"
3894
3950
  }
3895
- }, /* @__PURE__ */ React18.createElement(Stage, {
3951
+ }, /* @__PURE__ */ React19.createElement(Stage, {
3896
3952
  key: `canvas-${design.id || design.width}-${design.height}`,
3897
3953
  ref: stageRef,
3898
3954
  width: design.width,
3899
3955
  height: design.height,
3900
3956
  onClick: handleStageClick,
3901
3957
  onTap: handleStageClick
3902
- }, /* @__PURE__ */ React18.createElement(Layer, null, /* @__PURE__ */ React18.createElement(Rect2, {
3958
+ }, /* @__PURE__ */ React19.createElement(Layer, null, /* @__PURE__ */ React19.createElement(Rect2, {
3903
3959
  x: 0,
3904
3960
  y: 0,
3905
3961
  width: design.width,
@@ -3910,7 +3966,7 @@ var CanvasEditor = forwardRef(({
3910
3966
  }), currentPage.elements.map((element) => {
3911
3967
  switch (element.type) {
3912
3968
  case "text":
3913
- return React18.createElement(EditableTextElement, {
3969
+ return React19.createElement(EditableTextElement, {
3914
3970
  key: element.id,
3915
3971
  element,
3916
3972
  isSelected: element.id === selectedId,
@@ -3921,7 +3977,7 @@ var CanvasEditor = forwardRef(({
3921
3977
  onChange: (attrs) => updateElement(element.id, attrs)
3922
3978
  });
3923
3979
  case "image":
3924
- return React18.createElement(UrlImageElement, {
3980
+ return React19.createElement(UrlImageElement, {
3925
3981
  key: element.id,
3926
3982
  element,
3927
3983
  isSelected: element.id === selectedId,
@@ -3932,7 +3988,7 @@ var CanvasEditor = forwardRef(({
3932
3988
  onChange: (attrs) => updateElement(element.id, attrs)
3933
3989
  });
3934
3990
  case "shape":
3935
- return React18.createElement(ShapeElement, {
3991
+ return React19.createElement(ShapeElement, {
3936
3992
  key: element.id,
3937
3993
  element,
3938
3994
  isSelected: element.id === selectedId,
@@ -3945,27 +4001,27 @@ var CanvasEditor = forwardRef(({
3945
4001
  default:
3946
4002
  return null;
3947
4003
  }
3948
- }))))), config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
4004
+ }))))), config?.multiPage && /* @__PURE__ */ React19.createElement("div", {
3949
4005
  className: "absolute bottom-4 left-4 flex items-center space-x-2"
3950
- }, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("div", {
4006
+ }, design.pages.map((page, index) => /* @__PURE__ */ React19.createElement("div", {
3951
4007
  key: page.id,
3952
4008
  className: "relative group"
3953
- }, /* @__PURE__ */ React18.createElement("button", {
4009
+ }, /* @__PURE__ */ React19.createElement("button", {
3954
4010
  onClick: () => setCurrentPageId(page.id),
3955
4011
  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"}`
3956
- }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React18.createElement("button", {
4012
+ }, "Page ", index + 1), design.pages.length > 1 && /* @__PURE__ */ React19.createElement("button", {
3957
4013
  onClick: () => deletePage(page.id),
3958
4014
  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",
3959
4015
  title: `Delete Page ${index + 1}`
3960
- }, /* @__PURE__ */ React18.createElement(X2, {
4016
+ }, /* @__PURE__ */ React19.createElement(X2, {
3961
4017
  className: "w-3 h-3"
3962
- })))), /* @__PURE__ */ React18.createElement("button", {
4018
+ })))), /* @__PURE__ */ React19.createElement("button", {
3963
4019
  onClick: addPage,
3964
4020
  className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
3965
4021
  title: "Add Page"
3966
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4022
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
3967
4023
  className: "w-4 h-4"
3968
- })))), /* @__PURE__ */ React18.createElement(RightSidebar_default, {
4024
+ })))), /* @__PURE__ */ React19.createElement(RightSidebar_default, {
3969
4025
  currentPageElements: currentPage.elements,
3970
4026
  selectedElement,
3971
4027
  selectedId,
@@ -3975,34 +4031,34 @@ var CanvasEditor = forwardRef(({
3975
4031
  onMoveElementUp: moveElementUp,
3976
4032
  onMoveElementDown: moveElementDown,
3977
4033
  onDeleteSelected: deleteSelected
3978
- })), /* @__PURE__ */ React18.createElement("input", {
4034
+ })), /* @__PURE__ */ React19.createElement("input", {
3979
4035
  ref: fileInputRef,
3980
4036
  type: "file",
3981
4037
  accept: "image/*",
3982
4038
  onChange: handleImageUpload,
3983
4039
  className: "hidden",
3984
4040
  multiple: true
3985
- }), /* @__PURE__ */ React18.createElement("input", {
4041
+ }), /* @__PURE__ */ React19.createElement("input", {
3986
4042
  ref: jsonInputRef,
3987
4043
  type: "file",
3988
4044
  accept: ".json",
3989
4045
  onChange: handleImportJSON,
3990
4046
  className: "hidden"
3991
- }), showInputModal && /* @__PURE__ */ React18.createElement(TemplateInputModal_default, {
4047
+ }), showInputModal && /* @__PURE__ */ React19.createElement(TemplateInputModal_default, {
3992
4048
  inputs: pendingInputs,
3993
4049
  onComplete: handleInputModalComplete,
3994
4050
  onCancel: handleInputModalCancel
3995
- }), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
4051
+ }), showUnsplash && /* @__PURE__ */ React19.createElement("div", {
3996
4052
  className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
3997
- }, /* @__PURE__ */ React18.createElement("div", {
4053
+ }, /* @__PURE__ */ React19.createElement("div", {
3998
4054
  className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
3999
- }, /* @__PURE__ */ React18.createElement("div", {
4055
+ }, /* @__PURE__ */ React19.createElement("div", {
4000
4056
  className: "p-6 border-b border-gray-700"
4001
- }, /* @__PURE__ */ React18.createElement("h3", {
4057
+ }, /* @__PURE__ */ React19.createElement("h3", {
4002
4058
  className: "text-xl font-semibold text-white mb-4"
4003
- }, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
4059
+ }, "Search Unsplash"), /* @__PURE__ */ React19.createElement("div", {
4004
4060
  className: "flex space-x-4"
4005
- }, /* @__PURE__ */ React18.createElement("input", {
4061
+ }, /* @__PURE__ */ React19.createElement("input", {
4006
4062
  type: "text",
4007
4063
  value: unsplashQuery,
4008
4064
  onChange: (e) => setUnsplashQuery(e.target.value),
@@ -4010,59 +4066,59 @@ var CanvasEditor = forwardRef(({
4010
4066
  placeholder: "Search for images...",
4011
4067
  className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
4012
4068
  autoFocus: true
4013
- }), /* @__PURE__ */ React18.createElement("button", {
4069
+ }), /* @__PURE__ */ React19.createElement("button", {
4014
4070
  onClick: searchUnsplash,
4015
4071
  className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
4016
- }, "Search"), /* @__PURE__ */ React18.createElement("button", {
4072
+ }, "Search"), /* @__PURE__ */ React19.createElement("button", {
4017
4073
  onClick: () => {
4018
4074
  setShowUnsplash(false);
4019
4075
  setUnsplashQuery("");
4020
4076
  setUnsplashResults([]);
4021
4077
  },
4022
4078
  className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
4023
- }, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
4079
+ }, "Cancel"))), /* @__PURE__ */ React19.createElement("div", {
4024
4080
  className: "flex-1 overflow-y-auto p-6"
4025
- }, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
4081
+ }, unsplashResults.length > 0 ? /* @__PURE__ */ React19.createElement("div", {
4026
4082
  className: "grid grid-cols-3 gap-4"
4027
- }, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
4083
+ }, unsplashResults.map((result) => /* @__PURE__ */ React19.createElement("button", {
4028
4084
  key: result.id,
4029
4085
  onClick: () => addUnsplashImage(result.urls.regular),
4030
4086
  className: "relative group overflow-hidden rounded-lg aspect-square"
4031
- }, /* @__PURE__ */ React18.createElement("img", {
4087
+ }, /* @__PURE__ */ React19.createElement("img", {
4032
4088
  src: result.urls.thumb,
4033
4089
  alt: "",
4034
4090
  className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
4035
- }), /* @__PURE__ */ React18.createElement("div", {
4091
+ }), /* @__PURE__ */ React19.createElement("div", {
4036
4092
  className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
4037
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4093
+ }, /* @__PURE__ */ React19.createElement(PlusCircle, {
4038
4094
  className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
4039
- }))))) : /* @__PURE__ */ React18.createElement("div", {
4095
+ }))))) : /* @__PURE__ */ React19.createElement("div", {
4040
4096
  className: "text-center text-gray-400 py-12"
4041
- }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React18.createElement("div", {
4097
+ }, "Enter a search term to find images")))), showJsonModal && /* @__PURE__ */ React19.createElement("div", {
4042
4098
  className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
4043
- }, /* @__PURE__ */ React18.createElement("div", {
4099
+ }, /* @__PURE__ */ React19.createElement("div", {
4044
4100
  className: "bg-gray-800 rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-auto"
4045
- }, /* @__PURE__ */ React18.createElement("h2", {
4101
+ }, /* @__PURE__ */ React19.createElement("h2", {
4046
4102
  className: "text-white text-xl font-semibold mb-4"
4047
- }, "Load JSON Data"), /* @__PURE__ */ React18.createElement("p", {
4103
+ }, "Load JSON Data"), /* @__PURE__ */ React19.createElement("p", {
4048
4104
  className: "text-gray-300 mb-4"
4049
- }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React18.createElement("textarea", {
4105
+ }, 'Paste your JSON template data below and click "Load" to import it into the canvas.'), /* @__PURE__ */ React19.createElement("textarea", {
4050
4106
  value: jsonInputText,
4051
4107
  onChange: (e) => setJsonInputText(e.target.value),
4052
4108
  className: "w-full h-64 p-3 bg-gray-700 text-white border border-gray-600 rounded font-mono text-sm resize-none",
4053
4109
  placeholder: '{"width": 800, "height": 600, "pages": [...]}'
4054
- }), /* @__PURE__ */ React18.createElement("div", {
4110
+ }), /* @__PURE__ */ React19.createElement("div", {
4055
4111
  className: "flex justify-end space-x-3 mt-4"
4056
- }, /* @__PURE__ */ React18.createElement("button", {
4112
+ }, /* @__PURE__ */ React19.createElement("button", {
4057
4113
  onClick: () => {
4058
4114
  setShowJsonModal(false);
4059
4115
  setJsonInputText("");
4060
4116
  },
4061
4117
  className: "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
4062
- }, "Cancel"), /* @__PURE__ */ React18.createElement("button", {
4118
+ }, "Cancel"), /* @__PURE__ */ React19.createElement("button", {
4063
4119
  onClick: handleImportJSONData,
4064
4120
  className: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
4065
- }, "Load JSON")))));
4121
+ }, "Load JSON"))))));
4066
4122
  });
4067
4123
  var CanvasEditor_default = CanvasEditor;
4068
4124
  // src/lib/index.ts
@@ -4120,6 +4176,7 @@ function initWordPressCanvasEditor(containerId, props) {
4120
4176
  return false;
4121
4177
  }
4122
4178
  export {
4179
+ useCanvasStore,
4123
4180
  setUnsplashAccessKey,
4124
4181
  replaceUserInputs,
4125
4182
  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;yCA4wC9E,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;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;yCAo1C9E,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;
@@ -25,6 +26,8 @@ export interface CanvasStore {
25
26
  };
26
27
  width: number;
27
28
  height: number;
29
+ openSidePanel: (panelId: string | null) => void;
30
+ deletePages: (pageIds: string[]) => void;
28
31
  }
29
32
  export interface NavbarSection {
30
33
  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.2",
3
+ "version": "1.1.4",
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",