@merchi/product-editor 0.1.9
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/.turbo/turbo-build.log +1 -0
- package/README.md +174 -0
- package/dist/components/AlignMenu.d.ts +3 -0
- package/dist/components/AlignMenu.js +61 -0
- package/dist/components/FloatingToolbar.d.ts +4 -0
- package/dist/components/FloatingToolbar.js +97 -0
- package/dist/components/FormatButtons.d.ts +2 -0
- package/dist/components/FormatButtons.js +22 -0
- package/dist/components/ImageNavButton.d.ts +7 -0
- package/dist/components/ImageNavButton.js +14 -0
- package/dist/components/ImageZoomModal.d.ts +12 -0
- package/dist/components/ImageZoomModal.js +129 -0
- package/dist/components/LayerPanel.d.ts +4 -0
- package/dist/components/LayerPanel.js +223 -0
- package/dist/components/LoadingOverlay.d.ts +9 -0
- package/dist/components/LoadingOverlay.js +17 -0
- package/dist/components/ProductEditor.d.ts +4 -0
- package/dist/components/ProductEditor.js +67 -0
- package/dist/components/ProductImageGallery.d.ts +6 -0
- package/dist/components/ProductImageGallery.js +148 -0
- package/dist/components/ProductPreviews.d.ts +7 -0
- package/dist/components/ProductPreviews.js +281 -0
- package/dist/components/TextToolbar.d.ts +4 -0
- package/dist/components/TextToolbar.js +117 -0
- package/dist/components/Toolbar.d.ts +3 -0
- package/dist/components/Toolbar.js +47 -0
- package/dist/config/colorConfig.d.ts +1 -0
- package/dist/config/colorConfig.js +10 -0
- package/dist/config/fontConfig.d.ts +5 -0
- package/dist/config/fontConfig.js +21 -0
- package/dist/context/ProductEditorContext.d.ts +60 -0
- package/dist/context/ProductEditorContext.js +743 -0
- package/dist/hooks/useSwipeNavigate.d.ts +11 -0
- package/dist/hooks/useSwipeNavigate.js +35 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +30 -0
- package/dist/styles/BottomPreviewDisplay.css +65 -0
- package/dist/styles/FloatingToolbar.css +41 -0
- package/dist/styles/ImageGallery.css +147 -0
- package/dist/styles/ImageNavButton.css +35 -0
- package/dist/styles/ImageZoomModal.css +101 -0
- package/dist/styles/LayerPanel.css +179 -0
- package/dist/styles/LoadingOverlay.css +48 -0
- package/dist/styles/ProductEditor.css +192 -0
- package/dist/styles/TextToolbar.css +327 -0
- package/dist/styles/Toolbar.css +125 -0
- package/dist/styles/index.css +5 -0
- package/dist/styles/textToolbarSelectStyles.d.ts +3 -0
- package/dist/styles/textToolbarSelectStyles.js +30 -0
- package/dist/types.d.ts +228 -0
- package/dist/types.js +17 -0
- package/dist/utils/canvasAddText.d.ts +11 -0
- package/dist/utils/canvasAddText.js +66 -0
- package/dist/utils/canvasUtils.d.ts +37 -0
- package/dist/utils/canvasUtils.js +342 -0
- package/dist/utils/deviceUtils.d.ts +5 -0
- package/dist/utils/deviceUtils.js +33 -0
- package/dist/utils/draftTemplateUtils.d.ts +23 -0
- package/dist/utils/draftTemplateUtils.js +66 -0
- package/dist/utils/grid.d.ts +32 -0
- package/dist/utils/grid.js +151 -0
- package/dist/utils/imageUtils.d.ts +12 -0
- package/dist/utils/imageUtils.js +178 -0
- package/dist/utils/job.d.ts +40 -0
- package/dist/utils/job.js +115 -0
- package/dist/utils/keyboard.d.ts +1 -0
- package/dist/utils/keyboard.js +26 -0
- package/dist/utils/previewUtils.d.ts +9 -0
- package/dist/utils/previewUtils.js +39 -0
- package/dist/utils/psdConverter.d.ts +40 -0
- package/dist/utils/psdConverter.js +516 -0
- package/dist/utils/psdRenderUtils.d.ts +12 -0
- package/dist/utils/psdRenderUtils.js +465 -0
- package/dist/utils/renderUtils.d.ts +2 -0
- package/dist/utils/renderUtils.js +85 -0
- package/package.json +66 -0
- package/src/components/AlignMenu.tsx +49 -0
- package/src/components/FloatingToolbar.tsx +83 -0
- package/src/components/FormatButtons.tsx +31 -0
- package/src/components/ImageNavButton.tsx +23 -0
- package/src/components/ImageZoomModal.tsx +163 -0
- package/src/components/LayerPanel.tsx +256 -0
- package/src/components/LoadingOverlay.tsx +27 -0
- package/src/components/ProductEditor.tsx +104 -0
- package/src/components/ProductImageGallery.tsx +181 -0
- package/src/components/ProductPreviews.tsx +243 -0
- package/src/components/TextToolbar.tsx +164 -0
- package/src/components/Toolbar.tsx +86 -0
- package/src/config/colorConfig.ts +7 -0
- package/src/config/fontConfig.ts +23 -0
- package/src/context/ProductEditorContext.tsx +829 -0
- package/src/hooks/useSwipeNavigate.ts +40 -0
- package/src/index.ts +6 -0
- package/src/styles/BottomPreviewDisplay.css +65 -0
- package/src/styles/FloatingToolbar.css +41 -0
- package/src/styles/ImageGallery.css +147 -0
- package/src/styles/ImageNavButton.css +35 -0
- package/src/styles/ImageZoomModal.css +101 -0
- package/src/styles/LayerPanel.css +179 -0
- package/src/styles/LoadingOverlay.css +48 -0
- package/src/styles/ProductEditor.css +192 -0
- package/src/styles/TextToolbar.css +327 -0
- package/src/styles/Toolbar.css +125 -0
- package/src/styles/index.css +5 -0
- package/src/styles/textToolbarSelectStyles.ts +60 -0
- package/src/types/ag-psd/index.d.ts +1 -0
- package/src/types/fabric.d.ts +14 -0
- package/src/types/lodash/index.d.ts +1 -0
- package/src/types/psd.d.ts +53 -0
- package/src/types.ts +247 -0
- package/src/utils/canvasAddText.ts +72 -0
- package/src/utils/canvasUtils.ts +406 -0
- package/src/utils/deviceUtils.ts +31 -0
- package/src/utils/draftTemplateUtils.ts +70 -0
- package/src/utils/grid.ts +154 -0
- package/src/utils/imageUtils.ts +218 -0
- package/src/utils/job.ts +128 -0
- package/src/utils/keyboard.ts +28 -0
- package/src/utils/previewUtils.ts +43 -0
- package/src/utils/psdConverter.ts +595 -0
- package/src/utils/psdRenderUtils.ts +453 -0
- package/src/utils/renderUtils.ts +44 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for psd.js
|
|
3
|
+
* https://github.com/meltingice/psd.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare module 'psd.js' {
|
|
7
|
+
export interface PsdHeader {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
channels: number;
|
|
11
|
+
depth: number;
|
|
12
|
+
mode: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PsdImage {
|
|
16
|
+
width: () => number;
|
|
17
|
+
height: () => number;
|
|
18
|
+
toPng: () => HTMLImageElement;
|
|
19
|
+
toBase64: () => string;
|
|
20
|
+
saveAsPng: (output: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface PsdLayer {
|
|
24
|
+
name: string;
|
|
25
|
+
visible: boolean;
|
|
26
|
+
opacity: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
top: number;
|
|
30
|
+
left: number;
|
|
31
|
+
toPng: () => HTMLImageElement;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PsdFile {
|
|
35
|
+
header: PsdHeader;
|
|
36
|
+
image: PsdImage;
|
|
37
|
+
layers: PsdLayer[];
|
|
38
|
+
tree: () => any;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function fromURL(url: string): Promise<PsdFile>;
|
|
42
|
+
export function fromBuffer(buffer: ArrayBuffer): Promise<PsdFile>;
|
|
43
|
+
export function fromFile(file: File): Promise<PsdFile>;
|
|
44
|
+
|
|
45
|
+
// Default export
|
|
46
|
+
const PSD: {
|
|
47
|
+
fromURL: typeof fromURL;
|
|
48
|
+
fromBuffer: typeof fromBuffer;
|
|
49
|
+
fromFile: typeof fromFile;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default PSD;
|
|
53
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
export enum FieldType {
|
|
2
|
+
TEXT_INPUT = 1,
|
|
3
|
+
SELECT = 2,
|
|
4
|
+
FILE_UPLOAD = 3,
|
|
5
|
+
TEXT_AREA = 4,
|
|
6
|
+
NUMBER_INPUT = 5,
|
|
7
|
+
CHECKBOX = 6,
|
|
8
|
+
RADIO = 7,
|
|
9
|
+
FIELD_INSTRUCTIONS = 8,
|
|
10
|
+
IMAGE_SELECT = 9,
|
|
11
|
+
COLOUR_PICKER = 10,
|
|
12
|
+
COLOUR_SELECT = 11,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Draft {
|
|
16
|
+
id?: number;
|
|
17
|
+
// Add other draft properties as needed
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface MerchiFile {
|
|
21
|
+
id?: number;
|
|
22
|
+
uploadId?: string;
|
|
23
|
+
name?: string | null;
|
|
24
|
+
mimetype?: string | null;
|
|
25
|
+
size?: number;
|
|
26
|
+
creationDate?: Date | null;
|
|
27
|
+
cachedViewUrl?: string | null;
|
|
28
|
+
viewUrlExpires?: Date | null;
|
|
29
|
+
cachedDownloadUrl?: string | null;
|
|
30
|
+
downloadUrlExpires?: Date | null;
|
|
31
|
+
viewUrl: string;
|
|
32
|
+
downloadUrl?: string;
|
|
33
|
+
thumbnailUrl?: string;
|
|
34
|
+
previewUrl?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DraftTemplate {
|
|
38
|
+
id?: number;
|
|
39
|
+
name?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
width?: number;
|
|
42
|
+
height?: number;
|
|
43
|
+
file?: MerchiFile;
|
|
44
|
+
product?: Product | null;
|
|
45
|
+
editedByVariationFields?: VariationField[];
|
|
46
|
+
selectedByVariationFieldOptions?: VariationFieldsOption[];
|
|
47
|
+
draftPreviewLayers?: DraftPreviewLayer[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface DraftPreview {
|
|
51
|
+
id?: number;
|
|
52
|
+
file?: MerchiFile;
|
|
53
|
+
product?: Product;
|
|
54
|
+
description?: string | null;
|
|
55
|
+
name?: string | null;
|
|
56
|
+
date?: Date | null;
|
|
57
|
+
height?: number;
|
|
58
|
+
width?: number;
|
|
59
|
+
draftPreviewLayers?: DraftPreviewLayer[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface DraftPreviewLayer {
|
|
63
|
+
id?: number;
|
|
64
|
+
layerName?: string;
|
|
65
|
+
draftPreview?: DraftPreview;
|
|
66
|
+
draftTemplate?: DraftTemplate;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface VariationFieldsOption {
|
|
70
|
+
id?: number;
|
|
71
|
+
archived?: Date | null;
|
|
72
|
+
value?: string | null;
|
|
73
|
+
colour?: string | null;
|
|
74
|
+
currency?: string;
|
|
75
|
+
default?: boolean;
|
|
76
|
+
include?: boolean;
|
|
77
|
+
noInventory?: boolean;
|
|
78
|
+
position?: number;
|
|
79
|
+
variationCost?: number;
|
|
80
|
+
variationUnitCost?: number;
|
|
81
|
+
buyUnitCost?: number;
|
|
82
|
+
buyCost?: number;
|
|
83
|
+
variationField?: VariationField | null;
|
|
84
|
+
linkedFile?: MerchiFile | null;
|
|
85
|
+
selectedByVariations?: Variation[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface VariationField {
|
|
89
|
+
id?: number;
|
|
90
|
+
archived?: Date | null;
|
|
91
|
+
position?: number;
|
|
92
|
+
required?: boolean;
|
|
93
|
+
independent?: boolean;
|
|
94
|
+
name?: string;
|
|
95
|
+
instructions?: string;
|
|
96
|
+
placeholder?: string | null;
|
|
97
|
+
defaultValue?: string;
|
|
98
|
+
currency?: string;
|
|
99
|
+
fieldType?: FieldType;
|
|
100
|
+
margin?: number;
|
|
101
|
+
variationCost?: number;
|
|
102
|
+
variationUnitCost?: number;
|
|
103
|
+
buyUnitCost?: number;
|
|
104
|
+
buyCost?: number;
|
|
105
|
+
rows?: number;
|
|
106
|
+
fieldMin?: number | null;
|
|
107
|
+
fieldMax?: number | null;
|
|
108
|
+
allowDecimal?: boolean;
|
|
109
|
+
sellerProductEditable?: boolean;
|
|
110
|
+
multipleSelect?: boolean;
|
|
111
|
+
showFilePreview?: boolean;
|
|
112
|
+
allowFileMultiple?: boolean;
|
|
113
|
+
allowFileJpeg?: boolean;
|
|
114
|
+
allowFileGif?: boolean;
|
|
115
|
+
allowFilePdf?: boolean;
|
|
116
|
+
allowFilePng?: boolean;
|
|
117
|
+
allowFileAi?: boolean;
|
|
118
|
+
product?: Product;
|
|
119
|
+
variations?: Variation[];
|
|
120
|
+
options?: VariationFieldsOption[];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface VariationOption {
|
|
124
|
+
optionId?: number;
|
|
125
|
+
value?: string | null;
|
|
126
|
+
colour?: string | null;
|
|
127
|
+
position?: number;
|
|
128
|
+
available?: boolean;
|
|
129
|
+
default?: boolean;
|
|
130
|
+
include?: boolean;
|
|
131
|
+
linkedFile?: MerchiFile | null;
|
|
132
|
+
fieldName?: string;
|
|
133
|
+
quantity?: number;
|
|
134
|
+
currency?: string;
|
|
135
|
+
onceOffCost?: number;
|
|
136
|
+
unitCost?: number;
|
|
137
|
+
unitCostTotal?: number;
|
|
138
|
+
totalCost?: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface Variation {
|
|
142
|
+
id?: number;
|
|
143
|
+
archived?: Date | null;
|
|
144
|
+
value?: string | null;
|
|
145
|
+
currency?: string;
|
|
146
|
+
cost?: number;
|
|
147
|
+
quantity?: number;
|
|
148
|
+
onceOffCost?: number;
|
|
149
|
+
unitCost?: number;
|
|
150
|
+
unitCostTotal?: number;
|
|
151
|
+
variationField?: VariationField;
|
|
152
|
+
variationsGroup?: VariationsGroup | null;
|
|
153
|
+
job?: Job | null;
|
|
154
|
+
variationFiles?: MerchiFile[];
|
|
155
|
+
selectedOptions?: VariationOption[];
|
|
156
|
+
selectableOptions?: VariationOption[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface VariationsGroup {
|
|
160
|
+
id?: number;
|
|
161
|
+
archived?: Date | null;
|
|
162
|
+
quantity?: number;
|
|
163
|
+
groupCost?: number | null;
|
|
164
|
+
job?: Job | null;
|
|
165
|
+
variations?: Variation[];
|
|
166
|
+
inventoryCount?: number;
|
|
167
|
+
inventorySufficient?: boolean;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface Product {
|
|
171
|
+
id?: number;
|
|
172
|
+
name?: string;
|
|
173
|
+
description?: string | null;
|
|
174
|
+
draftTemplates?: DraftTemplate[];
|
|
175
|
+
draftPreviews?: DraftPreview[];
|
|
176
|
+
featureImage?: MerchiFile;
|
|
177
|
+
groupVariationFields?: VariationField[];
|
|
178
|
+
independentVariationFields?: VariationField[];
|
|
179
|
+
images?: MerchiFile[];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface Job {
|
|
183
|
+
id?: number;
|
|
184
|
+
quantity?: number;
|
|
185
|
+
currency?: string;
|
|
186
|
+
jobInfoApprovedByClient?: boolean;
|
|
187
|
+
costPerUnit?: number | null;
|
|
188
|
+
cost?: number | null;
|
|
189
|
+
taxAmount?: number | null;
|
|
190
|
+
totalCost?: number | null;
|
|
191
|
+
drafts?: Draft[];
|
|
192
|
+
sharedDrafts?: Draft[];
|
|
193
|
+
ownDrafts?: Draft[];
|
|
194
|
+
product?: Product;
|
|
195
|
+
variationsGroups?: VariationsGroup[];
|
|
196
|
+
variations?: Variation[];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface ProductEditorProps {
|
|
200
|
+
product: Product;
|
|
201
|
+
width?: number;
|
|
202
|
+
height?: number;
|
|
203
|
+
onSave?: (editedImage: string) => void;
|
|
204
|
+
onCancel?: () => void;
|
|
205
|
+
psdTemplateUrl?: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface SavedCanvasObject {
|
|
209
|
+
fieldId: string;
|
|
210
|
+
fileId?: string;
|
|
211
|
+
uniqueId?: string; // Add uniqueId property to the interface
|
|
212
|
+
type: string;
|
|
213
|
+
left: number;
|
|
214
|
+
top: number;
|
|
215
|
+
scaleX: number;
|
|
216
|
+
scaleY: number;
|
|
217
|
+
angle: number;
|
|
218
|
+
text?: string;
|
|
219
|
+
fontSize?: number;
|
|
220
|
+
fontFamily?: string;
|
|
221
|
+
fill?: string;
|
|
222
|
+
width?: number;
|
|
223
|
+
height?: number;
|
|
224
|
+
src?: string;
|
|
225
|
+
[key: string]: any; // Allow for other properties
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// New DraftTemplateData type definition that includes all requested properties
|
|
229
|
+
export interface DraftTemplateData {
|
|
230
|
+
template: DraftTemplate;
|
|
231
|
+
variationFieldIds: number[]; // List of IDs for all variation fields in this template
|
|
232
|
+
variationObjects: any[]; // Objects associated with the variation fields
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface RenderedDraftPreview {
|
|
236
|
+
templateId: number;
|
|
237
|
+
draft: string; // base64 string of the template artwork as a draft
|
|
238
|
+
canvasPreview: string; // base64 string of the template rendered with the full canvas
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface MappedPreview {
|
|
242
|
+
draftPreview: DraftPreview;
|
|
243
|
+
draftPreviewLayers: {
|
|
244
|
+
layerName: string | undefined;
|
|
245
|
+
renderedLayer: RenderedDraftPreview | null;
|
|
246
|
+
}[];
|
|
247
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// add text to the canvas
|
|
2
|
+
import { fabric } from 'fabric';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Adds an editable text object to the canvas
|
|
6
|
+
* @param canvas - The Fabric.js canvas instance
|
|
7
|
+
* @param width - The width of the canvas
|
|
8
|
+
* @param height - The height of the canvas
|
|
9
|
+
* @param defaultText - Optional default text (defaults to "Text")
|
|
10
|
+
* @param fontSize - Optional font size (defaults to 24)
|
|
11
|
+
* @param fontFamily - Optional font family (defaults to Arial)
|
|
12
|
+
*/
|
|
13
|
+
export const addText = (
|
|
14
|
+
canvas: fabric.Canvas,
|
|
15
|
+
width: number,
|
|
16
|
+
height: number,
|
|
17
|
+
defaultText: string = 'Text',
|
|
18
|
+
fontSize: number = 24,
|
|
19
|
+
fontFamily: string = 'Nunito'
|
|
20
|
+
) => {
|
|
21
|
+
if (!canvas) return null;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Safe check if canvas is still valid
|
|
25
|
+
if (!canvas.getElement() || !canvas.getElement().parentNode) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Create a new text object with minimal options
|
|
30
|
+
const text = new fabric.IText(defaultText, {
|
|
31
|
+
left: width / 2,
|
|
32
|
+
top: height / 2,
|
|
33
|
+
fontFamily: fontFamily,
|
|
34
|
+
fontSize: fontSize,
|
|
35
|
+
fill: '#000000',
|
|
36
|
+
originX: 'center',
|
|
37
|
+
originY: 'center',
|
|
38
|
+
selectable: true,
|
|
39
|
+
editable: false
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Add the text to the canvas
|
|
43
|
+
canvas.add(text);
|
|
44
|
+
|
|
45
|
+
// Ensure the text is rendered
|
|
46
|
+
canvas.renderAll();
|
|
47
|
+
|
|
48
|
+
// Make the text active - this is critical
|
|
49
|
+
const setActiveTextObject = () => {
|
|
50
|
+
try {
|
|
51
|
+
// Check if canvas is still valid
|
|
52
|
+
if (canvas && canvas.getElement() && canvas.getElement().parentNode) {
|
|
53
|
+
canvas.setActiveObject(text);
|
|
54
|
+
canvas.renderAll();
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error('Error setting active text object:', err);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Initial selection
|
|
62
|
+
setActiveTextObject();
|
|
63
|
+
|
|
64
|
+
// Delayed selection to ensure text becomes active
|
|
65
|
+
setTimeout(setActiveTextObject, 50);
|
|
66
|
+
|
|
67
|
+
return text;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Error adding text to canvas:', error);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
};
|