@finema/core 3.22.0 → 3.23.2
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/module.d.mts +2 -0
- package/dist/module.json +2 -2
- package/dist/module.mjs +16 -2
- package/dist/runtime/components/App.vue +1 -1
- package/dist/runtime/components/DevToolsWindow/index.vue +1 -1
- package/dist/runtime/components/Dialog/index.d.vue.ts +1 -4
- package/dist/runtime/components/Dialog/index.vue +9 -10
- package/dist/runtime/components/Dialog/index.vue.d.ts +1 -4
- package/dist/runtime/components/Empty.d.vue.ts +0 -1
- package/dist/runtime/components/Empty.vue +6 -2
- package/dist/runtime/components/Empty.vue.d.ts +0 -1
- package/dist/runtime/components/FlexDeck/index.vue +86 -81
- package/dist/runtime/components/Form/FieldWrapper.vue +14 -14
- package/dist/runtime/components/Form/Fields.vue +10 -10
- package/dist/runtime/components/Form/InputCheckbox/index.vue +20 -19
- package/dist/runtime/components/Form/InputCheckboxGroup/index.vue +2 -1
- package/dist/runtime/components/Form/InputComponent/index.vue +2 -1
- package/dist/runtime/components/Form/InputCurrency/index.vue +51 -50
- package/dist/runtime/components/Form/InputDateTime/date_time_field.types.d.ts +1 -1
- package/dist/runtime/components/Form/InputDateTime/index.vue +69 -64
- package/dist/runtime/components/Form/InputDateTimeRange/date_range_time_field.types.d.ts +1 -1
- package/dist/runtime/components/Form/InputDateTimeRange/index.vue +62 -57
- package/dist/runtime/components/Form/InputMonth/index.vue +10 -5
- package/dist/runtime/components/Form/InputMonth/types.d.ts +1 -1
- package/dist/runtime/components/Form/InputNumber/index.vue +22 -21
- package/dist/runtime/components/Form/InputRadio/index.d.vue.ts +1 -1
- package/dist/runtime/components/Form/InputRadio/index.vue +2 -1
- package/dist/runtime/components/Form/InputRadio/index.vue.d.ts +1 -1
- package/dist/runtime/components/Form/InputRating/index.vue +2 -1
- package/dist/runtime/components/Form/InputSearch/index.vue +7 -2
- package/dist/runtime/components/Form/InputSelect/index.vue +112 -111
- package/dist/runtime/components/Form/InputSelectMultiple/index.vue +120 -119
- package/dist/runtime/components/Form/InputTags/index.vue +56 -55
- package/dist/runtime/components/Form/InputText/index.vue +88 -87
- package/dist/runtime/components/Form/InputTextarea/index.vue +20 -19
- package/dist/runtime/components/Form/InputTime/index.vue +45 -40
- package/dist/runtime/components/Form/InputTime/types.d.ts +1 -1
- package/dist/runtime/components/Form/InputToggle/index.vue +19 -18
- package/dist/runtime/components/Form/InputUploadDropzone/index.d.vue.ts +1 -4
- package/dist/runtime/components/Form/InputUploadDropzone/index.vue +40 -35
- package/dist/runtime/components/Form/InputUploadDropzone/index.vue.d.ts +1 -4
- package/dist/runtime/components/Form/InputUploadDropzone/types.d.ts +2 -2
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.d.vue.ts +0 -5
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +63 -58
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue.d.ts +0 -5
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/types.d.ts +3 -3
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.d.vue.ts +0 -5
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +69 -60
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue.d.ts +0 -5
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/types.d.ts +3 -3
- package/dist/runtime/components/Form/InputUploadImageAuto/index.d.vue.ts +1 -6
- package/dist/runtime/components/Form/InputUploadImageAuto/index.vue +63 -58
- package/dist/runtime/components/Form/InputUploadImageAuto/index.vue.d.ts +1 -6
- package/dist/runtime/components/Form/InputUploadImageAuto/types.d.ts +3 -3
- package/dist/runtime/components/Form/InputWYSIWYG/EditorImageUploadNode.vue +18 -18
- package/dist/runtime/components/Form/InputWYSIWYG/EditorLinkPopover.vue +65 -65
- package/dist/runtime/components/Form/InputWYSIWYG/README.md +96 -96
- package/dist/runtime/components/Form/InputWYSIWYG/index.vue +43 -42
- package/dist/runtime/components/Form/fileState/EmptyState.vue +21 -21
- package/dist/runtime/components/Form/fileState/FailedState.vue +37 -33
- package/dist/runtime/components/Form/fileState/LoadingState.vue +24 -24
- package/dist/runtime/components/Form/fileState/MultipleFilesState.d.vue.ts +4 -4
- package/dist/runtime/components/Form/fileState/MultipleFilesState.vue +79 -75
- package/dist/runtime/components/Form/fileState/MultipleFilesState.vue.d.ts +4 -4
- package/dist/runtime/components/Form/fileState/PreviewModal.vue +23 -23
- package/dist/runtime/components/Form/fileState/SuccessState.d.vue.ts +2 -2
- package/dist/runtime/components/Form/fileState/SuccessState.vue +8 -4
- package/dist/runtime/components/Form/fileState/SuccessState.vue.d.ts +2 -2
- package/dist/runtime/components/Form/fileState/useFilePicker.d.ts +34 -0
- package/dist/runtime/components/Form/fileState/useFilePicker.js +48 -0
- package/dist/runtime/components/Form/fileState/useFileState.d.ts +7 -9
- package/dist/runtime/components/Form/fileState/useFileState.js +40 -120
- package/dist/runtime/components/Form/fileState/useUploadImageState.d.ts +7 -8
- package/dist/runtime/components/Form/fileState/useUploadImageState.js +28 -300
- package/dist/runtime/components/Form/fileState/useUploadState.d.ts +11 -7
- package/dist/runtime/components/Form/fileState/useUploadState.js +58 -131
- package/dist/runtime/components/Form/fileState/useUploadStateMultiple.d.ts +12 -18
- package/dist/runtime/components/Form/fileState/useUploadStateMultiple.js +89 -222
- package/dist/runtime/components/Form/index.vue +5 -5
- package/dist/runtime/components/Form/types.d.ts +2 -0
- package/dist/runtime/components/Image.vue +28 -28
- package/dist/runtime/components/Loader.d.vue.ts +1 -0
- package/dist/runtime/components/Loader.vue.d.ts +1 -0
- package/dist/runtime/components/Table/Base.d.vue.ts +15 -1
- package/dist/runtime/components/Table/Base.vue +118 -118
- package/dist/runtime/components/Table/Base.vue.d.ts +15 -1
- package/dist/runtime/components/Table/ColumnDate.vue +1 -1
- package/dist/runtime/components/Table/ColumnDateTime.vue +1 -1
- package/dist/runtime/components/Table/ColumnImage.vue +4 -4
- package/dist/runtime/components/Table/ColumnText.d.vue.ts +2 -3
- package/dist/runtime/components/Table/ColumnText.vue +11 -11
- package/dist/runtime/components/Table/ColumnText.vue.d.ts +2 -3
- package/dist/runtime/components/Table/Pagination.vue +70 -67
- package/dist/runtime/components/Table/Simple.vue +19 -19
- package/dist/runtime/components/Table/index.d.vue.ts +1 -1
- package/dist/runtime/components/Table/index.vue +37 -33
- package/dist/runtime/components/Table/index.vue.d.ts +1 -1
- package/dist/runtime/composables/loaderList.d.ts +2 -1
- package/dist/runtime/composables/loaderList.js +2 -1
- package/dist/runtime/composables/loaderObject.d.ts +2 -1
- package/dist/runtime/composables/loaderObject.js +2 -1
- package/dist/runtime/composables/loaderPage.js +194 -344
- package/dist/runtime/composables/useConfig.js +4 -3
- package/dist/runtime/composables/useDialog.js +5 -1
- package/dist/runtime/composables/useForm.d.ts +1 -1
- package/dist/runtime/composables/useForm.js +1 -1
- package/dist/runtime/composables/useMessages.d.ts +10 -0
- package/dist/runtime/composables/useMessages.js +10 -0
- package/dist/runtime/helpers/apiPageHelper.d.ts +0 -1
- package/dist/runtime/helpers/uploadCore.d.ts +54 -0
- package/dist/runtime/helpers/uploadCore.js +84 -0
- package/dist/runtime/i18n/valibot.d.ts +5 -68
- package/dist/runtime/i18n/valibot.js +33 -29
- package/dist/runtime/locale/en.d.ts +2 -0
- package/dist/runtime/locale/en.js +42 -0
- package/dist/runtime/locale/index.d.ts +7 -0
- package/dist/runtime/locale/index.js +8 -0
- package/dist/runtime/locale/th.d.ts +43 -0
- package/dist/runtime/locale/th.js +42 -0
- package/dist/runtime/server/tsconfig.json +3 -3
- package/dist/runtime/utils/ParamHelper.js +1 -1
- package/dist/runtime/utils/StringHelper.js +1 -4
- package/dist/runtime/utils/TimeHelper.js +2 -2
- package/dist/runtime/utils/lodash.js +2 -2
- package/package.json +20 -12
|
@@ -1,306 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
UploadState2["ERROR"] = "error";
|
|
14
|
-
return UploadState2;
|
|
15
|
-
})(UploadState || {});
|
|
16
|
-
export const useUploadImageState = (props, emits, onChange, setErrors, value, acceptedFileTypes, wrapperProps, dropzoneRef) => {
|
|
17
|
-
const overlay = useOverlay();
|
|
18
|
-
const previewModal = overlay.create(PreviewModal);
|
|
19
|
-
const selectedFile = ref();
|
|
20
|
-
const fileAllocate = useFileAllocate(selectedFile, props);
|
|
21
|
-
const appConfig = useAppConfig();
|
|
22
|
-
const {
|
|
23
|
-
percent,
|
|
24
|
-
onDownloadProgress,
|
|
25
|
-
onUploadProgress
|
|
26
|
-
} = useFileProgress();
|
|
27
|
-
const request = {
|
|
28
|
-
requestOptions: {
|
|
29
|
-
...props.requestOptions,
|
|
30
|
-
onDownloadProgress,
|
|
31
|
-
onUploadProgress
|
|
32
|
-
},
|
|
33
|
-
pathURL: props.uploadPathURL
|
|
34
|
-
};
|
|
35
|
-
const upload = useUploadLoader(request);
|
|
36
|
-
const validateImageDimensions = (file) => {
|
|
37
|
-
return new Promise((resolve) => {
|
|
38
|
-
if (!props.dimensions) {
|
|
39
|
-
resolve(true);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const img = new Image();
|
|
43
|
-
const url = URL.createObjectURL(file);
|
|
44
|
-
img.onload = () => {
|
|
45
|
-
URL.revokeObjectURL(url);
|
|
46
|
-
const {
|
|
47
|
-
width,
|
|
48
|
-
height
|
|
49
|
-
} = img;
|
|
50
|
-
const dimensions = props.dimensions;
|
|
51
|
-
if (dimensions.width !== void 0 && width !== dimensions.width) {
|
|
52
|
-
if (appConfig.core?.locale === "th") {
|
|
53
|
-
setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E01\u0E27\u0E49\u0E32\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 ${dimensions.width}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${width}px)`);
|
|
54
|
-
} else {
|
|
55
|
-
setErrors(`Image width must be ${dimensions.width}px (current: ${width}px)`);
|
|
56
|
-
}
|
|
57
|
-
resolve(false);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (dimensions.height !== void 0 && height !== dimensions.height) {
|
|
61
|
-
if (appConfig.core?.locale === "th") {
|
|
62
|
-
setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E39\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 ${dimensions.height}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${height}px)`);
|
|
63
|
-
} else {
|
|
64
|
-
setErrors(`Image height must be ${dimensions.height}px (current: ${height}px)`);
|
|
65
|
-
}
|
|
66
|
-
resolve(false);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
if (dimensions.minWidth !== void 0 && width < dimensions.minWidth) {
|
|
70
|
-
if (appConfig.core?.locale === "th") {
|
|
71
|
-
setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E01\u0E27\u0E49\u0E32\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32 ${dimensions.minWidth}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${width}px)`);
|
|
72
|
-
} else {
|
|
73
|
-
setErrors(`Image width must be at least ${dimensions.minWidth}px (current: ${width}px)`);
|
|
74
|
-
}
|
|
75
|
-
resolve(false);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (dimensions.minHeight !== void 0 && height < dimensions.minHeight) {
|
|
79
|
-
if (appConfig.core?.locale === "th") {
|
|
80
|
-
setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E39\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32 ${dimensions.minHeight}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${height}px)`);
|
|
81
|
-
} else {
|
|
82
|
-
setErrors(`Image height must be at least ${dimensions.minHeight}px (current: ${height}px)`);
|
|
83
|
-
}
|
|
84
|
-
resolve(false);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (dimensions.maxWidth !== void 0 && width > dimensions.maxWidth) {
|
|
88
|
-
if (appConfig.core?.locale === "th") {
|
|
89
|
-
setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E01\u0E27\u0E49\u0E32\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${dimensions.maxWidth}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${width}px)`);
|
|
90
|
-
} else {
|
|
91
|
-
setErrors(`Image width must not exceed ${dimensions.maxWidth}px (current: ${width}px)`);
|
|
92
|
-
}
|
|
93
|
-
resolve(false);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (dimensions.maxHeight !== void 0 && height > dimensions.maxHeight) {
|
|
97
|
-
if (appConfig.core?.locale === "th") {
|
|
98
|
-
setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E39\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${dimensions.maxHeight}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${height}px)`);
|
|
99
|
-
} else {
|
|
100
|
-
setErrors(`Image height must not exceed ${dimensions.maxHeight}px (current: ${height}px)`);
|
|
101
|
-
}
|
|
102
|
-
resolve(false);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
if (dimensions.aspectRatio !== void 0) {
|
|
106
|
-
const actualRatio = width / height;
|
|
107
|
-
const tolerance = dimensions.aspectRatioTolerance ?? 0.01;
|
|
108
|
-
const expectedRatio = dimensions.aspectRatio;
|
|
109
|
-
if (Math.abs(actualRatio - expectedRatio) > tolerance) {
|
|
110
|
-
if (appConfig.core?.locale === "th") {
|
|
111
|
-
setErrors(`\u0E2D\u0E31\u0E15\u0E23\u0E32\u0E2A\u0E48\u0E27\u0E19\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 (\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23: ${expectedRatio.toFixed(2)}, \u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${actualRatio.toFixed(2)})`);
|
|
112
|
-
} else {
|
|
113
|
-
setErrors(`Image aspect ratio is incorrect (expected: ${expectedRatio.toFixed(2)}, current: ${actualRatio.toFixed(2)})`);
|
|
114
|
-
}
|
|
115
|
-
resolve(false);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
setErrors("");
|
|
120
|
-
resolve(true);
|
|
121
|
-
};
|
|
122
|
-
img.onerror = () => {
|
|
123
|
-
URL.revokeObjectURL(url);
|
|
124
|
-
if (appConfig.core?.locale === "th") {
|
|
125
|
-
setErrors("\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E42\u0E2B\u0E25\u0E14\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E44\u0E14\u0E49");
|
|
126
|
-
} else {
|
|
127
|
-
setErrors("Failed to load image");
|
|
128
|
-
}
|
|
129
|
-
resolve(false);
|
|
130
|
-
};
|
|
131
|
-
img.src = url;
|
|
132
|
-
});
|
|
133
|
-
};
|
|
134
|
-
const validateFile = async (file) => {
|
|
135
|
-
if (props.accept && fileAllocate.acceptFile.value) {
|
|
136
|
-
const acceptedTypes = fileAllocate.acceptFile.value;
|
|
137
|
-
const acceptedTypesList = acceptedTypes.split(",").map((type) => type.trim());
|
|
138
|
-
const fileExtension = file.name.toLowerCase().split(".").pop();
|
|
139
|
-
const isValidFileType = acceptedTypesList.some((acceptedType) => {
|
|
140
|
-
if (acceptedType.startsWith(".")) {
|
|
141
|
-
const extension = acceptedType.slice(1).toLowerCase();
|
|
142
|
-
return fileExtension === extension;
|
|
143
|
-
} else if (!acceptedType.includes("/") && !acceptedType.includes("*")) {
|
|
144
|
-
return fileExtension === acceptedType.toLowerCase();
|
|
145
|
-
}
|
|
146
|
-
if (acceptedType.endsWith("/*")) {
|
|
147
|
-
const baseType = acceptedType.slice(0, -2);
|
|
148
|
-
return file.type.startsWith(baseType + "/");
|
|
149
|
-
}
|
|
150
|
-
return file.type === acceptedType;
|
|
151
|
-
});
|
|
152
|
-
if (!isValidFileType) {
|
|
153
|
-
if (appConfig.core?.locale === "th") {
|
|
154
|
-
setErrors("\u0E1B\u0E23\u0E30\u0E40\u0E20\u0E17\u0E44\u0E1F\u0E25\u0E4C\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 (\u0E23\u0E2D\u0E07\u0E23\u0E31\u0E1A\u0E40\u0E09\u0E1E\u0E32\u0E30 " + acceptedTypesList.join(", ") + ")");
|
|
155
|
-
} else {
|
|
156
|
-
setErrors("Invalid file type (only " + acceptedTypesList.join(", ") + " are allowed)");
|
|
157
|
-
}
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (props.maxSize) {
|
|
162
|
-
const maxSizeBytes = (fileAllocate.acceptFileSizeKb.value || 0) * 1024;
|
|
163
|
-
if (file.size > maxSizeBytes) {
|
|
164
|
-
if (fileAllocate.isAcceptFileUseMb.value) {
|
|
165
|
-
if (appConfig.core?.locale === "th") {
|
|
166
|
-
setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeMb.value} MB`);
|
|
167
|
-
} else {
|
|
168
|
-
setErrors(`File size must not exceed ${fileAllocate.acceptFileSizeMb.value} MB`);
|
|
169
|
-
}
|
|
170
|
-
} else {
|
|
171
|
-
if (appConfig.core?.locale === "th") {
|
|
172
|
-
setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeKb.value} KB`);
|
|
173
|
-
} else {
|
|
174
|
-
setErrors(`File size must not exceed ${fileAllocate.acceptFileSizeKb.value} KB`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const isDimensionsValid = await validateImageDimensions(file);
|
|
181
|
-
if (!isDimensionsValid) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
setErrors("");
|
|
185
|
-
return true;
|
|
186
|
-
};
|
|
187
|
-
const processFile = async (file) => {
|
|
188
|
-
const isValid = await validateFile(file);
|
|
189
|
-
if (!isValid) return;
|
|
190
|
-
selectedFile.value = file;
|
|
191
|
-
emits("change", file);
|
|
192
|
-
const formData = new FormData();
|
|
193
|
-
formData.append(props.bodyKey, file);
|
|
194
|
-
upload.run({
|
|
195
|
-
data: formData
|
|
1
|
+
import { UploadState, useUploadState } from "./useUploadState.js";
|
|
2
|
+
import { validateDimensions } from "#core/helpers/uploadCore";
|
|
3
|
+
import { useCoreMessages } from "#core/composables/useMessages";
|
|
4
|
+
export { UploadState };
|
|
5
|
+
const readImageSize = (file) => new Promise((resolve) => {
|
|
6
|
+
const image = new Image();
|
|
7
|
+
const url = URL.createObjectURL(file);
|
|
8
|
+
image.onload = () => {
|
|
9
|
+
URL.revokeObjectURL(url);
|
|
10
|
+
resolve({
|
|
11
|
+
width: image.width,
|
|
12
|
+
height: image.height
|
|
196
13
|
});
|
|
197
14
|
};
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (file) {
|
|
202
|
-
processFile(file);
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
const fileDialog = useFileDialog({
|
|
206
|
-
accept: acceptedFileTypes.value || "image/*",
|
|
207
|
-
directory: false,
|
|
208
|
-
multiple: false
|
|
209
|
-
});
|
|
210
|
-
const dropzone = useDropZone(dropzoneRef, {
|
|
211
|
-
onDrop: handleFileDrop,
|
|
212
|
-
multiple: false,
|
|
213
|
-
preventDefaultForUnhandled: false
|
|
214
|
-
});
|
|
215
|
-
const currentState = computed(() => {
|
|
216
|
-
if (value.value) return "success" /* SUCCESS */;
|
|
217
|
-
if (selectedFile.value && upload.status.value.isLoading) return "uploading" /* UPLOADING */;
|
|
218
|
-
if (selectedFile.value && upload.status.value.isError) return "error" /* ERROR */;
|
|
219
|
-
return "empty" /* EMPTY */;
|
|
220
|
-
});
|
|
221
|
-
const isEmpty = computed(() => currentState.value === "empty" /* EMPTY */);
|
|
222
|
-
const isUploading = computed(() => currentState.value === "uploading" /* UPLOADING */);
|
|
223
|
-
const isSuccess = computed(() => currentState.value === "success" /* SUCCESS */);
|
|
224
|
-
const isError = computed(() => currentState.value === "error" /* ERROR */);
|
|
225
|
-
const handleInputChange = (event) => {
|
|
226
|
-
if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
|
|
227
|
-
const file = event.target.files?.[0];
|
|
228
|
-
if (file) {
|
|
229
|
-
processFile(file);
|
|
230
|
-
}
|
|
15
|
+
image.onerror = () => {
|
|
16
|
+
URL.revokeObjectURL(url);
|
|
17
|
+
resolve(void 0);
|
|
231
18
|
};
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
19
|
+
image.src = url;
|
|
20
|
+
});
|
|
21
|
+
export const useUploadImageState = (context) => {
|
|
22
|
+
const {
|
|
23
|
+
messages
|
|
24
|
+
} = useCoreMessages();
|
|
25
|
+
return useUploadState(context, {
|
|
26
|
+
defaultAccept: "image/*",
|
|
27
|
+
validateExtra: async (file) => {
|
|
28
|
+
if (!context.props.dimensions) return;
|
|
29
|
+
const size = await readImageSize(file);
|
|
30
|
+
if (!size) return messages.value.upload.imageLoadFailed;
|
|
31
|
+
return validateDimensions(size, context.props.dimensions, messages.value.upload);
|
|
236
32
|
}
|
|
237
33
|
});
|
|
238
|
-
const handleOpenFile = () => {
|
|
239
|
-
if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
|
|
240
|
-
fileDialog.open();
|
|
241
|
-
};
|
|
242
|
-
const handleDeleteFile = () => {
|
|
243
|
-
fileDialog.reset();
|
|
244
|
-
upload.clear();
|
|
245
|
-
selectedFile.value = void 0;
|
|
246
|
-
onChange(void 0);
|
|
247
|
-
emits("delete");
|
|
248
|
-
};
|
|
249
|
-
const handleRetryUpload = () => {
|
|
250
|
-
if (selectedFile.value) {
|
|
251
|
-
const formData = new FormData();
|
|
252
|
-
formData.append(props.bodyKey, selectedFile.value);
|
|
253
|
-
upload.run(formData);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
const handlePreview = () => {
|
|
257
|
-
previewModal.open({
|
|
258
|
-
value: value.value
|
|
259
|
-
});
|
|
260
|
-
};
|
|
261
|
-
useWatchTrue(
|
|
262
|
-
() => upload.status.value.isSuccess,
|
|
263
|
-
() => {
|
|
264
|
-
if (upload.data.value) {
|
|
265
|
-
const fileValue = {
|
|
266
|
-
url: _get(upload.data.value, props.responseURL),
|
|
267
|
-
path: _get(upload.data.value, props.responsePath),
|
|
268
|
-
name: _get(upload.data.value, props.responseName) || selectedFile.value?.name,
|
|
269
|
-
size: Number(_get(upload.data.value, props.responseSize) || selectedFile.value?.size),
|
|
270
|
-
id: _get(upload.data.value, props.responseID)
|
|
271
|
-
};
|
|
272
|
-
value.value = fileValue;
|
|
273
|
-
emits("success", fileValue);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
);
|
|
277
|
-
useWatchTrue(
|
|
278
|
-
() => upload.status.value.isError,
|
|
279
|
-
() => {
|
|
280
|
-
if (appConfig.core?.locale === "th") {
|
|
281
|
-
setErrors("\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14: " + StringHelper.getError(upload.status.value.errorData));
|
|
282
|
-
} else {
|
|
283
|
-
setErrors("An error occurred: " + StringHelper.getError(upload.status.value.errorData));
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
);
|
|
287
|
-
return {
|
|
288
|
-
// State
|
|
289
|
-
currentState,
|
|
290
|
-
isEmpty,
|
|
291
|
-
isUploading,
|
|
292
|
-
isSuccess,
|
|
293
|
-
isError,
|
|
294
|
-
selectedFile,
|
|
295
|
-
// Upload utilities
|
|
296
|
-
upload,
|
|
297
|
-
dropzone,
|
|
298
|
-
percent,
|
|
299
|
-
// Handlers
|
|
300
|
-
handleInputChange,
|
|
301
|
-
handleOpenFile,
|
|
302
|
-
handleDeleteFile,
|
|
303
|
-
handleRetryUpload,
|
|
304
|
-
handlePreview
|
|
305
|
-
};
|
|
306
34
|
};
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import type { TemplateRef } from 'vue';
|
|
2
1
|
import type { IUploadDropzoneAutoProps } from '../InputUploadDropzoneAuto/types.js';
|
|
2
|
+
import { type IUploadFieldContext } from './useFilePicker.js';
|
|
3
|
+
import { UploadState } from '#core/helpers/uploadCore';
|
|
3
4
|
import type { IFileValue } from '#core/components/Form/types';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export { UploadState };
|
|
6
|
+
interface IUploadStateOptions {
|
|
7
|
+
defaultAccept?: string;
|
|
8
|
+
/** Extra check after type and size pass; resolves to an error message, or undefined when the file is fine */
|
|
9
|
+
validateExtra?: (file: File) => Promise<string | undefined>;
|
|
9
10
|
}
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Uploads the picked file right away and stores the file reference returned by the API as the field value
|
|
13
|
+
*/
|
|
14
|
+
export declare const useUploadState: (context: IUploadFieldContext<IUploadDropzoneAutoProps, IFileValue>, options?: IUploadStateOptions) => {
|
|
11
15
|
currentState: import("vue").ComputedRef<UploadState>;
|
|
12
16
|
isEmpty: import("vue").ComputedRef<boolean>;
|
|
13
17
|
isUploading: import("vue").ComputedRef<boolean>;
|
|
@@ -1,167 +1,94 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
1
|
+
import { useFilePicker } from "./useFilePicker.js";
|
|
2
|
+
import { toFileValue, toUploadFormData, UploadState, validateFile } from "#core/helpers/uploadCore";
|
|
3
|
+
import { useWatchTrue } from "#core/composables/useWatch";
|
|
4
|
+
import { useCoreMessages } from "#core/composables/useMessages";
|
|
5
5
|
import { useUploadLoader } from "#core/composables/useUpload";
|
|
6
|
-
import {
|
|
6
|
+
import { useFileProgress } from "#core/helpers/componentHelper";
|
|
7
7
|
import { StringHelper } from "#core/utils/StringHelper";
|
|
8
|
-
import {
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
8
|
+
import { computed, ref } from "#imports";
|
|
9
|
+
export { UploadState };
|
|
10
|
+
export const useUploadState = (context, options = {}) => {
|
|
11
|
+
const {
|
|
12
|
+
props,
|
|
13
|
+
emits,
|
|
14
|
+
onChange,
|
|
15
|
+
setErrors,
|
|
16
|
+
value
|
|
17
|
+
} = context;
|
|
18
|
+
const {
|
|
19
|
+
messages,
|
|
20
|
+
format
|
|
21
|
+
} = useCoreMessages();
|
|
19
22
|
const selectedFile = ref();
|
|
20
|
-
const fileAllocate = useFileAllocate(selectedFile, props);
|
|
21
23
|
const {
|
|
22
24
|
percent,
|
|
23
25
|
onDownloadProgress,
|
|
24
26
|
onUploadProgress
|
|
25
27
|
} = useFileProgress();
|
|
26
|
-
const
|
|
28
|
+
const upload = useUploadLoader({
|
|
27
29
|
requestOptions: {
|
|
28
30
|
...props.requestOptions,
|
|
29
31
|
onDownloadProgress,
|
|
30
32
|
onUploadProgress
|
|
31
33
|
},
|
|
32
34
|
pathURL: props.uploadPathURL
|
|
33
|
-
};
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return fileExtension === acceptedType.toLowerCase();
|
|
46
|
-
}
|
|
47
|
-
if (acceptedType.endsWith("/*")) {
|
|
48
|
-
const baseType = acceptedType.slice(0, -2);
|
|
49
|
-
return file.type.startsWith(baseType + "/");
|
|
50
|
-
}
|
|
51
|
-
return file.type === acceptedType;
|
|
52
|
-
});
|
|
53
|
-
if (!isValidFileType) {
|
|
54
|
-
setErrors("\u0E1B\u0E23\u0E30\u0E40\u0E20\u0E17\u0E44\u0E1F\u0E25\u0E4C\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 (\u0E23\u0E2D\u0E07\u0E23\u0E31\u0E1A\u0E40\u0E09\u0E1E\u0E32\u0E30 " + acceptedTypesList.join(", ") + ")");
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (props.maxSize) {
|
|
59
|
-
const maxSizeBytes = (fileAllocate.acceptFileSizeKb.value || 0) * 1024;
|
|
60
|
-
if (file.size > maxSizeBytes) {
|
|
61
|
-
if (fileAllocate.isAcceptFileUseMb.value) {
|
|
62
|
-
setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeMb.value} MB`);
|
|
63
|
-
} else {
|
|
64
|
-
setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeKb.value} KB`);
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
setErrors("");
|
|
70
|
-
return true;
|
|
71
|
-
};
|
|
72
|
-
const processFile = (file) => {
|
|
73
|
-
if (!validateFile(file)) return;
|
|
74
|
-
selectedFile.value = file;
|
|
75
|
-
emits("change", file);
|
|
76
|
-
const formData = new FormData();
|
|
77
|
-
formData.append(props.bodyKey, file);
|
|
35
|
+
});
|
|
36
|
+
const currentState = computed(() => {
|
|
37
|
+
if (value.value) return UploadState.SUCCESS;
|
|
38
|
+
if (selectedFile.value && upload.status.value.isLoading) return UploadState.UPLOADING;
|
|
39
|
+
if (selectedFile.value && upload.status.value.isError) return UploadState.ERROR;
|
|
40
|
+
return UploadState.EMPTY;
|
|
41
|
+
});
|
|
42
|
+
const isEmpty = computed(() => currentState.value === UploadState.EMPTY);
|
|
43
|
+
const isUploading = computed(() => currentState.value === UploadState.UPLOADING);
|
|
44
|
+
const isSuccess = computed(() => currentState.value === UploadState.SUCCESS);
|
|
45
|
+
const isError = computed(() => currentState.value === UploadState.ERROR);
|
|
46
|
+
const startUpload = (file) => {
|
|
78
47
|
upload.run({
|
|
79
|
-
data:
|
|
48
|
+
data: toUploadFormData(props.bodyKey, file)
|
|
80
49
|
});
|
|
81
50
|
};
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
51
|
+
const processFile = async (file) => {
|
|
52
|
+
const error = validateFile(file, props, messages.value.upload) ?? await options.validateExtra?.(file);
|
|
53
|
+
setErrors(error ?? "");
|
|
54
|
+
if (error) return;
|
|
55
|
+
selectedFile.value = file;
|
|
56
|
+
emits("change", file);
|
|
57
|
+
startUpload(file);
|
|
88
58
|
};
|
|
89
|
-
const
|
|
90
|
-
accept: acceptedFileTypes.value || "",
|
|
91
|
-
directory: false,
|
|
92
|
-
multiple: false
|
|
93
|
-
});
|
|
94
|
-
const dropzone = useDropZone(dropzoneRef, {
|
|
95
|
-
onDrop: handleFileDrop,
|
|
96
|
-
// dataTypes: typeof props.accept === 'string' ? [props.accept] : props.accept,
|
|
59
|
+
const picker = useFilePicker(context, {
|
|
97
60
|
multiple: false,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (selectedFile.value && upload.status.value.isLoading) return "uploading" /* UPLOADING */;
|
|
103
|
-
if (selectedFile.value && upload.status.value.isError) return "error" /* ERROR */;
|
|
104
|
-
return "empty" /* EMPTY */;
|
|
105
|
-
});
|
|
106
|
-
const isEmpty = computed(() => currentState.value === "empty" /* EMPTY */);
|
|
107
|
-
const isUploading = computed(() => currentState.value === "uploading" /* UPLOADING */);
|
|
108
|
-
const isSuccess = computed(() => currentState.value === "success" /* SUCCESS */);
|
|
109
|
-
const isError = computed(() => currentState.value === "error" /* ERROR */);
|
|
110
|
-
const handleInputChange = (event) => {
|
|
111
|
-
if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
|
|
112
|
-
const file = event.target.files?.[0];
|
|
113
|
-
if (file) {
|
|
114
|
-
processFile(file);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
fileDialog.onChange((files) => {
|
|
118
|
-
if (files?.length) {
|
|
119
|
-
processFile(files[0]);
|
|
61
|
+
defaultAccept: options.defaultAccept,
|
|
62
|
+
canDrop: () => isEmpty.value,
|
|
63
|
+
onFiles: async ([file]) => {
|
|
64
|
+
if (file) await processFile(file);
|
|
120
65
|
}
|
|
121
66
|
});
|
|
122
|
-
const handleOpenFile = () => {
|
|
123
|
-
if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
|
|
124
|
-
fileDialog.open();
|
|
125
|
-
};
|
|
126
67
|
const handleDeleteFile = () => {
|
|
127
|
-
fileDialog.reset();
|
|
68
|
+
picker.fileDialog.reset();
|
|
128
69
|
upload.clear();
|
|
129
70
|
selectedFile.value = void 0;
|
|
130
71
|
onChange(void 0);
|
|
131
72
|
emits("delete");
|
|
132
73
|
};
|
|
133
74
|
const handleRetryUpload = () => {
|
|
134
|
-
if (selectedFile.value)
|
|
135
|
-
const formData = new FormData();
|
|
136
|
-
formData.append(props.bodyKey, selectedFile.value);
|
|
137
|
-
upload.run(formData);
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
const handlePreview = () => {
|
|
141
|
-
previewModal.open({
|
|
142
|
-
value: value.value
|
|
143
|
-
});
|
|
75
|
+
if (selectedFile.value) startUpload(selectedFile.value);
|
|
144
76
|
};
|
|
145
77
|
useWatchTrue(
|
|
146
78
|
() => upload.status.value.isSuccess,
|
|
147
79
|
() => {
|
|
148
|
-
if (upload.data.value)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
name: _get(upload.data.value, props.responseName) || selectedFile.value?.name,
|
|
153
|
-
size: Number(_get(upload.data.value, props.responseSize) || selectedFile.value?.size),
|
|
154
|
-
id: _get(upload.data.value, props.responseID)
|
|
155
|
-
};
|
|
156
|
-
value.value = fileValue;
|
|
157
|
-
emits("success", fileValue);
|
|
158
|
-
}
|
|
80
|
+
if (!upload.data.value) return;
|
|
81
|
+
const fileValue = toFileValue(upload.data.value, props, selectedFile.value);
|
|
82
|
+
value.value = fileValue;
|
|
83
|
+
emits("success", fileValue);
|
|
159
84
|
}
|
|
160
85
|
);
|
|
161
86
|
useWatchTrue(
|
|
162
87
|
() => upload.status.value.isError,
|
|
163
88
|
() => {
|
|
164
|
-
setErrors(
|
|
89
|
+
setErrors(format(messages.value.upload.error, {
|
|
90
|
+
message: StringHelper.getError(upload.status.value.errorData, messages.value.common.somethingWentWrong)
|
|
91
|
+
}));
|
|
165
92
|
}
|
|
166
93
|
);
|
|
167
94
|
return {
|
|
@@ -174,13 +101,13 @@ export const useUploadState = (props, emits, onChange, setErrors, value, accepte
|
|
|
174
101
|
selectedFile,
|
|
175
102
|
// Upload utilities
|
|
176
103
|
upload,
|
|
177
|
-
dropzone,
|
|
104
|
+
dropzone: picker.dropzone,
|
|
178
105
|
percent,
|
|
179
106
|
// Handlers
|
|
180
|
-
handleInputChange,
|
|
181
|
-
handleOpenFile,
|
|
107
|
+
handleInputChange: picker.handleInputChange,
|
|
108
|
+
handleOpenFile: picker.handleOpenFile,
|
|
182
109
|
handleDeleteFile,
|
|
183
110
|
handleRetryUpload,
|
|
184
|
-
handlePreview
|
|
111
|
+
handlePreview: () => picker.openPreview(value.value)
|
|
185
112
|
};
|
|
186
113
|
};
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import type { TemplateRef } from 'vue';
|
|
2
1
|
import type { IUploadDropzoneAutoMultipleProps } from '../InputUploadDropzoneAutoMultiple/types.js';
|
|
2
|
+
import { type IUploadFieldContext } from './useFilePicker.js';
|
|
3
|
+
import { UploadState } from '#core/helpers/uploadCore';
|
|
3
4
|
import type { IFileValue } from '#core/components/Form/types';
|
|
4
|
-
export
|
|
5
|
-
EMPTY = "empty",
|
|
6
|
-
UPLOADING = "uploading",
|
|
7
|
-
SUCCESS = "success",
|
|
8
|
-
ERROR = "error"
|
|
9
|
-
}
|
|
5
|
+
export { UploadState };
|
|
10
6
|
export interface FileUploadItem {
|
|
7
|
+
id: number;
|
|
11
8
|
file: File;
|
|
12
9
|
state: UploadState;
|
|
13
10
|
progress: number;
|
|
14
11
|
value?: IFileValue;
|
|
15
12
|
error?: string;
|
|
16
|
-
uploadLoader?: any;
|
|
17
|
-
percentRef?: any;
|
|
18
|
-
cleanupWatchers?: (() => void)[];
|
|
19
13
|
}
|
|
20
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Uploads every picked file right away. Finished files move into the field value (newest first);
|
|
16
|
+
* `fileItems` only holds the ones still uploading or failed.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useUploadStateMultiple: (context: IUploadFieldContext<IUploadDropzoneAutoMultipleProps, IFileValue[]>) => {
|
|
21
19
|
fileItems: import("vue").Ref<{
|
|
20
|
+
id: number;
|
|
22
21
|
file: {
|
|
23
22
|
readonly lastModified: number;
|
|
24
23
|
readonly name: string;
|
|
@@ -56,10 +55,8 @@ export declare const useUploadStateMultiple: (props: IUploadDropzoneAutoMultiple
|
|
|
56
55
|
id?: string | undefined;
|
|
57
56
|
} | undefined;
|
|
58
57
|
error?: string | undefined;
|
|
59
|
-
uploadLoader?: any;
|
|
60
|
-
percentRef?: any;
|
|
61
|
-
cleanupWatchers?: (() => void)[] | undefined;
|
|
62
58
|
}[], FileUploadItem[] | {
|
|
59
|
+
id: number;
|
|
63
60
|
file: {
|
|
64
61
|
readonly lastModified: number;
|
|
65
62
|
readonly name: string;
|
|
@@ -97,9 +94,6 @@ export declare const useUploadStateMultiple: (props: IUploadDropzoneAutoMultiple
|
|
|
97
94
|
id?: string | undefined;
|
|
98
95
|
} | undefined;
|
|
99
96
|
error?: string | undefined;
|
|
100
|
-
uploadLoader?: any;
|
|
101
|
-
percentRef?: any;
|
|
102
|
-
cleanupWatchers?: (() => void)[] | undefined;
|
|
103
97
|
}[]>;
|
|
104
98
|
isEmpty: import("vue").ComputedRef<boolean>;
|
|
105
99
|
hasUploading: import("vue").ComputedRef<boolean>;
|
|
@@ -108,5 +102,5 @@ export declare const useUploadStateMultiple: (props: IUploadDropzoneAutoMultiple
|
|
|
108
102
|
handleOpenFile: () => void;
|
|
109
103
|
handleDeleteFile: (index: number) => void;
|
|
110
104
|
handleRetryUpload: (index: number) => Promise<void>;
|
|
111
|
-
handlePreview: (fileValue: IFileValue) => void;
|
|
105
|
+
handlePreview: (fileValue: IFileValue | File) => void;
|
|
112
106
|
};
|