labellife-design-tool 1.2.9 → 1.3.0

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.
@@ -547,7 +547,7 @@ function initJsxCompat() {
547
547
  }
548
548
 
549
549
  // src/CanvasEditor.tsx
550
- import React18, { useState as useState3, useRef as useRef5, useEffect as useEffect4, useMemo, useCallback as useCallback4 } from "react";
550
+ import React17, { useRef as useRef4, useEffect as useEffect4, useMemo, useCallback as useCallback4 } from "react";
551
551
  import { Stage, Layer, Rect as Rect2 } from "react-konva";
552
552
  import {
553
553
  PlusCircle
@@ -1361,61 +1361,6 @@ var UrlImageElement = ({ element, isSelected, onSelect, onChange }) => {
1361
1361
  }
1362
1362
  }));
1363
1363
  };
1364
- // src/constants/CanvasPresets.ts
1365
- var CANVAS_PRESETS = [
1366
- { name: "Instagram Post", width: 1080, height: 1080 },
1367
- { name: "Instagram Story", width: 1080, height: 1920 },
1368
- { name: "Facebook Post", width: 1200, height: 630 },
1369
- { name: "Twitter Post", width: 1024, height: 512 },
1370
- { name: "A4", width: 794, height: 1123 },
1371
- { name: "Letter", width: 816, height: 1056 },
1372
- { name: "YouTube Thumbnail", width: 1280, height: 720 },
1373
- { name: "Custom", width: 800, height: 600 }
1374
- ];
1375
- // src/constants/DefaultColors.ts
1376
- var DEFAULT_COLORS = [
1377
- "#000000",
1378
- "#FFFFFF",
1379
- "#FF0000",
1380
- "#00FF00",
1381
- "#0000FF",
1382
- "#FFFF00",
1383
- "#FF00FF",
1384
- "#00FFFF",
1385
- "#FFA500",
1386
- "#800080",
1387
- "#FFC0CB",
1388
- "#A52A2A",
1389
- "#808080",
1390
- "#C0C0C0",
1391
- "#FFD700"
1392
- ];
1393
- // src/constants/FontFamilies.ts
1394
- var FONT_FAMILIES = [
1395
- "Arial",
1396
- "Helvetica",
1397
- "Times New Roman",
1398
- "Georgia",
1399
- "Verdana",
1400
- "Courier New",
1401
- "Comic Sans MS",
1402
- "Impact",
1403
- "Trebuchet MS",
1404
- "Palatino",
1405
- "Garamond",
1406
- "Bookman",
1407
- "Tahoma"
1408
- ];
1409
- // src/config.ts
1410
- var _unsplashAccessKey = typeof process !== "undefined" && process.env?.UNSPLASH_ACCESS_KEY ? process.env.UNSPLASH_ACCESS_KEY : undefined;
1411
- var UNSPLASH_ACCESS_KEY = _unsplashAccessKey || "YOUR_UNSPLASH_ACCESS_KEY_HERE";
1412
- function setUnsplashAccessKey(key) {
1413
- _unsplashAccessKey = key;
1414
- }
1415
- function getUnsplashAccessKey() {
1416
- return _unsplashAccessKey;
1417
- }
1418
-
1419
1364
  // src/components/Header.tsx
1420
1365
  import React7 from "react";
1421
1366
 
@@ -1879,6 +1824,53 @@ var ElementPanel_default = ElementPanel;
1879
1824
 
1880
1825
  // src/panels/TextPanel.tsx
1881
1826
  import React10 from "react";
1827
+
1828
+ // src/constants/CanvasPresets.ts
1829
+ var CANVAS_PRESETS = [
1830
+ { name: "Instagram Post", width: 1080, height: 1080 },
1831
+ { name: "Instagram Story", width: 1080, height: 1920 },
1832
+ { name: "Facebook Post", width: 1200, height: 630 },
1833
+ { name: "Twitter Post", width: 1024, height: 512 },
1834
+ { name: "A4", width: 794, height: 1123 },
1835
+ { name: "Letter", width: 816, height: 1056 },
1836
+ { name: "YouTube Thumbnail", width: 1280, height: 720 },
1837
+ { name: "Custom", width: 800, height: 600 }
1838
+ ];
1839
+ // src/constants/DefaultColors.ts
1840
+ var DEFAULT_COLORS = [
1841
+ "#000000",
1842
+ "#FFFFFF",
1843
+ "#FF0000",
1844
+ "#00FF00",
1845
+ "#0000FF",
1846
+ "#FFFF00",
1847
+ "#FF00FF",
1848
+ "#00FFFF",
1849
+ "#FFA500",
1850
+ "#800080",
1851
+ "#FFC0CB",
1852
+ "#A52A2A",
1853
+ "#808080",
1854
+ "#C0C0C0",
1855
+ "#FFD700"
1856
+ ];
1857
+ // src/constants/FontFamilies.ts
1858
+ var FONT_FAMILIES = [
1859
+ "Arial",
1860
+ "Helvetica",
1861
+ "Times New Roman",
1862
+ "Georgia",
1863
+ "Verdana",
1864
+ "Courier New",
1865
+ "Comic Sans MS",
1866
+ "Impact",
1867
+ "Trebuchet MS",
1868
+ "Palatino",
1869
+ "Garamond",
1870
+ "Bookman",
1871
+ "Tahoma"
1872
+ ];
1873
+ // src/panels/TextPanel.tsx
1882
1874
  import {
1883
1875
  Bold,
1884
1876
  Italic,
@@ -2725,394 +2717,16 @@ var RightSidebar = ({
2725
2717
  }), /* @__PURE__ */ React16.createElement("span", null, "Delete"))));
2726
2718
  };
2727
2719
  var RightSidebar_default = RightSidebar;
2728
- // src/components/TemplateInputModal.tsx
2729
- import React17, { useState as useState2, useRef as useRef4 } from "react";
2730
- import { X, Upload as Upload2, Image as ImageIcon4, ChevronLeft, ChevronRight } from "lucide-react";
2731
- var TemplateInputModal = ({
2732
- inputs,
2733
- onComplete,
2734
- onCancel
2735
- }) => {
2736
- const isLightTheme = document.title.includes("Light Theme");
2737
- const modalStyle = {
2738
- backgroundColor: isLightTheme ? "#f8fafc" : "#1f2937",
2739
- color: isLightTheme ? "#0f172a" : "#ffffff",
2740
- borderColor: isLightTheme ? "#cbd5e1" : "#374151",
2741
- boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
2742
- };
2743
- const headerStyle = {
2744
- borderBottomColor: isLightTheme ? "#e2e8f0" : "#374151",
2745
- borderBottomWidth: "1px",
2746
- borderBottomStyle: "solid"
2747
- };
2748
- const footerStyle = {
2749
- borderTopColor: isLightTheme ? "#e2e8f0" : "#374151",
2750
- borderTopWidth: "1px",
2751
- borderTopStyle: "solid"
2752
- };
2753
- const inputStyle = {
2754
- backgroundColor: isLightTheme ? "#ffffff" : "#374151",
2755
- borderColor: isLightTheme ? "#cbd5e1" : "#4b5563",
2756
- color: isLightTheme ? "#0f172a" : "#ffffff"
2757
- };
2758
- const labelStyle = {
2759
- color: isLightTheme ? "#0f172a" : "#d1d5db",
2760
- fontWeight: 500
2761
- };
2762
- const helpTextStyle = {
2763
- color: isLightTheme ? "#64748b" : "#9ca3af"
2764
- };
2765
- const primaryButtonStyle = {
2766
- backgroundColor: "#2563eb",
2767
- color: "#ffffff"
2768
- };
2769
- const secondaryButtonStyle = {
2770
- backgroundColor: isLightTheme ? "#e2e8f0" : "#374151",
2771
- color: isLightTheme ? "#0f172a" : "#ffffff",
2772
- border: "none"
2773
- };
2774
- const [values, setValues] = useState2({});
2775
- const [errors, setErrors] = useState2({});
2776
- const [currentStep, setCurrentStep] = useState2(0);
2777
- const fileInputRefs = useRef4({});
2778
- const sortedInputs = [...inputs].sort((a, b) => (a.config.order || 0) - (b.config.order || 0));
2779
- const currentInput = sortedInputs[currentStep];
2780
- const isFirstStep = currentStep === 0;
2781
- const isLastStep = currentStep === sortedInputs.length - 1;
2782
- const handleTextChange = (id, value) => {
2783
- setValues((prev) => ({ ...prev, [id]: value }));
2784
- if (errors[id]) {
2785
- setErrors((prev) => {
2786
- const newErrors = { ...prev };
2787
- delete newErrors[id];
2788
- return newErrors;
2789
- });
2790
- }
2791
- };
2792
- const handleFileChange = (id, file) => {
2793
- if (!file) {
2794
- setValues((prev) => {
2795
- const newValues = { ...prev };
2796
- delete newValues[id];
2797
- return newValues;
2798
- });
2799
- return;
2800
- }
2801
- const config = inputs.find((input) => input.config.id === id)?.config;
2802
- if (!config)
2803
- return;
2804
- if (config.accept && !file.type.match(config.accept.replace("*", ".*"))) {
2805
- setErrors((prev) => ({
2806
- ...prev,
2807
- [id]: `File must be of type: ${config.accept}`
2808
- }));
2809
- return;
2810
- }
2811
- if (config.maxSize && file.size > config.maxSize) {
2812
- const maxSizeMB = (config.maxSize / 1024 / 1024).toFixed(2);
2813
- setErrors((prev) => ({
2814
- ...prev,
2815
- [id]: `File size must be less than ${maxSizeMB}MB`
2816
- }));
2817
- return;
2818
- }
2819
- const reader = new FileReader;
2820
- reader.onload = (e) => {
2821
- const result = e.target?.result;
2822
- if (typeof result === "string") {
2823
- setValues((prev) => ({ ...prev, [id]: result }));
2824
- setErrors((prev) => {
2825
- const newErrors = { ...prev };
2826
- delete newErrors[id];
2827
- return newErrors;
2828
- });
2829
- }
2830
- };
2831
- reader.onerror = () => {
2832
- setErrors((prev) => ({
2833
- ...prev,
2834
- [id]: "Failed to read file"
2835
- }));
2836
- };
2837
- reader.readAsDataURL(file);
2838
- };
2839
- const validateCurrentStep = () => {
2840
- if (!currentInput)
2841
- return false;
2842
- const config = currentInput.config;
2843
- const value = values[config.id];
2844
- const newErrors = { ...errors };
2845
- delete newErrors[config.id];
2846
- if (config.required && !value) {
2847
- newErrors[config.id] = "This field is required";
2848
- setErrors(newErrors);
2849
- return false;
2850
- }
2851
- if (config.type === "text" && value) {
2852
- if (config.minLength && value.length < config.minLength) {
2853
- newErrors[config.id] = `Minimum length is ${config.minLength} characters`;
2854
- setErrors(newErrors);
2855
- return false;
2856
- }
2857
- if (config.maxLength && value.length > config.maxLength) {
2858
- newErrors[config.id] = `Maximum length is ${config.maxLength} characters`;
2859
- setErrors(newErrors);
2860
- return false;
2861
- }
2862
- }
2863
- setErrors(newErrors);
2864
- return true;
2865
- };
2866
- const handleNext = () => {
2867
- if (!validateCurrentStep()) {
2868
- return;
2869
- }
2870
- if (isLastStep) {
2871
- const allErrors = {};
2872
- sortedInputs.forEach((input) => {
2873
- if (input.config.required && !values[input.config.id]) {
2874
- allErrors[input.config.id] = "This field is required";
2875
- }
2876
- });
2877
- if (Object.keys(allErrors).length > 0) {
2878
- setErrors(allErrors);
2879
- const firstErrorIndex = sortedInputs.findIndex((input) => allErrors[input.config.id]);
2880
- if (firstErrorIndex !== -1) {
2881
- setCurrentStep(firstErrorIndex);
2882
- }
2883
- return;
2884
- }
2885
- onComplete(values);
2886
- } else {
2887
- setCurrentStep((prev) => prev + 1);
2888
- }
2889
- };
2890
- const handlePrevious = () => {
2891
- if (!isFirstStep) {
2892
- setCurrentStep((prev) => prev - 1);
2893
- }
2894
- };
2895
- const handleSkip = () => {
2896
- if (!currentInput.config.required) {
2897
- const defaultValue = currentInput.config.defaultValue || "";
2898
- const valueToSet = defaultValue;
2899
- setValues((prev) => ({ ...prev, [currentInput.config.id]: valueToSet }));
2900
- setErrors((prev) => {
2901
- const newErrors = { ...prev };
2902
- delete newErrors[currentInput.config.id];
2903
- return newErrors;
2904
- });
2905
- const updatedValues = { ...values, [currentInput.config.id]: valueToSet };
2906
- if (isLastStep) {
2907
- const allErrors = {};
2908
- sortedInputs.forEach((input) => {
2909
- if (input.config.required && !updatedValues[input.config.id]) {
2910
- allErrors[input.config.id] = "This field is required";
2911
- }
2912
- });
2913
- if (Object.keys(allErrors).length > 0) {
2914
- setErrors(allErrors);
2915
- const firstErrorIndex = sortedInputs.findIndex((input) => allErrors[input.config.id]);
2916
- if (firstErrorIndex !== -1) {
2917
- setCurrentStep(firstErrorIndex);
2918
- }
2919
- return;
2920
- }
2921
- onComplete(updatedValues);
2922
- } else {
2923
- setCurrentStep((prev) => prev + 1);
2924
- }
2925
- }
2926
- };
2927
- const renderInput = (input) => {
2928
- const { config } = input;
2929
- const defaultValue = config.defaultValue || "";
2930
- const value = values[config.id] !== undefined ? values[config.id] : defaultValue;
2931
- const error = errors[config.id];
2932
- switch (config.type) {
2933
- case "image": {
2934
- const isUrl = value && (value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:"));
2935
- const isDefaultValue = value === defaultValue && defaultValue && (defaultValue.startsWith("http://") || defaultValue.startsWith("https://"));
2936
- return /* @__PURE__ */ React17.createElement("div", {
2937
- className: "space-y-2"
2938
- }, /* @__PURE__ */ React17.createElement("label", {
2939
- className: "block text-sm font-medium",
2940
- style: labelStyle
2941
- }, config.label, config.required && /* @__PURE__ */ React17.createElement("span", {
2942
- className: "text-red-400 ml-1"
2943
- }, "*")), config.helpText && /* @__PURE__ */ React17.createElement("p", {
2944
- className: "text-xs",
2945
- style: helpTextStyle
2946
- }, config.helpText), isDefaultValue && /* @__PURE__ */ React17.createElement("p", {
2947
- className: "text-xs text-blue-400"
2948
- }, "Using default image"), /* @__PURE__ */ React17.createElement("div", {
2949
- className: "flex items-center space-x-4"
2950
- }, /* @__PURE__ */ React17.createElement("input", {
2951
- ref: (el) => {
2952
- fileInputRefs.current[config.id] = el;
2953
- },
2954
- type: "file",
2955
- accept: config.accept || "image/*",
2956
- onChange: (e) => handleFileChange(config.id, e.target.files?.[0] || null),
2957
- className: "hidden"
2958
- }), /* @__PURE__ */ React17.createElement("button", {
2959
- type: "button",
2960
- onClick: () => fileInputRefs.current[config.id]?.click(),
2961
- className: "flex items-center space-x-2 px-4 py-2 rounded border-2 border-dashed transition-colors",
2962
- style: {
2963
- borderColor: value ? "#10b981" : isLightTheme ? "#cbd5e1" : "#4b5563",
2964
- backgroundColor: value ? "rgba(16, 185, 129, 0.1)" : isLightTheme ? "rgba(226, 232, 240, 0.5)" : "rgba(55, 65, 81, 0.5)",
2965
- color: value ? "#10b981" : isLightTheme ? "#475569" : "#d1d5db"
2966
- }
2967
- }, /* @__PURE__ */ React17.createElement(Upload2, {
2968
- className: "w-4 h-4"
2969
- }), /* @__PURE__ */ React17.createElement("span", null, value ? "Change Image" : "Upload Image")), value && /* @__PURE__ */ React17.createElement("div", {
2970
- className: "flex items-center space-x-2"
2971
- }, /* @__PURE__ */ React17.createElement(ImageIcon4, {
2972
- className: "w-5 h-5",
2973
- style: { color: "#10b981" }
2974
- }), /* @__PURE__ */ React17.createElement("span", {
2975
- className: "text-sm",
2976
- style: { color: isLightTheme ? "#64748b" : "#9ca3af" }
2977
- }, isUrl && !isDefaultValue ? "Image URL" : isDefaultValue ? "Default image" : "Image selected"), /* @__PURE__ */ React17.createElement("button", {
2978
- type: "button",
2979
- onClick: () => {
2980
- const resetValue = defaultValue || "";
2981
- setValues((prev) => ({ ...prev, [config.id]: resetValue }));
2982
- setErrors((prev) => {
2983
- const newErrors = { ...prev };
2984
- delete newErrors[config.id];
2985
- return newErrors;
2986
- });
2987
- },
2988
- className: "text-sm",
2989
- style: { color: "#ef4444" }
2990
- }, isDefaultValue ? "Clear" : "Remove"))), value && isUrl && /* @__PURE__ */ React17.createElement("div", {
2991
- className: "mt-2"
2992
- }, /* @__PURE__ */ React17.createElement("img", {
2993
- src: value,
2994
- alt: "Preview",
2995
- className: "max-w-xs max-h-32 object-contain rounded border",
2996
- style: { borderColor: isLightTheme ? "#cbd5e1" : "#4b5563" },
2997
- onError: (e) => {
2998
- setErrors((prev) => ({
2999
- ...prev,
3000
- [config.id]: "Failed to load image"
3001
- }));
3002
- }
3003
- })), error && /* @__PURE__ */ React17.createElement("p", {
3004
- className: "text-sm",
3005
- style: { color: "#ef4444" }
3006
- }, error));
3007
- }
3008
- case "text":
3009
- return /* @__PURE__ */ React17.createElement("div", {
3010
- className: "space-y-2"
3011
- }, /* @__PURE__ */ React17.createElement("label", {
3012
- className: "block text-sm font-medium",
3013
- style: labelStyle
3014
- }, config.label, config.required && /* @__PURE__ */ React17.createElement("span", {
3015
- className: "text-red-400 ml-1"
3016
- }, "*")), config.helpText && /* @__PURE__ */ React17.createElement("p", {
3017
- className: "text-xs",
3018
- style: helpTextStyle
3019
- }, config.helpText), /* @__PURE__ */ React17.createElement("input", {
3020
- type: "text",
3021
- value,
3022
- onChange: (e) => handleTextChange(config.id, e.target.value),
3023
- placeholder: config.placeholder || "Enter text here...",
3024
- maxLength: config.maxLength,
3025
- className: "w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500",
3026
- style: {
3027
- backgroundColor: "#ffffff",
3028
- color: "#0f172a",
3029
- borderColor: error ? "#ef4444" : "#cbd5e1"
3030
- }
3031
- }), config.maxLength && /* @__PURE__ */ React17.createElement("p", {
3032
- className: "text-xs text-right",
3033
- style: helpTextStyle
3034
- }, value.length, " / ", config.maxLength), error && /* @__PURE__ */ React17.createElement("p", {
3035
- className: "text-sm",
3036
- style: { color: "#ef4444" }
3037
- }, error));
3038
- default:
3039
- return null;
3040
- }
3041
- };
3042
- if (!currentInput) {
3043
- return null;
3044
- }
3045
- return /* @__PURE__ */ React17.createElement("div", {
3046
- className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
3047
- }, /* @__PURE__ */ React17.createElement("div", {
3048
- className: "rounded-lg w-full max-w-2xl max-h-[90vh] overflow-hidden flex flex-col",
3049
- style: modalStyle
3050
- }, /* @__PURE__ */ React17.createElement("div", {
3051
- className: "p-6 border-b flex items-center justify-between",
3052
- style: headerStyle
3053
- }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("h2", {
3054
- className: "text-xl font-semibold",
3055
- style: { color: isLightTheme ? "#0f172a" : "#ffffff" }
3056
- }, inputs.some((input) => input.config.required) ? "Template Input Required" : "Template Customization"), /* @__PURE__ */ React17.createElement("p", {
3057
- className: "text-sm mt-1",
3058
- style: { color: isLightTheme ? "#64748b" : "#9ca3af" }
3059
- }, "Step ", currentStep + 1, " of ", sortedInputs.length, !inputs.some((input) => input.config.required) && /* @__PURE__ */ React17.createElement("span", {
3060
- style: { color: "#2563eb", marginLeft: "8px" }
3061
- }, "(All fields optional)"))), /* @__PURE__ */ React17.createElement("button", {
3062
- onClick: onCancel,
3063
- className: "transition-colors",
3064
- style: { color: isLightTheme ? "#64748b" : "#9ca3af" }
3065
- }, /* @__PURE__ */ React17.createElement(X, {
3066
- className: "w-5 h-5"
3067
- }))), /* @__PURE__ */ React17.createElement("div", {
3068
- className: "px-6 pt-4"
3069
- }, /* @__PURE__ */ React17.createElement("div", {
3070
- className: "w-full rounded-full h-2",
3071
- style: { backgroundColor: isLightTheme ? "#e2e8f0" : "#374151" }
3072
- }, /* @__PURE__ */ React17.createElement("div", {
3073
- className: "h-2 rounded-full transition-all duration-300",
3074
- style: {
3075
- backgroundColor: "#2563eb",
3076
- width: `${(currentStep + 1) / sortedInputs.length * 100}%`
3077
- }
3078
- }))), /* @__PURE__ */ React17.createElement("div", {
3079
- className: "flex-1 overflow-y-auto p-6"
3080
- }, /* @__PURE__ */ React17.createElement("div", {
3081
- className: "space-y-4"
3082
- }, renderInput(currentInput))), /* @__PURE__ */ React17.createElement("div", {
3083
- className: "p-6 border-t flex items-center justify-between",
3084
- style: footerStyle
3085
- }, /* @__PURE__ */ React17.createElement("button", {
3086
- onClick: onCancel,
3087
- className: "px-4 py-2 rounded transition-colors",
3088
- style: secondaryButtonStyle
3089
- }, "Cancel"), /* @__PURE__ */ React17.createElement("div", {
3090
- className: "flex items-center space-x-3"
3091
- }, !isFirstStep && /* @__PURE__ */ React17.createElement("button", {
3092
- onClick: handlePrevious,
3093
- className: "px-4 py-2 rounded transition-colors flex items-center space-x-2",
3094
- style: secondaryButtonStyle
3095
- }, /* @__PURE__ */ React17.createElement(ChevronLeft, {
3096
- className: "w-4 h-4"
3097
- }), /* @__PURE__ */ React17.createElement("span", null, "Previous")), !currentInput.config.required && /* @__PURE__ */ React17.createElement("button", {
3098
- onClick: handleSkip,
3099
- className: "px-4 py-2 rounded transition-colors",
3100
- style: { ...secondaryButtonStyle, opacity: 0.9 }
3101
- }, "Skip"), /* @__PURE__ */ React17.createElement("button", {
3102
- onClick: handleNext,
3103
- className: "px-4 py-2 rounded transition-colors flex items-center space-x-2",
3104
- style: primaryButtonStyle
3105
- }, /* @__PURE__ */ React17.createElement("span", null, isLastStep ? "Complete" : "Next"), !isLastStep && /* @__PURE__ */ React17.createElement(ChevronRight, {
3106
- className: "w-4 h-4"
3107
- }))))));
3108
- };
3109
- var TemplateInputModal_default = TemplateInputModal;
3110
-
3111
2720
  // src/store/simpleStore.ts
3112
2721
  class SimpleCanvasStore {
3113
2722
  _design;
3114
2723
  _activePageId;
3115
2724
  _activePanelId;
2725
+ _selectedId;
2726
+ _selectedIds;
2727
+ _tool;
2728
+ _zoom;
2729
+ _selectedShape;
3116
2730
  _listeners = {};
3117
2731
  constructor(initialDesign) {
3118
2732
  this._design = {
@@ -3127,6 +2741,11 @@ class SimpleCanvasStore {
3127
2741
  };
3128
2742
  this._activePageId = initialDesign?.pages?.[0]?.id || null;
3129
2743
  this._activePanelId = null;
2744
+ this._selectedId = null;
2745
+ this._selectedIds = [];
2746
+ this._tool = "select";
2747
+ this._zoom = 1;
2748
+ this._selectedShape = "rect";
3130
2749
  }
3131
2750
  on(event, callback) {
3132
2751
  this._listeners[event] = callback;
@@ -3166,12 +2785,27 @@ class SimpleCanvasStore {
3166
2785
  get activePanelId() {
3167
2786
  return this._activePanelId;
3168
2787
  }
2788
+ get selectedId() {
2789
+ return this._selectedId;
2790
+ }
2791
+ get selectedIds() {
2792
+ return this._selectedIds;
2793
+ }
2794
+ get tool() {
2795
+ return this._tool;
2796
+ }
2797
+ get zoom() {
2798
+ return this._zoom;
2799
+ }
2800
+ get selectedShape() {
2801
+ return this._selectedShape;
2802
+ }
3169
2803
  setDesign(design) {
3170
2804
  this._design = design;
3171
2805
  if (design.pages.find((p) => p.id === this._activePageId)) {} else if (design.pages.length > 0) {
3172
2806
  this._activePageId = design.pages[0].id;
3173
2807
  }
3174
- this.emit("designChanged", design);
2808
+ this.emit("designChanged", this._design);
3175
2809
  this.emit("activePageChanged", this._activePageId);
3176
2810
  }
3177
2811
  updateDesign(updates) {
@@ -3213,14 +2847,6 @@ class SimpleCanvasStore {
3213
2847
  this._design.pages = remainingPages;
3214
2848
  this.emit("designChanged", this._design);
3215
2849
  }
3216
- setActivePage(pageId) {
3217
- const page = this._design.pages.find((p) => p.id === pageId);
3218
- if (page) {
3219
- this._activePageId = pageId;
3220
- this.emit("activePageChanged", pageId);
3221
- this.emit("designChanged", this._design);
3222
- }
3223
- }
3224
2850
  addElement(element) {
3225
2851
  const page = this.activePage;
3226
2852
  if (!page) {
@@ -3242,34 +2868,32 @@ class SimpleCanvasStore {
3242
2868
  ...element
3243
2869
  };
3244
2870
  page.elements.push(newElement);
3245
- console.log(`addElement: Added element ${newElement.id} to page. Total elements: ${page.elements.length}`);
3246
2871
  this.emit("designChanged", this._design);
3247
- console.log("addElement: Emitted designChanged event");
3248
- }
3249
- updateElement(elementId, updates) {
3250
- for (const page of this._design.pages) {
3251
- const elementIndex = page.elements.findIndex((e) => e.id === elementId);
3252
- if (elementIndex !== -1) {
3253
- page.elements[elementIndex] = { ...page.elements[elementIndex], ...updates };
3254
- this.emit("designChanged", this._design);
3255
- return;
3256
- }
3257
- }
3258
- }
3259
- deleteElement(elementId) {
3260
- for (const page of this._design.pages) {
3261
- const elementIndex = page.elements.findIndex((e) => e.id === elementId);
3262
- if (elementIndex !== -1) {
3263
- page.elements.splice(elementIndex, 1);
3264
- this.emit("designChanged", this._design);
3265
- return;
3266
- }
3267
- }
3268
2872
  }
3269
2873
  openSidePanel(panelId) {
3270
2874
  this._activePanelId = panelId;
3271
2875
  this.emit("activePanelChanged", panelId);
3272
2876
  }
2877
+ setSelectedId(selectedId) {
2878
+ this._selectedId = selectedId;
2879
+ this.emit("selectedIdChanged", selectedId);
2880
+ }
2881
+ setSelectedIds(selectedIds) {
2882
+ this._selectedIds = selectedIds;
2883
+ this.emit("selectedIdsChanged", selectedIds);
2884
+ }
2885
+ setTool(tool) {
2886
+ this._tool = tool;
2887
+ this.emit("toolChanged", tool);
2888
+ }
2889
+ setZoom(zoom) {
2890
+ this._zoom = zoom;
2891
+ this.emit("zoomChanged", zoom);
2892
+ }
2893
+ setSelectedShape(shape) {
2894
+ this._selectedShape = shape;
2895
+ this.emit("selectedShapeChanged", shape);
2896
+ }
3273
2897
  async toBlob(type = "png") {
3274
2898
  return new Promise((resolve, reject) => {
3275
2899
  try {
@@ -3299,6 +2923,34 @@ class SimpleCanvasStore {
3299
2923
  }
3300
2924
  });
3301
2925
  }
2926
+ setActivePage(pageId) {
2927
+ const page = this._design.pages.find((p) => p.id === pageId);
2928
+ if (page) {
2929
+ this._activePageId = pageId;
2930
+ this.emit("activePageChanged", pageId);
2931
+ this.emit("designChanged", this._design);
2932
+ }
2933
+ }
2934
+ updateElement(elementId, updates) {
2935
+ for (const page of this._design.pages) {
2936
+ const elementIndex = page.elements.findIndex((e) => e.id === elementId);
2937
+ if (elementIndex !== -1) {
2938
+ page.elements[elementIndex] = { ...page.elements[elementIndex], ...updates };
2939
+ this.emit("designChanged", this._design);
2940
+ return;
2941
+ }
2942
+ }
2943
+ }
2944
+ deleteElement(elementId) {
2945
+ for (const page of this._design.pages) {
2946
+ const elementIndex = page.elements.findIndex((e) => e.id === elementId);
2947
+ if (elementIndex !== -1) {
2948
+ page.elements.splice(elementIndex, 1);
2949
+ this.emit("designChanged", this._design);
2950
+ return;
2951
+ }
2952
+ }
2953
+ }
3302
2954
  async loadJSON(jsonData) {
3303
2955
  return new Promise((resolve, reject) => {
3304
2956
  try {
@@ -3328,197 +2980,89 @@ var CanvasEditor = ({
3328
2980
  config,
3329
2981
  store: externalStore
3330
2982
  }) => {
3331
- console.log("=== CanvasEditor initializing ===", { hasExternalStore: !!externalStore });
3332
2983
  const store = externalStore || createSimpleStore({
3333
2984
  name,
3334
2985
  width: 800,
3335
2986
  height: 600
3336
2987
  });
3337
- const [design, setDesign] = useState3(() => {
3338
- if (externalStore) {
3339
- return externalStore.design;
3340
- }
3341
- return {
3342
- id: Date.now().toString(),
3343
- name: "Untitled Design",
3344
- width: 800,
3345
- height: 600,
3346
- pages: [
3347
- {
3348
- id: "1",
3349
- name: "Page 1",
3350
- elements: [],
3351
- background: "#ffffff"
3352
- }
3353
- ],
3354
- fonts: FONT_FAMILIES,
3355
- colors: DEFAULT_COLORS
3356
- };
3357
- });
3358
- const [currentPageId, setCurrentPageId] = useState3(() => {
3359
- if (externalStore?.design.pages && externalStore.design.pages.length > 0) {
3360
- return externalStore.design.pages[0].id;
3361
- }
3362
- if (externalStore?.activePageId) {
3363
- return externalStore.activePageId;
3364
- }
3365
- return "1";
3366
- });
3367
- const [selectedId, setSelectedId] = useState3(null);
3368
- const [selectedIds, setSelectedIds] = useState3([]);
3369
- const [tool, setTool] = useState3("select");
3370
- const [activePanelId, setActivePanelId] = useState3("elements");
2988
+ const stageRef = useRef4(null);
2989
+ const fileInputRef = useRef4(null);
2990
+ const jsonInputRef = useRef4(null);
2991
+ const containerRef = useRef4(null);
2992
+ const currentPage = store.design.pages.find((p) => p.id === store.activePageId) || store.design.pages[0] || null;
2993
+ const selectedElement = currentPage?.elements.find((el) => el.id === store.selectedId) || null;
3371
2994
  useEffect4(() => {
3372
2995
  if (externalStore) {
3373
- const handleDesignChange = (newDesign) => {
3374
- console.log("CanvasEditor received designChanged:", newDesign.pages[0]?.elements.length, "elements on page 1");
3375
- setDesign(newDesign);
3376
- };
3377
- const handleActivePageChange = (pageId) => {
3378
- setCurrentPageId(pageId);
3379
- };
3380
- const handleActivePanelChange = (panelId) => {
3381
- setActivePanelId(panelId || "elements");
3382
- };
2996
+ const handleDesignChange = (newDesign) => {};
2997
+ const handleActivePageChange = (pageId) => {};
2998
+ const handleActivePanelChange = (panelId) => {};
2999
+ const handleSelectedIdChange = (selectedId) => {};
3000
+ const handleSelectedIdsChange = (selectedIds) => {};
3001
+ const handleToolChange = (tool) => {};
3002
+ const handleZoomChange = (zoom) => {};
3003
+ const handleSelectedShapeChange = (shape) => {};
3383
3004
  externalStore.on("designChanged", handleDesignChange);
3384
3005
  externalStore.on("activePageChanged", handleActivePageChange);
3385
3006
  externalStore.on("activePanelChanged", handleActivePanelChange);
3007
+ externalStore.on("selectedIdChanged", handleSelectedIdChange);
3008
+ externalStore.on("selectedIdsChanged", handleSelectedIdsChange);
3009
+ externalStore.on("toolChanged", handleToolChange);
3010
+ externalStore.on("zoomChanged", handleZoomChange);
3011
+ externalStore.on("selectedShapeChanged", handleSelectedShapeChange);
3386
3012
  return () => {
3387
3013
  externalStore.off("designChanged");
3388
3014
  externalStore.off("activePageChanged");
3389
3015
  externalStore.off("activePanelChanged");
3016
+ externalStore.off("selectedIdChanged");
3017
+ externalStore.off("selectedIdsChanged");
3018
+ externalStore.off("toolChanged");
3019
+ externalStore.off("zoomChanged");
3020
+ externalStore.off("selectedShapeChanged");
3390
3021
  };
3391
3022
  }
3392
3023
  }, [externalStore]);
3393
- const [showUnsplash, setShowUnsplash] = useState3(false);
3394
- const [unsplashQuery, setUnsplashQuery] = useState3("");
3395
- const [unsplashResults, setUnsplashResults] = useState3([]);
3396
- const [unsplashMode, setUnsplashMode] = useState3("element");
3397
- const [zoom, setZoom] = useState3(1);
3398
- const [selectedShape, setSelectedShape] = useState3("rect");
3399
- const [history, setHistory] = useState3([]);
3400
- const [historyIndex, setHistoryIndex] = useState3(-1);
3401
- const [showInputModal, setShowInputModal] = useState3(false);
3402
- const [pendingInputs, setPendingInputs] = useState3([]);
3403
- const stageRef = useRef5(null);
3404
- const fileInputRef = useRef5(null);
3405
- const jsonInputRef = useRef5(null);
3406
- const containerRef = useRef5(null);
3407
- const currentPage = design.pages.find((p) => p.id === currentPageId) || design.pages[0] || null;
3408
- const selectedElement = currentPage?.elements.find((el) => el.id === selectedId) || null;
3409
- const saveToHistory = useCallback4((newDesign) => {
3410
- const newHistory = history.slice(0, historyIndex + 1);
3411
- newHistory.push(JSON.parse(JSON.stringify(newDesign)));
3412
- setHistory(newHistory);
3413
- setHistoryIndex(newHistory.length - 1);
3414
- }, [history, historyIndex]);
3415
- const undo = useCallback4(() => {
3416
- if (historyIndex > 0) {
3417
- setHistoryIndex(historyIndex - 1);
3418
- setDesign(JSON.parse(JSON.stringify(history[historyIndex - 1])));
3419
- }
3420
- }, [history, historyIndex]);
3421
- const redo = useCallback4(() => {
3422
- if (historyIndex < history.length - 1) {
3423
- setHistoryIndex(historyIndex + 1);
3424
- setDesign(JSON.parse(JSON.stringify(history[historyIndex + 1])));
3024
+ const handleStageClick = useCallback4((e) => {
3025
+ const clickedOnEmpty = e.target === e.target.getStage();
3026
+ if (clickedOnEmpty) {
3027
+ store.setSelectedId(null);
3028
+ store.setSelectedIds([]);
3425
3029
  }
3426
- }, [history, historyIndex]);
3030
+ }, [store]);
3427
3031
  const addText = useCallback4(() => {
3428
- const newElement = {
3429
- id: Date.now().toString(),
3032
+ if (!store.activePage)
3033
+ return;
3034
+ store.activePage.addElement({
3430
3035
  type: "text",
3431
- name: "Text",
3432
- x: design.width / 2 - 50,
3433
- y: design.height / 2 - 20,
3434
- rotation: 0,
3435
- visible: true,
3436
- locked: false,
3437
- opacity: 1,
3438
- text: "Click to edit text",
3439
- fontSize: 24,
3440
- fontFamily: "Arial",
3441
- fill: "#000000",
3442
- align: "left",
3443
- lineHeight: 1.2,
3444
- letterSpacing: 0,
3445
- textCase: "none",
3446
- strikethrough: false
3447
- };
3448
- const newDesign = {
3449
- ...design,
3450
- pages: design.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
3451
- };
3452
- setDesign(newDesign);
3453
- saveToHistory(newDesign);
3454
- if (externalStore) {
3455
- externalStore.setDesign(newDesign);
3456
- }
3457
- setSelectedId(newElement.id);
3458
- setTool("select");
3459
- }, [currentPageId, saveToHistory, design.width, design.height, externalStore]);
3036
+ text: "Edit this text",
3037
+ x: store.design.width / 2 - 50,
3038
+ y: store.design.height / 2 - 15,
3039
+ width: 100,
3040
+ height: 30
3041
+ });
3042
+ }, [store]);
3460
3043
  const addShape = useCallback4((shapeType) => {
3461
- const newElement = {
3462
- id: Date.now().toString(),
3044
+ if (!store.activePage)
3045
+ return;
3046
+ store.activePage.addElement({
3463
3047
  type: "shape",
3464
- name: shapeType.charAt(0).toUpperCase() + shapeType.slice(1),
3465
- x: design.width / 2 - 50,
3466
- y: design.height / 2 - 50,
3467
- width: 100,
3468
- height: 100,
3469
- rotation: 0,
3470
- visible: true,
3471
- locked: false,
3472
- opacity: 1,
3473
- fill: "#4299e1",
3474
- stroke: "#000000",
3475
- strokeWidth: 0,
3476
3048
  shapeType,
3477
- sides: shapeType === "polygon" ? 6 : undefined,
3478
- innerRadius: shapeType === "star" ? 40 : undefined,
3479
- outerRadius: shapeType === "star" ? 70 : undefined
3480
- };
3481
- setDesign((prev) => {
3482
- const newDesign = {
3483
- ...prev,
3484
- pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
3485
- };
3486
- saveToHistory(newDesign);
3487
- return newDesign;
3049
+ x: store.design.width / 2 - 50,
3050
+ y: store.design.height / 2 - 50,
3051
+ width: 100,
3052
+ height: 100
3488
3053
  });
3489
- setSelectedId(newElement.id);
3490
- }, [currentPageId, saveToHistory, design.width, design.height]);
3491
- const handleStageClick = useCallback4((e) => {
3492
- const clickedOnEmpty = e.target === e.target.getStage();
3493
- if (clickedOnEmpty) {
3494
- setSelectedId(null);
3495
- setSelectedIds([]);
3496
- }
3497
- }, []);
3054
+ }, [store]);
3498
3055
  const updateElement = useCallback4((id, attrs) => {
3499
- setDesign((prev) => ({
3500
- ...prev,
3501
- pages: prev.pages.map((page) => ({
3502
- ...page,
3503
- elements: page.elements.map((el) => el.id === id ? { ...el, ...attrs } : el)
3504
- }))
3505
- }));
3506
- }, []);
3056
+ store.updateElement(id, attrs);
3057
+ }, [store]);
3507
3058
  const deleteSelected = useCallback4(() => {
3508
- if (selectedId || selectedIds.length > 0) {
3509
- const idsToDelete = selectedIds.length > 0 ? selectedIds : [selectedId];
3510
- setDesign((prev) => ({
3511
- ...prev,
3512
- pages: prev.pages.map((page) => ({
3513
- ...page,
3514
- elements: page.elements.filter((el) => !idsToDelete.includes(el.id))
3515
- }))
3516
- }));
3517
- setSelectedId(null);
3518
- setSelectedIds([]);
3519
- saveToHistory(design);
3059
+ if (store.selectedId || store.selectedIds.length > 0) {
3060
+ const idsToDelete = store.selectedIds.length > 0 ? store.selectedIds : [store.selectedId];
3061
+ idsToDelete.forEach((id) => store.deleteElement(id));
3062
+ store.setSelectedId(null);
3063
+ store.setSelectedIds([]);
3520
3064
  }
3521
- }, [selectedId, selectedIds, saveToHistory, design]);
3065
+ }, [store]);
3522
3066
  const duplicateSelected = useCallback4(() => {
3523
3067
  if (selectedElement) {
3524
3068
  const newElement = {
@@ -3528,634 +3072,254 @@ var CanvasEditor = ({
3528
3072
  x: selectedElement.x + 20,
3529
3073
  y: selectedElement.y + 20
3530
3074
  };
3531
- setDesign((prev) => {
3532
- const newDesign = {
3533
- ...prev,
3534
- pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
3535
- };
3536
- saveToHistory(newDesign);
3537
- return newDesign;
3075
+ store.activePage?.addElement(newElement);
3076
+ store.setSelectedId(newElement.id);
3077
+ }
3078
+ }, [selectedElement, store]);
3079
+ const moveElementUp = useCallback4((id) => {}, [store]);
3080
+ const moveElementDown = useCallback4((id) => {}, [store]);
3081
+ const addPage = useCallback4(() => {
3082
+ store.addPage();
3083
+ }, [store]);
3084
+ const deletePage = useCallback4((pageId) => {
3085
+ store.deletePages([pageId]);
3086
+ }, [store]);
3087
+ const panelConfigs = useMemo(() => {
3088
+ const builtInConfigs = {
3089
+ elements: { id: "elements", title: "Elements", component: ElementPanel_default, props: { onAddShape: addShape, store } },
3090
+ text: { id: "text", title: "Text", component: TextPanel_default, props: { selectedElement, updateElement, onAddText: addText, store } },
3091
+ image: { id: "image", title: "Image", component: ImagePanel_default, props: { selectedElement, updateElement, store } },
3092
+ background: { id: "background", title: "Background", component: BackgroundPanel_default, props: { store } },
3093
+ design: { id: "design", title: "Design", component: DesignPanel_default, props: { store } },
3094
+ variables: { id: "variables", title: "Variables", component: VariablesPanel_default, props: { store } },
3095
+ export: { id: "export", title: "Export", component: ExportPanel_default, props: { store } }
3096
+ };
3097
+ const mergedConfigs = { ...builtInConfigs };
3098
+ if (config?.panels) {
3099
+ config.panels.forEach((panelConfig) => {
3100
+ if (typeof panelConfig === "string") {} else {
3101
+ const customPanelConfig = {
3102
+ id: panelConfig.id,
3103
+ title: panelConfig.title,
3104
+ component: panelConfig.component,
3105
+ props: panelConfig.props || {},
3106
+ ...panelConfig.icon && typeof panelConfig.icon.type === "string" ? {
3107
+ icon: panelConfig.icon.type
3108
+ } : {}
3109
+ };
3110
+ mergedConfigs[panelConfig.id] = customPanelConfig;
3111
+ }
3538
3112
  });
3539
- setSelectedId(newElement.id);
3540
3113
  }
3541
- }, [selectedElement, currentPageId, saveToHistory]);
3542
- const moveElementUp = useCallback4((id) => {
3543
- setDesign((prev) => ({
3544
- ...prev,
3545
- pages: prev.pages.map((page) => {
3546
- if (page.id === currentPageId) {
3547
- const index = page.elements.findIndex((el) => el.id === id);
3548
- if (index < page.elements.length - 1) {
3549
- const newElements = [...page.elements];
3550
- [newElements[index], newElements[index + 1]] = [
3551
- newElements[index + 1],
3552
- newElements[index]
3553
- ];
3554
- return { ...page, elements: newElements };
3114
+ const orderedConfigs = [];
3115
+ if (config?.panels) {
3116
+ config.panels.forEach((panelConfig) => {
3117
+ if (typeof panelConfig === "string") {
3118
+ if (mergedConfigs[panelConfig]) {
3119
+ orderedConfigs.push(mergedConfigs[panelConfig]);
3555
3120
  }
3121
+ } else {
3122
+ orderedConfigs.push(mergedConfigs[panelConfig.id]);
3556
3123
  }
3557
- return page;
3558
- })
3559
- }));
3560
- }, [currentPageId]);
3561
- const moveElementDown = useCallback4((id) => {
3562
- setDesign((prev) => ({
3563
- ...prev,
3564
- pages: prev.pages.map((page) => {
3565
- if (page.id === currentPageId) {
3566
- const index = page.elements.findIndex((el) => el.id === id);
3567
- if (index > 0) {
3568
- const newElements = [...page.elements];
3569
- [newElements[index], newElements[index - 1]] = [
3570
- newElements[index - 1],
3571
- newElements[index]
3572
- ];
3573
- return { ...page, elements: newElements };
3574
- }
3124
+ });
3125
+ }
3126
+ return orderedConfigs.length > 0 ? orderedConfigs : Object.values(builtInConfigs);
3127
+ }, [addShape, addText, config, selectedElement, updateElement, store]);
3128
+ const DynamicPanelRenderer = useMemo(() => {
3129
+ const activePanel = panelConfigs.find((panel) => panel.id === store.activePanelId);
3130
+ if (!activePanel)
3131
+ return null;
3132
+ const PanelComponent = activePanel.component;
3133
+ return /* @__PURE__ */ React17.createElement(PanelComponent, {
3134
+ key: activePanel.id,
3135
+ ...activePanel.props
3136
+ });
3137
+ }, [panelConfigs, store.activePanelId]);
3138
+ const handleExportPNG = useCallback4(() => {
3139
+ exportToPNG(stageRef.current, store.design);
3140
+ }, [store.design]);
3141
+ const handleExportJPG = useCallback4(() => {
3142
+ exportToJPG(stageRef.current, store.design);
3143
+ }, [store.design]);
3144
+ const handleExportJSON = useCallback4(() => {
3145
+ exportToJSON(store.design);
3146
+ }, [store.design]);
3147
+ const handleImportJSON = useCallback4((e) => {
3148
+ const file = e.target.files?.[0];
3149
+ if (file) {
3150
+ const reader = new FileReader;
3151
+ reader.onload = (event) => {
3152
+ try {
3153
+ const jsonData = JSON.parse(event.target?.result);
3154
+ importFromJSON(jsonData, (loadedDesign) => {
3155
+ store.setDesign(loadedDesign);
3156
+ }, (errorMessage) => {
3157
+ console.error("Import error:", errorMessage);
3158
+ }, () => {
3159
+ console.log("Import requires user inputs - not implemented");
3160
+ });
3161
+ } catch (error) {
3162
+ console.error("Invalid JSON file:", error);
3575
3163
  }
3576
- return page;
3577
- })
3578
- }));
3579
- }, [currentPageId]);
3580
- const addPage = useCallback4(() => {
3581
- const newPage = {
3582
- id: Date.now().toString(),
3583
- name: `Page ${design.pages.length + 1}`,
3584
- elements: [],
3585
- background: "#ffffff",
3586
- backgroundImageObject: undefined
3587
- };
3588
- setDesign((prev) => ({
3589
- ...prev,
3590
- pages: [...prev.pages, newPage]
3591
- }));
3592
- setCurrentPageId(newPage.id);
3593
- }, [design.pages.length]);
3594
- const deletePage = useCallback4((pageId) => {
3595
- if (design.pages.length > 1) {
3596
- setDesign((prev) => ({
3597
- ...prev,
3598
- pages: prev.pages.filter((p) => p.id !== pageId)
3599
- }));
3600
- if (currentPageId === pageId) {
3601
- setCurrentPageId(design.pages[0].id);
3602
- }
3164
+ };
3165
+ reader.readAsText(file);
3603
3166
  }
3604
- }, [design.pages, currentPageId]);
3167
+ }, [store]);
3605
3168
  const handleImageUpload = useCallback4((e) => {
3606
3169
  const file = e.target.files?.[0];
3607
3170
  if (file) {
3608
3171
  const reader = new FileReader;
3609
3172
  reader.onload = (event) => {
3610
3173
  const img = new window.Image;
3611
- img.src = event.target?.result;
3612
3174
  img.onload = () => {
3613
- const newElement = {
3614
- id: Date.now().toString(),
3615
- type: "image",
3616
- name: file.name,
3617
- x: 100,
3618
- y: 100,
3619
- width: img.naturalWidth,
3620
- height: img.naturalHeight,
3621
- rotation: 0,
3622
- visible: true,
3623
- locked: false,
3624
- opacity: 1,
3625
- src: event.target?.result,
3626
- cropX: 0,
3627
- cropY: 0,
3628
- cropWidth: img.naturalWidth,
3629
- cropHeight: img.naturalHeight,
3630
- mask: undefined
3631
- };
3632
- setDesign((prev) => ({
3633
- ...prev,
3634
- pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
3635
- }));
3636
- saveToHistory(design);
3175
+ if (store.activePage) {
3176
+ store.activePage.addElement({
3177
+ type: "image",
3178
+ src: event.target?.result,
3179
+ x: store.design.width / 2 - img.width / 2,
3180
+ y: store.design.height / 2 - img.height / 2,
3181
+ width: img.width,
3182
+ height: img.height
3183
+ });
3184
+ }
3637
3185
  };
3186
+ img.src = event.target?.result;
3638
3187
  };
3639
3188
  reader.readAsDataURL(file);
3640
3189
  }
3641
- if (fileInputRef.current) {
3642
- fileInputRef.current.value = "";
3643
- }
3644
- }, [currentPageId, saveToHistory]);
3645
- const searchUnsplash = useCallback4(async () => {
3646
- if (!unsplashQuery)
3647
- return;
3648
- if (UNSPLASH_ACCESS_KEY === "YOUR_UNSPLASH_ACCESS_KEY_HERE" || !UNSPLASH_ACCESS_KEY) {
3649
- console.warn("Unsplash API key is not configured. Please set UNSPLASH_ACCESS_KEY in src/config.ts");
3650
- const mockResults = Array(9).fill(null).map((_, i) => ({
3651
- id: `unsplash-mock-${i}`,
3652
- urls: {
3653
- regular: `https://source.unsplash.com/400x300/?${unsplashQuery}&sig=${i}`,
3654
- thumb: `https://source.unsplash.com/200x150/?${unsplashQuery}&sig=${i}`
3655
- },
3656
- user: { name: "Mock User" }
3657
- }));
3658
- setUnsplashResults(mockResults);
3659
- return;
3660
- }
3661
- try {
3662
- const response = await fetch(`https://api.unsplash.com/search/photos?query=${encodeURIComponent(unsplashQuery)}&per_page=9`, {
3663
- headers: {
3664
- Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`
3665
- }
3666
- });
3667
- if (!response.ok) {
3668
- console.error("Failed to fetch from Unsplash:", response.statusText);
3669
- setUnsplashResults([]);
3670
- return;
3671
- }
3672
- const data = await response.json();
3673
- setUnsplashResults(data.results.map((img) => ({
3674
- id: img.id,
3675
- urls: { regular: img.urls.regular, thumb: img.urls.thumb },
3676
- user: { name: img.user.name }
3677
- })));
3678
- } catch (error) {
3679
- console.error("Error searching Unsplash:", error);
3680
- setUnsplashResults([]);
3681
- }
3682
- }, [unsplashQuery]);
3683
- const addUnsplashImage = useCallback4((imageUrl) => {
3684
- if (unsplashMode === "element") {
3685
- const img = new window.Image;
3686
- img.crossOrigin = "anonymous";
3687
- img.src = imageUrl;
3688
- img.onload = () => {
3689
- const newElement = {
3690
- id: Date.now().toString(),
3691
- type: "image",
3692
- name: "Unsplash Image",
3693
- x: 100,
3694
- y: 100,
3695
- width: img.naturalWidth,
3696
- height: img.naturalHeight,
3697
- rotation: 0,
3698
- visible: true,
3699
- locked: false,
3700
- opacity: 1,
3701
- src: imageUrl,
3702
- cropX: 0,
3703
- cropY: 0,
3704
- cropWidth: img.naturalWidth,
3705
- cropHeight: img.naturalHeight,
3706
- mask: undefined
3707
- };
3708
- setDesign((prev) => ({
3709
- ...prev,
3710
- pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
3711
- }));
3712
- saveToHistory(design);
3713
- };
3714
- } else if (unsplashMode === "background") {
3715
- const bgImg = new window.Image;
3716
- bgImg.crossOrigin = "anonymous";
3717
- bgImg.src = imageUrl;
3718
- bgImg.onload = () => {
3719
- setDesign((prev) => ({
3720
- ...prev,
3721
- pages: prev.pages.map((p) => p.id === currentPageId ? {
3722
- ...p,
3723
- background: `url(${imageUrl})`,
3724
- backgroundImageObject: bgImg
3725
- } : p)
3726
- }));
3727
- saveToHistory(design);
3728
- };
3729
- }
3730
- setShowUnsplash(false);
3731
- setUnsplashQuery("");
3732
- setUnsplashResults([]);
3733
- setUnsplashMode("element");
3734
- }, [currentPageId, saveToHistory, unsplashMode]);
3735
- const handleImportJSON = (event) => {
3736
- importFromJSON(event, (newDesign) => {
3737
- if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
3738
- setDesign(newDesign);
3739
- setSelectedId(null);
3740
- setSelectedIds([]);
3741
- const firstPageId = newDesign.pages[0]?.id;
3742
- setCurrentPageId(firstPageId || "1");
3743
- saveToHistory(newDesign);
3744
- } else {
3745
- alert("Invalid design structure in JSON file. Could not load.");
3746
- }
3747
- }, (errorMessage) => {
3748
- alert(`Error importing JSON: ${errorMessage}`);
3749
- }, (inputs, onComplete) => {
3750
- setPendingInputs(inputs);
3751
- setShowInputModal(true);
3752
- window.__pendingImportComplete = onComplete;
3753
- });
3754
- if (jsonInputRef.current) {
3755
- jsonInputRef.current.value = "";
3756
- }
3757
- };
3758
- const handleInputModalComplete = (values) => {
3759
- setShowInputModal(false);
3760
- const onComplete = window.__pendingImportComplete;
3761
- if (onComplete) {
3762
- onComplete(values);
3763
- delete window.__pendingImportComplete;
3764
- }
3765
- setPendingInputs([]);
3766
- };
3767
- const handleInputModalCancel = () => {
3768
- setShowInputModal(false);
3769
- setPendingInputs([]);
3770
- delete window.__pendingImportComplete;
3771
- };
3772
- const panelConfigs = useMemo(() => {
3773
- const builtInConfigs = {
3774
- elements: {
3775
- id: "elements",
3776
- title: "Elements",
3777
- component: ElementPanel_default,
3778
- props: { onAddShape: addShape, store }
3779
- },
3780
- text: {
3781
- id: "text",
3782
- title: "Text",
3783
- component: TextPanel_default,
3784
- props: {
3785
- selectedElement,
3786
- updateElement,
3787
- setTool,
3788
- onAddText: addText,
3789
- store
3790
- }
3791
- },
3792
- image: {
3793
- id: "image",
3794
- title: "Images",
3795
- component: ImagePanel_default,
3796
- props: {
3797
- selectedElement,
3798
- updateElement,
3799
- onUploadClick: () => fileInputRef.current?.click(),
3800
- onUnsplashClick: () => {
3801
- setShowUnsplash(true);
3802
- setUnsplashMode("element");
3803
- },
3804
- canvasWidth: design.width,
3805
- canvasHeight: design.height,
3806
- store
3807
- }
3808
- },
3809
- design: {
3810
- id: "design",
3811
- title: "Design",
3812
- component: DesignPanel_default,
3813
- props: {
3814
- design,
3815
- currentPage,
3816
- selectedElement,
3817
- setDesign,
3818
- updateElement,
3819
- onSetUnsplashBackground: () => {
3820
- setShowUnsplash(true);
3821
- setUnsplashMode("background");
3822
- },
3823
- config,
3824
- store
3825
- }
3826
- },
3827
- background: {
3828
- id: "background",
3829
- title: "Background",
3830
- component: BackgroundPanel_default,
3831
- props: {
3832
- design,
3833
- currentPage,
3834
- setDesign,
3835
- onSetUnsplashBackground: () => {
3836
- setShowUnsplash(true);
3837
- setUnsplashMode("background");
3838
- },
3839
- store
3840
- }
3841
- },
3842
- ...config?.variables ? {
3843
- variables: {
3844
- id: "variables",
3845
- title: "Variables",
3846
- component: VariablesPanel_default,
3847
- props: {
3848
- config,
3849
- design,
3850
- setDesign,
3851
- store
3852
- }
3853
- }
3854
- } : {},
3855
- ...config?.export ? {
3856
- export: {
3857
- id: "export",
3858
- title: "Export",
3859
- component: ExportPanel_default,
3860
- props: {
3861
- onExportToPNG: config.export?.png ? () => {
3862
- if (stageRef.current)
3863
- exportToPNG(stageRef.current, design);
3864
- } : undefined,
3865
- onExportToJPG: config.export?.jpg ? () => {
3866
- if (stageRef.current)
3867
- exportToJPG(stageRef.current, design);
3868
- } : undefined,
3869
- onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
3870
- onImportJSON: () => jsonInputRef.current?.click(),
3871
- store
3872
- }
3873
- }
3874
- } : {}
3875
- };
3876
- if (!config?.panels || config.panels.length === 0) {
3877
- return [
3878
- "text",
3879
- "elements",
3880
- "image",
3881
- "design",
3882
- "background",
3883
- ...config?.variables ? ["variables"] : [],
3884
- ...config?.export ? ["export"] : []
3885
- ].filter((id) => builtInConfigs[id]).map((id) => builtInConfigs[id]);
3886
- }
3887
- const ordered = [];
3888
- for (const panel of config.panels) {
3889
- if (typeof panel === "string") {
3890
- const config2 = builtInConfigs[panel];
3891
- if (config2) {
3892
- ordered.push(config2);
3893
- }
3894
- } else {
3895
- ordered.push({
3896
- id: panel.id,
3897
- title: panel.title,
3898
- component: panel.component,
3899
- props: { ...panel.props, store }
3900
- });
3901
- }
3902
- }
3903
- return ordered;
3904
- }, [
3905
- addShape,
3906
- addText,
3907
- config,
3908
- currentPage,
3909
- design,
3910
- selectedElement,
3911
- setTool,
3912
- updateElement,
3913
- store
3914
- ]);
3915
- const DynamicPanelRenderer = () => {
3916
- const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
3917
- if (!activePanelConfig) {
3918
- return /* @__PURE__ */ React18.createElement("div", {
3919
- className: "text-white"
3920
- }, "Panel not found");
3921
- }
3922
- const PanelComponent = activePanelConfig.component;
3923
- return /* @__PURE__ */ React18.createElement(PanelComponent, {
3924
- ...activePanelConfig.props
3925
- });
3926
- };
3927
- useEffect4(() => {
3928
- const handleKeyDown = (e) => {
3929
- if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
3930
- return;
3931
- if (e.metaKey || e.ctrlKey) {
3932
- switch (e.key) {
3933
- case "z":
3934
- if (e.shiftKey) {
3935
- redo();
3936
- } else {
3937
- undo();
3938
- }
3939
- e.preventDefault();
3940
- break;
3941
- case "c":
3942
- break;
3943
- case "v":
3944
- break;
3945
- case "d":
3946
- duplicateSelected();
3947
- e.preventDefault();
3948
- break;
3949
- case "s":
3950
- exportToJSON(design);
3951
- e.preventDefault();
3952
- break;
3953
- }
3954
- } else {
3955
- switch (e.key) {
3956
- case "Delete":
3957
- case "Backspace":
3958
- deleteSelected();
3959
- break;
3960
- case "Escape":
3961
- setSelectedId(null);
3962
- setSelectedIds([]);
3963
- break;
3964
- }
3965
- }
3966
- };
3967
- window.addEventListener("keydown", handleKeyDown);
3968
- return () => window.removeEventListener("keydown", handleKeyDown);
3969
- }, [deleteSelected, duplicateSelected, exportToJSON, undo, redo]);
3970
- useEffect4(() => {
3971
- if (history.length === 0) {
3972
- setHistory([JSON.parse(JSON.stringify(design))]);
3973
- setHistoryIndex(0);
3974
- }
3975
- }, []);
3976
- return /* @__PURE__ */ React18.createElement("div", {
3977
- className: "h-screen flex flex-col bg-gray-900"
3978
- }, /* @__PURE__ */ React18.createElement(Header_default, {
3190
+ }, [store]);
3191
+ return /* @__PURE__ */ React17.createElement("div", {
3192
+ className: "w-full h-full flex flex-col bg-gray-900"
3193
+ }, /* @__PURE__ */ React17.createElement(Header_default, {
3979
3194
  name,
3980
- zoom,
3981
- historyIndex,
3982
- historyLength: history.length,
3983
- onUndo: undo,
3984
- onRedo: redo,
3985
- onZoomIn: () => setZoom(Math.min(3, zoom + 0.1)),
3986
- onZoomOut: () => setZoom(Math.max(0.1, zoom - 0.1)),
3987
- onZoomReset: () => setZoom(1),
3988
- onSetActivePanel: setActivePanelId
3989
- }), /* @__PURE__ */ React18.createElement("div", {
3195
+ zoom: store.zoom,
3196
+ historyIndex: 0,
3197
+ historyLength: 0,
3198
+ onUndo: () => {},
3199
+ onRedo: () => {},
3200
+ onZoomIn: () => store.setZoom(Math.min(3, store.zoom + 0.1)),
3201
+ onZoomOut: () => store.setZoom(Math.max(0.1, store.zoom - 0.1)),
3202
+ onZoomReset: () => store.setZoom(1),
3203
+ onSetActivePanel: store.openSidePanel
3204
+ }), /* @__PURE__ */ React17.createElement("div", {
3990
3205
  className: "flex-1 flex overflow-hidden"
3991
- }, /* @__PURE__ */ React18.createElement("div", {
3206
+ }, /* @__PURE__ */ React17.createElement("div", {
3992
3207
  className: "w-80 bg-gray-800 border-r border-gray-700 flex"
3993
- }, /* @__PURE__ */ React18.createElement(LeftMenu_default, {
3994
- tool,
3995
- activePanel: activePanelId,
3996
- onSetTool: setTool,
3997
- onSetActivePanel: setActivePanelId,
3208
+ }, /* @__PURE__ */ React17.createElement(LeftMenu_default, {
3209
+ tool: store.tool,
3210
+ activePanel: store.activePanelId || "elements",
3211
+ onSetTool: store.setTool,
3212
+ onSetActivePanel: store.openSidePanel,
3998
3213
  config
3999
- }), /* @__PURE__ */ React18.createElement("div", {
3214
+ }), /* @__PURE__ */ React17.createElement("div", {
4000
3215
  className: "flex-1 p-4 overflow-y-auto"
4001
- }, /* @__PURE__ */ React18.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React18.createElement("div", {
3216
+ }, /* @__PURE__ */ React17.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React17.createElement("div", {
4002
3217
  className: "flex-1 bg-gray-700 overflow-hidden relative",
4003
3218
  ref: containerRef
4004
- }, !currentPage ? /* @__PURE__ */ React18.createElement("div", {
3219
+ }, !currentPage ? /* @__PURE__ */ React17.createElement("div", {
4005
3220
  className: "absolute inset-0 flex items-center justify-center text-gray-400"
4006
- }, /* @__PURE__ */ React18.createElement("div", {
3221
+ }, /* @__PURE__ */ React17.createElement("div", {
4007
3222
  className: "text-center"
4008
- }, /* @__PURE__ */ React18.createElement("p", {
3223
+ }, /* @__PURE__ */ React17.createElement("p", {
4009
3224
  className: "mb-4"
4010
- }, "No pages available"), /* @__PURE__ */ React18.createElement("button", {
3225
+ }, "No pages available"), /* @__PURE__ */ React17.createElement("button", {
4011
3226
  onClick: () => store.addPage(),
4012
3227
  className: "px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
4013
- }, "Add Page"))) : /* @__PURE__ */ React18.createElement("div", {
3228
+ }, "Add Page"))) : /* @__PURE__ */ React17.createElement("div", {
4014
3229
  className: "absolute inset-0 flex items-center justify-center"
4015
- }, /* @__PURE__ */ React18.createElement("div", {
3230
+ }, /* @__PURE__ */ React17.createElement("div", {
4016
3231
  className: "bg-white shadow-2xl",
4017
3232
  style: {
4018
- transform: `scale(${zoom})`,
3233
+ transform: `scale(${store.zoom})`,
4019
3234
  transformOrigin: "center center"
4020
3235
  }
4021
- }, /* @__PURE__ */ React18.createElement(Stage, {
3236
+ }, /* @__PURE__ */ React17.createElement(Stage, {
4022
3237
  ref: stageRef,
4023
- width: design.width,
4024
- height: design.height,
3238
+ width: store.design.width,
3239
+ height: store.design.height,
4025
3240
  onClick: handleStageClick,
4026
3241
  onTap: handleStageClick
4027
- }, /* @__PURE__ */ React18.createElement(Layer, null, /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(Rect2, {
3242
+ }, /* @__PURE__ */ React17.createElement(Layer, null, /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(Rect2, {
4028
3243
  x: 0,
4029
3244
  y: 0,
4030
- width: design.width,
4031
- height: design.height,
3245
+ width: store.design.width,
3246
+ height: store.design.height,
4032
3247
  fill: currentPage.backgroundImageObject ? undefined : currentPage.background,
4033
3248
  fillPatternImage: currentPage.backgroundImageObject,
4034
3249
  fillPatternRepeat: "no-repeat"
4035
3250
  }), currentPage.elements.map((element) => {
4036
3251
  switch (element.type) {
4037
3252
  case "text":
4038
- return /* @__PURE__ */ React18.createElement(EditableTextElement, {
3253
+ return /* @__PURE__ */ React17.createElement(EditableTextElement, {
4039
3254
  key: element.id,
4040
3255
  element,
4041
- isSelected: element.id === selectedId,
3256
+ isSelected: element.id === store.selectedId,
4042
3257
  onSelect: () => {
4043
- setSelectedId(element.id);
4044
- setSelectedIds([]);
3258
+ store.setSelectedId(element.id);
3259
+ store.setSelectedIds([]);
4045
3260
  },
4046
3261
  onChange: (attrs) => updateElement(element.id, attrs)
4047
3262
  });
4048
3263
  case "image":
4049
- return /* @__PURE__ */ React18.createElement(UrlImageElement, {
3264
+ return /* @__PURE__ */ React17.createElement(UrlImageElement, {
4050
3265
  key: element.id,
4051
3266
  element,
4052
- isSelected: element.id === selectedId,
3267
+ isSelected: element.id === store.selectedId,
4053
3268
  onSelect: () => {
4054
- setSelectedId(element.id);
4055
- setSelectedIds([]);
3269
+ store.setSelectedId(element.id);
3270
+ store.setSelectedIds([]);
4056
3271
  },
4057
3272
  onChange: (attrs) => updateElement(element.id, attrs)
4058
3273
  });
4059
3274
  case "shape":
4060
- return /* @__PURE__ */ React18.createElement(ShapeElement, {
3275
+ return /* @__PURE__ */ React17.createElement(ShapeElement, {
4061
3276
  key: element.id,
4062
3277
  element,
4063
- isSelected: element.id === selectedId,
3278
+ isSelected: element.id === store.selectedId,
4064
3279
  onSelect: () => {
4065
- setSelectedId(element.id);
4066
- setSelectedIds([]);
3280
+ store.setSelectedId(element.id);
3281
+ store.setSelectedIds([]);
4067
3282
  },
4068
3283
  onChange: (attrs) => updateElement(element.id, attrs)
4069
3284
  });
4070
3285
  default:
4071
3286
  return null;
4072
3287
  }
4073
- })))))), " ", config?.multiPage && /* @__PURE__ */ React18.createElement("div", {
3288
+ })))))), config?.multiPage && /* @__PURE__ */ React17.createElement("div", {
4074
3289
  className: "absolute bottom-4 left-4 flex items-center space-x-2"
4075
- }, design.pages.map((page, index) => /* @__PURE__ */ React18.createElement("button", {
3290
+ }, store.design.pages.map((page, index) => /* @__PURE__ */ React17.createElement("button", {
4076
3291
  key: page.id,
4077
- onClick: () => setCurrentPageId(page.id),
4078
- 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"}`
4079
- }, "Page ", index + 1)), /* @__PURE__ */ React18.createElement("button", {
3292
+ onClick: () => store.setActivePage(page.id),
3293
+ className: `px-3 py-1 rounded text-sm ${page.id === store.activePageId ? "bg-blue-600 text-white" : "bg-gray-800 text-gray-300 hover:bg-gray-700"}`
3294
+ }, "Page ", index + 1)), /* @__PURE__ */ React17.createElement("button", {
4080
3295
  onClick: addPage,
4081
- className: "p-1 bg-gray-800 text-gray-300 rounded hover:bg-gray-700",
3296
+ className: "px-3 py-1 rounded text-sm bg-gray-800 text-gray-300 hover:bg-gray-700",
4082
3297
  title: "Add Page"
4083
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
3298
+ }, /* @__PURE__ */ React17.createElement(PlusCircle, {
4084
3299
  className: "w-4 h-4"
4085
- })))), /* @__PURE__ */ React18.createElement(RightSidebar_default, {
3300
+ })))), /* @__PURE__ */ React17.createElement(RightSidebar_default, {
4086
3301
  currentPageElements: currentPage?.elements || [],
4087
3302
  selectedElement,
4088
- selectedId,
4089
- onSelectElement: setSelectedId,
3303
+ selectedId: store.selectedId,
3304
+ onSelectElement: store.setSelectedId,
4090
3305
  onUpdateElement: updateElement,
4091
3306
  onDuplicateSelected: duplicateSelected,
4092
3307
  onMoveElementUp: moveElementUp,
4093
3308
  onMoveElementDown: moveElementDown,
4094
3309
  onDeleteSelected: deleteSelected
4095
- })), /* @__PURE__ */ React18.createElement("input", {
3310
+ })), /* @__PURE__ */ React17.createElement("input", {
4096
3311
  ref: fileInputRef,
4097
3312
  type: "file",
4098
3313
  accept: "image/*",
4099
3314
  onChange: handleImageUpload,
4100
- className: "hidden",
4101
- multiple: true
4102
- }), /* @__PURE__ */ React18.createElement("input", {
3315
+ style: { display: "none" }
3316
+ }), /* @__PURE__ */ React17.createElement("input", {
4103
3317
  ref: jsonInputRef,
4104
3318
  type: "file",
4105
3319
  accept: ".json",
4106
3320
  onChange: handleImportJSON,
4107
- className: "hidden"
4108
- }), showInputModal && /* @__PURE__ */ React18.createElement(TemplateInputModal_default, {
4109
- inputs: pendingInputs,
4110
- onComplete: handleInputModalComplete,
4111
- onCancel: handleInputModalCancel
4112
- }), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
4113
- className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
4114
- }, /* @__PURE__ */ React18.createElement("div", {
4115
- className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
4116
- }, /* @__PURE__ */ React18.createElement("div", {
4117
- className: "p-6 border-b border-gray-700"
4118
- }, /* @__PURE__ */ React18.createElement("h3", {
4119
- className: "text-xl font-semibold text-white mb-4"
4120
- }, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
4121
- className: "flex space-x-4"
4122
- }, /* @__PURE__ */ React18.createElement("input", {
4123
- type: "text",
4124
- value: unsplashQuery,
4125
- onChange: (e) => setUnsplashQuery(e.target.value),
4126
- onKeyDown: (e) => e.key === "Enter" && searchUnsplash(),
4127
- placeholder: "Search for images...",
4128
- className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
4129
- autoFocus: true
4130
- }), /* @__PURE__ */ React18.createElement("button", {
4131
- onClick: searchUnsplash,
4132
- className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
4133
- }, "Search"), /* @__PURE__ */ React18.createElement("button", {
4134
- onClick: () => {
4135
- setShowUnsplash(false);
4136
- setUnsplashQuery("");
4137
- setUnsplashResults([]);
4138
- },
4139
- className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
4140
- }, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
4141
- className: "flex-1 overflow-y-auto p-6"
4142
- }, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
4143
- className: "grid grid-cols-3 gap-4"
4144
- }, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
4145
- key: result.id,
4146
- onClick: () => addUnsplashImage(result.urls.regular),
4147
- className: "relative group overflow-hidden rounded-lg aspect-square"
4148
- }, /* @__PURE__ */ React18.createElement("img", {
4149
- src: result.urls.thumb,
4150
- alt: "",
4151
- className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
4152
- }), /* @__PURE__ */ React18.createElement("div", {
4153
- className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
4154
- }, /* @__PURE__ */ React18.createElement(PlusCircle, {
4155
- className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
4156
- }))))) : /* @__PURE__ */ React18.createElement("div", {
4157
- className: "text-center text-gray-400 py-12"
4158
- }, "Enter a search term to find images")))));
3321
+ style: { display: "none" }
3322
+ }));
4159
3323
  };
4160
3324
  var CanvasEditor_default = CanvasEditor;
4161
3325
  // src/context/CanvasStoreContext.tsx
@@ -4168,6 +3332,14 @@ var useCanvasStore = () => {
4168
3332
  }
4169
3333
  return store;
4170
3334
  };
3335
+ // src/config.ts
3336
+ var _unsplashAccessKey = typeof process !== "undefined" && process.env?.UNSPLASH_ACCESS_KEY ? process.env.UNSPLASH_ACCESS_KEY : undefined;
3337
+ function setUnsplashAccessKey(key) {
3338
+ _unsplashAccessKey = key;
3339
+ }
3340
+ function getUnsplashAccessKey() {
3341
+ return _unsplashAccessKey;
3342
+ }
4171
3343
 
4172
3344
  // src/lib/index.ts
4173
3345
  initJsxCompat();