@bosonprotocol/react-kit 0.32.0-alpha.9 → 0.32.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.
- package/dist/cjs/components/error/SimpleError.d.ts +7 -5
- package/dist/cjs/components/error/SimpleError.d.ts.map +1 -1
- package/dist/cjs/components/error/SimpleError.js +4 -4
- package/dist/cjs/components/error/SimpleError.js.map +1 -1
- package/dist/cjs/components/form/Field.styles.d.ts +0 -1
- package/dist/cjs/components/form/Field.styles.d.ts.map +1 -1
- package/dist/cjs/components/form/Field.styles.js.map +1 -1
- package/dist/cjs/components/form/FormField.d.ts +1 -1
- package/dist/cjs/components/form/FormField.d.ts.map +1 -1
- package/dist/cjs/components/form/FormField.js +5 -3
- package/dist/cjs/components/form/FormField.js.map +1 -1
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.d.ts +9 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.d.ts.map +1 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.js +65 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.js.map +1 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts +10 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts.map +1 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.js +100 -0
- package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.js.map +1 -0
- package/dist/cjs/components/form/Upload/Upload.d.ts +39 -2
- package/dist/cjs/components/form/Upload/Upload.d.ts.map +1 -1
- package/dist/cjs/components/form/Upload/Upload.js +81 -19
- package/dist/cjs/components/form/Upload/Upload.js.map +1 -1
- package/dist/cjs/components/form/Upload/WithUploadToIpfs.d.ts +1 -1
- package/dist/cjs/components/form/Upload/WithUploadToIpfs.d.ts.map +1 -1
- package/dist/cjs/components/form/Upload/WithUploadToIpfs.js +9 -7
- package/dist/cjs/components/form/Upload/WithUploadToIpfs.js.map +1 -1
- package/dist/cjs/components/form/index.d.ts +1 -1
- package/dist/cjs/components/form/index.d.ts.map +1 -1
- package/dist/cjs/components/form/index.js +1 -1
- package/dist/cjs/components/form/index.js.map +1 -1
- package/dist/cjs/components/form/types.d.ts +17 -4
- package/dist/cjs/components/form/types.d.ts.map +1 -1
- package/dist/cjs/components/modal/ModalComponents.d.ts +2 -0
- package/dist/cjs/components/modal/ModalComponents.d.ts.map +1 -1
- package/dist/cjs/components/modal/ModalComponents.js +3 -1
- package/dist/cjs/components/modal/ModalComponents.js.map +1 -1
- package/dist/cjs/components/modal/ModalContext.d.ts +2 -1
- package/dist/cjs/components/modal/ModalContext.d.ts.map +1 -1
- package/dist/cjs/components/modal/ModalContext.js.map +1 -1
- package/dist/cjs/components/modal/ModalTypes.d.ts +1 -0
- package/dist/cjs/components/modal/ModalTypes.d.ts.map +1 -1
- package/dist/cjs/components/modal/ModalTypes.js +2 -1
- package/dist/cjs/components/modal/ModalTypes.js.map +1 -1
- package/dist/cjs/components/modal/useModal.d.ts +3 -2
- package/dist/cjs/components/modal/useModal.d.ts.map +1 -1
- package/dist/cjs/hooks/images/useFileImage.d.ts +8 -0
- package/dist/cjs/hooks/images/useFileImage.d.ts.map +1 -0
- package/dist/cjs/hooks/images/useFileImage.js +26 -0
- package/dist/cjs/hooks/images/useFileImage.js.map +1 -0
- package/dist/cjs/hooks/images/useIpfsImage.d.ts +13 -0
- package/dist/cjs/hooks/images/useIpfsImage.d.ts.map +1 -0
- package/dist/cjs/hooks/images/useIpfsImage.js +26 -0
- package/dist/cjs/hooks/images/useIpfsImage.js.map +1 -0
- package/dist/cjs/lib/base64/base64.d.ts +4 -1
- package/dist/cjs/lib/base64/base64.d.ts.map +1 -1
- package/dist/cjs/lib/base64/base64.js +1 -1
- package/dist/cjs/lib/base64/base64.js.map +1 -1
- package/dist/esm/components/error/SimpleError.d.ts +7 -5
- package/dist/esm/components/error/SimpleError.d.ts.map +1 -1
- package/dist/esm/components/error/SimpleError.js +4 -4
- package/dist/esm/components/error/SimpleError.js.map +1 -1
- package/dist/esm/components/form/Field.styles.d.ts +0 -1
- package/dist/esm/components/form/Field.styles.d.ts.map +1 -1
- package/dist/esm/components/form/Field.styles.js.map +1 -1
- package/dist/esm/components/form/FormField.d.ts +1 -1
- package/dist/esm/components/form/FormField.d.ts.map +1 -1
- package/dist/esm/components/form/FormField.js +3 -2
- package/dist/esm/components/form/FormField.js.map +1 -1
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.d.ts +9 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.d.ts.map +1 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.js +36 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.js.map +1 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts +10 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts.map +1 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.js +48 -0
- package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.js.map +1 -0
- package/dist/esm/components/form/Upload/Upload.d.ts +39 -2
- package/dist/esm/components/form/Upload/Upload.d.ts.map +1 -1
- package/dist/esm/components/form/Upload/Upload.js +93 -19
- package/dist/esm/components/form/Upload/Upload.js.map +1 -1
- package/dist/esm/components/form/Upload/WithUploadToIpfs.d.ts +1 -1
- package/dist/esm/components/form/Upload/WithUploadToIpfs.d.ts.map +1 -1
- package/dist/esm/components/form/Upload/WithUploadToIpfs.js +9 -7
- package/dist/esm/components/form/Upload/WithUploadToIpfs.js.map +1 -1
- package/dist/esm/components/form/index.d.ts +1 -1
- package/dist/esm/components/form/index.d.ts.map +1 -1
- package/dist/esm/components/form/index.js +1 -1
- package/dist/esm/components/form/index.js.map +1 -1
- package/dist/esm/components/form/types.d.ts +17 -4
- package/dist/esm/components/form/types.d.ts.map +1 -1
- package/dist/esm/components/modal/ModalComponents.d.ts +2 -0
- package/dist/esm/components/modal/ModalComponents.d.ts.map +1 -1
- package/dist/esm/components/modal/ModalComponents.js +3 -1
- package/dist/esm/components/modal/ModalComponents.js.map +1 -1
- package/dist/esm/components/modal/ModalContext.d.ts +2 -1
- package/dist/esm/components/modal/ModalContext.d.ts.map +1 -1
- package/dist/esm/components/modal/ModalContext.js.map +1 -1
- package/dist/esm/components/modal/ModalTypes.d.ts +1 -0
- package/dist/esm/components/modal/ModalTypes.d.ts.map +1 -1
- package/dist/esm/components/modal/ModalTypes.js +2 -1
- package/dist/esm/components/modal/ModalTypes.js.map +1 -1
- package/dist/esm/components/modal/useModal.d.ts +3 -2
- package/dist/esm/components/modal/useModal.d.ts.map +1 -1
- package/dist/esm/hooks/images/useFileImage.d.ts +8 -0
- package/dist/esm/hooks/images/useFileImage.d.ts.map +1 -0
- package/dist/esm/hooks/images/useFileImage.js +13 -0
- package/dist/esm/hooks/images/useFileImage.js.map +1 -0
- package/dist/esm/hooks/images/useIpfsImage.d.ts +13 -0
- package/dist/esm/hooks/images/useIpfsImage.d.ts.map +1 -0
- package/dist/esm/hooks/images/useIpfsImage.js +16 -0
- package/dist/esm/hooks/images/useIpfsImage.js.map +1 -0
- package/dist/esm/lib/base64/base64.d.ts +4 -1
- package/dist/esm/lib/base64/base64.d.ts.map +1 -1
- package/dist/esm/lib/base64/base64.js +1 -1
- package/dist/esm/lib/base64/base64.js.map +1 -1
- package/package.json +7 -4
- package/src/components/error/SimpleError.tsx +19 -10
- package/src/components/form/Field.styles.ts +1 -1
- package/src/components/form/FormField.tsx +6 -4
- package/src/components/form/Upload/ImageEditorModal/ImageEditor.tsx +74 -0
- package/src/components/form/Upload/ImageEditorModal/ImageEditorModal.tsx +77 -0
- package/src/components/form/Upload/Upload.tsx +137 -41
- package/src/components/form/Upload/WithUploadToIpfs.tsx +13 -11
- package/src/components/form/index.ts +1 -1
- package/src/components/form/types.ts +18 -3
- package/src/components/modal/ModalComponents.tsx +3 -1
- package/src/components/modal/ModalContext.tsx +4 -3
- package/src/components/modal/ModalTypes.ts +2 -1
- package/src/hooks/images/useFileImage.ts +24 -0
- package/src/hooks/images/useIpfsImage.ts +27 -0
- package/src/lib/base64/base64.ts +1 -1
- package/src/stories/buttons/Upload.stories.tsx +82 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Sentry from "@sentry/browser";
|
|
1
2
|
import { useField } from "formik";
|
|
2
3
|
import { Image, Trash, VideoCamera } from "phosphor-react";
|
|
3
4
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
@@ -19,6 +20,8 @@ import {
|
|
|
19
20
|
import type { UploadFileType, UploadProps, FileProps } from "../types";
|
|
20
21
|
import UploadedFiles from "./UploadedFiles";
|
|
21
22
|
import { WithUploadToIpfs, WithUploadToIpfsProps } from "./WithUploadToIpfs";
|
|
23
|
+
import { useModal } from "../../modal/useModal";
|
|
24
|
+
import { ImageEditorModal } from "./ImageEditorModal/ImageEditorModal";
|
|
22
25
|
const colors = theme.colors.light;
|
|
23
26
|
|
|
24
27
|
function Upload({
|
|
@@ -33,11 +36,21 @@ function Upload({
|
|
|
33
36
|
wrapperProps,
|
|
34
37
|
onLoadSinglePreviewImage,
|
|
35
38
|
withUpload,
|
|
39
|
+
withEditor,
|
|
36
40
|
saveToIpfs,
|
|
37
41
|
loadMedia,
|
|
38
42
|
onLoading,
|
|
43
|
+
width,
|
|
44
|
+
height,
|
|
45
|
+
borderRadius,
|
|
46
|
+
imgPreviewStyle,
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
48
|
+
removeFile,
|
|
49
|
+
saveButtonTheme,
|
|
39
50
|
...props
|
|
40
51
|
}: UploadProps & WithUploadToIpfsProps) {
|
|
52
|
+
const { updateProps, store } = useModal();
|
|
53
|
+
const [showEditor, setShowEditor] = useState<boolean>(false);
|
|
41
54
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
42
55
|
const [preview, setPreview] = useState<string | null>();
|
|
43
56
|
const [field, meta, helpers] = useField(name);
|
|
@@ -51,10 +64,10 @@ function Upload({
|
|
|
51
64
|
);
|
|
52
65
|
|
|
53
66
|
const errorMessage = meta.error && meta.touched ? meta.error : "";
|
|
54
|
-
const displayError =
|
|
55
|
-
typeof errorMessage === typeof "string" && errorMessage !== "";
|
|
67
|
+
const displayError = typeof errorMessage === "string" && errorMessage !== "";
|
|
56
68
|
|
|
57
69
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
70
|
+
const [nativeFiles, setNativeFiles] = useState<File[] | null>(null);
|
|
58
71
|
const setFiles = useCallback(
|
|
59
72
|
(value: unknown) => {
|
|
60
73
|
helpers.setValue(value);
|
|
@@ -74,7 +87,7 @@ function Upload({
|
|
|
74
87
|
useEffect(() => {
|
|
75
88
|
onFilesSelect?.(files);
|
|
76
89
|
helpers.setValue(files);
|
|
77
|
-
|
|
90
|
+
console.log("useEffect", { files });
|
|
78
91
|
if (!multiple && files && files?.length !== 0) {
|
|
79
92
|
if (isImageOnly) {
|
|
80
93
|
if (withUpload) {
|
|
@@ -104,10 +117,17 @@ function Upload({
|
|
|
104
117
|
}
|
|
105
118
|
handleLoading(true);
|
|
106
119
|
try {
|
|
107
|
-
const imagePreview
|
|
108
|
-
|
|
120
|
+
const imagePreview = await loadMedia(fileSrc || "");
|
|
121
|
+
if (imagePreview) {
|
|
122
|
+
setPreview(imagePreview);
|
|
123
|
+
} else {
|
|
124
|
+
console.warn(
|
|
125
|
+
`imagePreview ${imagePreview} is falsy in loadIpfsImagePreview`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
109
128
|
} catch (error) {
|
|
110
129
|
console.error(error);
|
|
130
|
+
Sentry.captureException(error);
|
|
111
131
|
} finally {
|
|
112
132
|
handleLoading(false);
|
|
113
133
|
}
|
|
@@ -120,11 +140,18 @@ function Upload({
|
|
|
120
140
|
}
|
|
121
141
|
try {
|
|
122
142
|
handleLoading(true);
|
|
123
|
-
const imagePreview
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
const imagePreview = await loadMedia(fileSrc || "");
|
|
144
|
+
if (imagePreview) {
|
|
145
|
+
setPreview(imagePreview);
|
|
146
|
+
onLoadSinglePreviewImage?.(imagePreview);
|
|
147
|
+
} else {
|
|
148
|
+
console.warn(
|
|
149
|
+
`imagePreview ${imagePreview} is falsy in loadIpfsImagePreview`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
126
152
|
} catch (error) {
|
|
127
153
|
console.error(error);
|
|
154
|
+
Sentry.captureException(error);
|
|
128
155
|
} finally {
|
|
129
156
|
handleLoading(false);
|
|
130
157
|
}
|
|
@@ -152,41 +179,83 @@ function Upload({
|
|
|
152
179
|
setFiles(newArray);
|
|
153
180
|
};
|
|
154
181
|
|
|
155
|
-
const handleChange = (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
182
|
+
const handleChange = useCallback(
|
|
183
|
+
async (filesArray: File[] | null) => {
|
|
184
|
+
if (!meta.touched) {
|
|
185
|
+
helpers.setTouched(true);
|
|
186
|
+
}
|
|
159
187
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
console.error(error);
|
|
188
|
+
if (!filesArray) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
for (const file of filesArray) {
|
|
192
|
+
if (maxSize) {
|
|
193
|
+
if (file.size > maxSize) {
|
|
194
|
+
const error = `File size cannot exceed more than ${bytesToSize(
|
|
195
|
+
maxSize
|
|
196
|
+
)}`;
|
|
197
|
+
// TODO: change to notification
|
|
198
|
+
console.error(error);
|
|
199
|
+
}
|
|
173
200
|
}
|
|
174
201
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
202
|
+
setFiles(filesArray);
|
|
203
|
+
},
|
|
204
|
+
[helpers, maxSize, meta.touched, setFiles]
|
|
205
|
+
);
|
|
178
206
|
|
|
179
207
|
const handleSave = useCallback(
|
|
180
|
-
async (
|
|
208
|
+
async (efiles: File[] | null) => {
|
|
209
|
+
if (!meta.touched) {
|
|
210
|
+
helpers.setTouched(true);
|
|
211
|
+
}
|
|
181
212
|
handleLoading(true);
|
|
182
|
-
const files
|
|
183
|
-
|
|
213
|
+
const files = await saveToIpfs(efiles);
|
|
214
|
+
if (files) {
|
|
215
|
+
setFiles(files);
|
|
216
|
+
} else {
|
|
217
|
+
setFiles([]);
|
|
218
|
+
console.warn(
|
|
219
|
+
`There has been an error because 'files' ${files} is falsy in handleSave`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
handleLoading(false);
|
|
184
223
|
},
|
|
185
|
-
[saveToIpfs,
|
|
224
|
+
[meta.touched, handleLoading, saveToIpfs, helpers, setFiles]
|
|
186
225
|
);
|
|
187
|
-
|
|
226
|
+
const saveFn = withUpload ? handleSave : handleChange;
|
|
227
|
+
const style = {
|
|
228
|
+
borderRadius: borderRadius ? `${borderRadius}%` : "",
|
|
229
|
+
width: width ? `100%` : ""
|
|
230
|
+
};
|
|
188
231
|
return (
|
|
189
232
|
<>
|
|
233
|
+
{withEditor && showEditor && (
|
|
234
|
+
<ImageEditorModal
|
|
235
|
+
saveButtonTheme={saveButtonTheme}
|
|
236
|
+
files={nativeFiles}
|
|
237
|
+
borderRadius={borderRadius}
|
|
238
|
+
width={width}
|
|
239
|
+
height={height}
|
|
240
|
+
hideModal={async (fileList) => {
|
|
241
|
+
if (fileList) {
|
|
242
|
+
await saveFn(fileList);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
setShowEditor(false);
|
|
246
|
+
updateProps({
|
|
247
|
+
...store,
|
|
248
|
+
modalType: store.modalType,
|
|
249
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
250
|
+
// @ts-ignore
|
|
251
|
+
modalProps: {
|
|
252
|
+
...store.modalProps,
|
|
253
|
+
hidden: false
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}}
|
|
257
|
+
/>
|
|
258
|
+
)}
|
|
190
259
|
<FieldFileUploadWrapper {...wrapperProps} $disabled={!!disabled}>
|
|
191
260
|
<FieldInput
|
|
192
261
|
{...props}
|
|
@@ -194,7 +263,29 @@ function Upload({
|
|
|
194
263
|
type="file"
|
|
195
264
|
accept={accept}
|
|
196
265
|
multiple={multiple}
|
|
197
|
-
onChange={
|
|
266
|
+
onChange={async (e) => {
|
|
267
|
+
const files = e.target.files
|
|
268
|
+
? Object.values(e.target.files)
|
|
269
|
+
: e.target.files;
|
|
270
|
+
|
|
271
|
+
if (files && withEditor) {
|
|
272
|
+
setNativeFiles(files);
|
|
273
|
+
setShowEditor(true);
|
|
274
|
+
updateProps({
|
|
275
|
+
...store,
|
|
276
|
+
modalType: store.modalType,
|
|
277
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
278
|
+
// @ts-ignore
|
|
279
|
+
modalProps: {
|
|
280
|
+
...store.modalProps,
|
|
281
|
+
hidden: true
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
} else {
|
|
285
|
+
await saveFn(files);
|
|
286
|
+
}
|
|
287
|
+
e.target.value = ""; // allow user to select the same file again
|
|
288
|
+
}}
|
|
198
289
|
ref={(ref) => {
|
|
199
290
|
inputRef.current = ref;
|
|
200
291
|
}}
|
|
@@ -206,10 +297,10 @@ function Upload({
|
|
|
206
297
|
</ThemedButton>
|
|
207
298
|
) : (
|
|
208
299
|
<FileUploadWrapper
|
|
209
|
-
choosen={files !== null}
|
|
210
300
|
data-disabled={disabled}
|
|
211
301
|
onClick={handleChooseFile}
|
|
212
302
|
error={errorMessage}
|
|
303
|
+
style={style}
|
|
213
304
|
>
|
|
214
305
|
{isLoading ? (
|
|
215
306
|
<Loading size={2} />
|
|
@@ -220,17 +311,22 @@ function Upload({
|
|
|
220
311
|
{isVideoOnly ? (
|
|
221
312
|
<VideoPreview
|
|
222
313
|
src={
|
|
223
|
-
"
|
|
224
|
-
|
|
225
|
-
"data:
|
|
226
|
-
|
|
314
|
+
preview?.startsWith("http")
|
|
315
|
+
? preview
|
|
316
|
+
: "data:video/mp4;base64," +
|
|
317
|
+
preview?.substring(
|
|
318
|
+
"data:application/octet-stream;base64,".length
|
|
319
|
+
)
|
|
227
320
|
}
|
|
228
321
|
autoPlay
|
|
229
322
|
muted
|
|
230
323
|
loop
|
|
231
324
|
/>
|
|
232
325
|
) : (
|
|
233
|
-
<ImagePreview
|
|
326
|
+
<ImagePreview
|
|
327
|
+
style={{ ...imgPreviewStyle }}
|
|
328
|
+
src={preview}
|
|
329
|
+
/>
|
|
234
330
|
)}
|
|
235
331
|
</>
|
|
236
332
|
) : isVideoOnly ? (
|
|
@@ -248,7 +344,7 @@ function Upload({
|
|
|
248
344
|
</FileUploadWrapper>
|
|
249
345
|
)}
|
|
250
346
|
{!disabled && field.value && field.value?.length !== 0 && preview && (
|
|
251
|
-
<div onClick={handleRemoveAllFiles} data-remove>
|
|
347
|
+
<div onClick={handleRemoveAllFiles} data-remove style={style}>
|
|
252
348
|
<Trash size={24} color={colors.white} />
|
|
253
349
|
</div>
|
|
254
350
|
)}
|
|
@@ -17,11 +17,13 @@ export const SUPPORTED_FORMATS = [
|
|
|
17
17
|
"image/jpg",
|
|
18
18
|
"image/jpeg",
|
|
19
19
|
"image/gif",
|
|
20
|
-
"image/png"
|
|
20
|
+
"image/png",
|
|
21
|
+
"image/webp"
|
|
21
22
|
];
|
|
22
|
-
|
|
23
23
|
export interface WithUploadToIpfsProps {
|
|
24
|
-
saveToIpfs: (
|
|
24
|
+
saveToIpfs: (
|
|
25
|
+
files: File[] | null
|
|
26
|
+
) => Promise<false | FileProps[] | undefined>;
|
|
25
27
|
loadMedia: (src: string) => string;
|
|
26
28
|
removeFile: (src: string) => void;
|
|
27
29
|
}
|
|
@@ -32,16 +34,16 @@ export function WithUploadToIpfs<P extends WithUploadToIpfsProps>(
|
|
|
32
34
|
props: Omit<P & UploadProps, keyof WithUploadToIpfsProps>
|
|
33
35
|
) => {
|
|
34
36
|
const withUpload = props?.withUpload || false;
|
|
35
|
-
|
|
37
|
+
const accept: string = props.accept
|
|
38
|
+
? props.accept
|
|
39
|
+
: SUPPORTED_FORMATS.join(",");
|
|
36
40
|
const { saveFile, loadMedia, removeFile } = useSaveImageToIpfs();
|
|
37
41
|
|
|
38
|
-
const saveToIpfs = useCallback(
|
|
39
|
-
async (
|
|
40
|
-
if (!
|
|
42
|
+
const saveToIpfs: WithUploadToIpfsProps["saveToIpfs"] = useCallback(
|
|
43
|
+
async (filesArray: File[] | null) => {
|
|
44
|
+
if (!filesArray) {
|
|
41
45
|
return;
|
|
42
46
|
}
|
|
43
|
-
const { files } = e.target;
|
|
44
|
-
const filesArray = Object.values(files);
|
|
45
47
|
const filesErrors: string[] = [];
|
|
46
48
|
|
|
47
49
|
for (const file of filesArray) {
|
|
@@ -105,12 +107,12 @@ export function WithUploadToIpfs<P extends WithUploadToIpfsProps>(
|
|
|
105
107
|
const newProps = useMemo(
|
|
106
108
|
() => ({
|
|
107
109
|
maxSize: MAX_FILE_SIZE,
|
|
108
|
-
|
|
110
|
+
accept,
|
|
109
111
|
saveToIpfs,
|
|
110
112
|
loadMedia,
|
|
111
113
|
removeFile
|
|
112
114
|
}),
|
|
113
|
-
[saveToIpfs, loadMedia, removeFile]
|
|
115
|
+
[saveToIpfs, loadMedia, removeFile, accept]
|
|
114
116
|
);
|
|
115
117
|
|
|
116
118
|
if (withUpload) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { default as Checkbox } from "./Checkbox";
|
|
2
2
|
export { default as Datepicker } from "./Datepicker";
|
|
3
3
|
export { default as Error } from "./Error";
|
|
4
|
-
export {
|
|
4
|
+
export { FormField } from "./FormField";
|
|
5
5
|
export * from "./BaseInput";
|
|
6
6
|
export { default as Input, InputProps } from "./Input";
|
|
7
7
|
export { default as Phone } from "./Phone";
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
1
2
|
import { SingleValue } from "react-select";
|
|
3
|
+
import { CSSProperties } from "styled-components";
|
|
4
|
+
import { ImageEditorModalProps } from "./Upload/ImageEditorModal/ImageEditorModal";
|
|
2
5
|
import type { TextAreaTheme } from "./Field.styles";
|
|
3
6
|
|
|
4
7
|
export interface BaseProps {
|
|
@@ -29,12 +32,13 @@ export interface ErrorProps {
|
|
|
29
32
|
|
|
30
33
|
export interface FormFieldProps {
|
|
31
34
|
title: string;
|
|
35
|
+
titleIcon?: ReactNode;
|
|
32
36
|
subTitle?: string | false;
|
|
33
37
|
required?: boolean;
|
|
34
38
|
tooltip?: string;
|
|
35
39
|
children: React.ReactNode | string;
|
|
36
40
|
style?: React.CSSProperties;
|
|
37
|
-
|
|
41
|
+
copyIconColor?: CSSProperties["backgroundColor"];
|
|
38
42
|
valueToCopy?:
|
|
39
43
|
| string
|
|
40
44
|
| {
|
|
@@ -87,7 +91,7 @@ export interface SelectProps extends BaseProps {
|
|
|
87
91
|
label?: string;
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
export
|
|
94
|
+
export type UploadProps = BaseProps & {
|
|
91
95
|
accept?: string;
|
|
92
96
|
multiple?: boolean;
|
|
93
97
|
trigger?: React.ReactNode | JSX.Element;
|
|
@@ -98,7 +102,18 @@ export interface UploadProps extends BaseProps {
|
|
|
98
102
|
onLoadSinglePreviewImage?: (base64Uri: string) => void;
|
|
99
103
|
withUpload?: boolean;
|
|
100
104
|
onLoading?: (loading: boolean) => void;
|
|
101
|
-
|
|
105
|
+
borderRadius?: number;
|
|
106
|
+
width?: number;
|
|
107
|
+
height?: number;
|
|
108
|
+
imgPreviewStyle?: Pick<CSSProperties, "objectFit">;
|
|
109
|
+
} & (
|
|
110
|
+
| {
|
|
111
|
+
withEditor: true;
|
|
112
|
+
saveButtonTheme: ImageEditorModalProps["saveButtonTheme"];
|
|
113
|
+
}
|
|
114
|
+
| { withEditor: false; saveButtonTheme: undefined }
|
|
115
|
+
);
|
|
116
|
+
|
|
102
117
|
export interface FileProps {
|
|
103
118
|
src: string;
|
|
104
119
|
name?: string; // for example: "redeemeum.png"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ImageEditorModal } from "../form/Upload/ImageEditorModal/ImageEditorModal";
|
|
1
2
|
import { MODAL_TYPES } from "./ModalTypes";
|
|
2
3
|
import FinanceDeposit from "./components/SellerFinance/FinanceDeposit";
|
|
3
4
|
import FinanceWithdraw from "./components/SellerFinance/FinanceWithdraw";
|
|
@@ -10,5 +11,6 @@ export const MODAL_COMPONENTS = {
|
|
|
10
11
|
[MODAL_TYPES.FINANCE_WITHDRAW_MODAL]: FinanceWithdraw,
|
|
11
12
|
[MODAL_TYPES.TRANSACTION_FAILED]: TransactionFailedModal,
|
|
12
13
|
[MODAL_TYPES.TRANSACTION_SUBMITTED]: TransactionSubmittedModal,
|
|
13
|
-
[MODAL_TYPES.WAITING_FOR_CONFIRMATION]: WaitingForConfirmationModal
|
|
14
|
+
[MODAL_TYPES.WAITING_FOR_CONFIRMATION]: WaitingForConfirmationModal,
|
|
15
|
+
[MODAL_TYPES.IMAGE_EDITOR]: ImageEditorModal
|
|
14
16
|
} as const;
|
|
@@ -12,6 +12,7 @@ export type ModalProps = {
|
|
|
12
12
|
contentStyle?: CSSProperties;
|
|
13
13
|
closable?: boolean;
|
|
14
14
|
onClose?: (data: unknown | undefined | null) => void;
|
|
15
|
+
hidden?: boolean;
|
|
15
16
|
};
|
|
16
17
|
export type ModalType = keyof typeof MODAL_TYPES | null;
|
|
17
18
|
type ModalSize = "xxs" | "xs" | "s" | "m" | "l" | "xl";
|
|
@@ -25,9 +26,9 @@ export type Store = {
|
|
|
25
26
|
theme?: "light" | "dark";
|
|
26
27
|
};
|
|
27
28
|
export type GenericModalProps<T extends keyof typeof MODAL_TYPES> =
|
|
28
|
-
Parameters<(typeof MODAL_COMPONENTS)[T]>
|
|
29
|
-
? ModalProps &
|
|
30
|
-
: ModalProps
|
|
29
|
+
Parameters<(typeof MODAL_COMPONENTS)[T]> extends [infer P, ...any[]]
|
|
30
|
+
? ModalProps & P
|
|
31
|
+
: ModalProps;
|
|
31
32
|
|
|
32
33
|
export interface ModalContextType {
|
|
33
34
|
showModal: <T extends keyof typeof MODAL_TYPES>(
|
|
@@ -3,5 +3,6 @@ export const MODAL_TYPES = {
|
|
|
3
3
|
FINANCE_WITHDRAW_MODAL: "FINANCE_WITHDRAW_MODAL",
|
|
4
4
|
TRANSACTION_FAILED: "TRANSACTION_FAILED",
|
|
5
5
|
TRANSACTION_SUBMITTED: "TRANSACTION_SUBMITTED",
|
|
6
|
-
WAITING_FOR_CONFIRMATION: "WAITING_FOR_CONFIRMATION"
|
|
6
|
+
WAITING_FOR_CONFIRMATION: "WAITING_FOR_CONFIRMATION",
|
|
7
|
+
IMAGE_EDITOR: "IMAGE_EDITOR"
|
|
7
8
|
} as const;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useQuery } from "react-query";
|
|
2
|
+
import { loadAndSetImagePromise } from "../../lib/base64/base64";
|
|
3
|
+
|
|
4
|
+
type UseFileImageProps = {
|
|
5
|
+
file: File | undefined;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function useFileImage(
|
|
9
|
+
{ file }: UseFileImageProps,
|
|
10
|
+
options: { enabled: boolean }
|
|
11
|
+
) {
|
|
12
|
+
return useQuery(
|
|
13
|
+
["useFileImage", file],
|
|
14
|
+
async () => {
|
|
15
|
+
if (!file) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
return await loadAndSetImagePromise(file);
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
enabled: !!file && options.enabled
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useQuery } from "react-query";
|
|
2
|
+
import { fetchImageAsBase64 } from "../../lib/base64/base64";
|
|
3
|
+
import { getImageMetadata } from "../../lib/images/images";
|
|
4
|
+
|
|
5
|
+
type UseIpfsImageProps = {
|
|
6
|
+
url: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function useIpfsImage(
|
|
10
|
+
{ url }: UseIpfsImageProps,
|
|
11
|
+
options: { enabled: boolean }
|
|
12
|
+
) {
|
|
13
|
+
return useQuery(
|
|
14
|
+
["useIpfsImage", url],
|
|
15
|
+
async () => {
|
|
16
|
+
const result = await fetchImageAsBase64(url);
|
|
17
|
+
const metadata = await getImageMetadata(result.base64);
|
|
18
|
+
return {
|
|
19
|
+
...result,
|
|
20
|
+
...metadata
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
enabled: options.enabled
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
}
|
package/src/lib/base64/base64.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { IpfsMetadataStorage } from "@bosonprotocol/ipfs-storage";
|
|
|
3
3
|
export async function fetchImageAsBase64(imageUrl: string) {
|
|
4
4
|
const response = await fetch(imageUrl);
|
|
5
5
|
const blob = await response.blob();
|
|
6
|
-
return blobToBase64(blob);
|
|
6
|
+
return { base64: await blobToBase64(blob), blob };
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function fromBase64ToBinary(base64: string): Buffer {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { fn } from "@storybook/test";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Meta } from "@storybook/react";
|
|
4
|
+
import { Upload } from "../..";
|
|
5
|
+
import { EnvironmentProvider } from "../../components/environment/EnvironmentProvider";
|
|
6
|
+
import { IpfsProvider } from "../../components/ipfs/IpfsProvider";
|
|
7
|
+
import { Formik } from "formik";
|
|
8
|
+
import { QueryClientProviderCustom } from "../../components/queryClient/withQueryClientProvider";
|
|
9
|
+
import {
|
|
10
|
+
bosonButtonThemeKeys,
|
|
11
|
+
bosonButtonThemes
|
|
12
|
+
} from "../../components/ui/ThemedButton";
|
|
13
|
+
const name = "upload";
|
|
14
|
+
|
|
15
|
+
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
|
16
|
+
export default {
|
|
17
|
+
title: "Visual Components/Buttons/Upload",
|
|
18
|
+
component: Upload,
|
|
19
|
+
parameters: {
|
|
20
|
+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
|
21
|
+
layout: "centered"
|
|
22
|
+
},
|
|
23
|
+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
// args: { onClick: fn() },
|
|
26
|
+
argTypes: {
|
|
27
|
+
name: {
|
|
28
|
+
table: {
|
|
29
|
+
disabled: true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
accept: {
|
|
33
|
+
control: "select",
|
|
34
|
+
options: ["image/*", "video/*", "image/*,video/*"]
|
|
35
|
+
},
|
|
36
|
+
disabled: { control: "boolean" },
|
|
37
|
+
withEditor: { control: "boolean" },
|
|
38
|
+
// @ts-expect-error saveButtonThemeKey is not a valid prop name of Upload but saveButtonTheme is so we get the theme from the key
|
|
39
|
+
saveButtonThemeKey: {
|
|
40
|
+
control: "select",
|
|
41
|
+
options: bosonButtonThemeKeys
|
|
42
|
+
},
|
|
43
|
+
placeholder: { control: "text" },
|
|
44
|
+
width: { control: "number" },
|
|
45
|
+
height: { control: "number" },
|
|
46
|
+
borderRadius: { control: "number" }
|
|
47
|
+
},
|
|
48
|
+
decorators: [
|
|
49
|
+
(Story, { args }) => {
|
|
50
|
+
return (
|
|
51
|
+
<QueryClientProviderCustom>
|
|
52
|
+
<EnvironmentProvider configId="testing-80002-0" envName="testing">
|
|
53
|
+
<IpfsProvider>
|
|
54
|
+
<Formik initialValues={{ [name]: [] }} onSubmit={console.log}>
|
|
55
|
+
<Story
|
|
56
|
+
args={{
|
|
57
|
+
...args,
|
|
58
|
+
saveButtonTheme: bosonButtonThemes({
|
|
59
|
+
withBosonStyle: false
|
|
60
|
+
// @ts-expect-error saveButtonThemeKey is not a valid prop name of Upload but saveButtonTheme is so we get the theme from the key
|
|
61
|
+
})[args.saveButtonThemeKey]
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
</Formik>
|
|
65
|
+
</IpfsProvider>
|
|
66
|
+
</EnvironmentProvider>
|
|
67
|
+
</QueryClientProviderCustom>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
} satisfies Meta<typeof Upload>;
|
|
72
|
+
|
|
73
|
+
const BASE_ARGS = {
|
|
74
|
+
name
|
|
75
|
+
} as const;
|
|
76
|
+
|
|
77
|
+
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
|
78
|
+
export const Base = {
|
|
79
|
+
args: {
|
|
80
|
+
...BASE_ARGS
|
|
81
|
+
}
|
|
82
|
+
};
|