@finema/core 2.22.0 → 2.23.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/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/Form/Fields.vue +5 -1
- package/dist/runtime/components/Form/InputUploadDropzone/index.vue +105 -0
- package/dist/runtime/components/Form/InputUploadDropzone/index.vue.d.ts +12 -0
- package/dist/runtime/components/Form/InputUploadDropzone/types.d.ts +11 -0
- package/dist/runtime/components/Form/InputUploadDropzone/types.js +0 -0
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +5 -5
- package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/EmptyState.vue +1 -1
- package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/FailedState.vue +1 -1
- package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/LoadingState.vue +1 -1
- package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/SuccessState.vue +7 -6
- package/dist/runtime/components/Form/fileState/useFileState.d.ts +23 -0
- package/dist/runtime/components/Form/fileState/useFileState.js +154 -0
- package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/useUploadState.d.ts +1 -1
- package/dist/runtime/components/Form/types.d.ts +2 -1
- package/dist/runtime/composables/useFileIcon.d.ts +1 -0
- package/dist/runtime/composables/useFileIcon.js +9 -0
- package/dist/runtime/theme/uploadFileDropzone.d.ts +4 -3
- package/dist/runtime/theme/uploadFileDropzone.js +4 -3
- package/package.json +1 -1
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/EmptyState.vue.d.ts +0 -0
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/FailedState.vue.d.ts +0 -0
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/LoadingState.vue.d.ts +0 -0
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/PreviewModal.vue +0 -0
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/PreviewModal.vue.d.ts +0 -0
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/SuccessState.vue.d.ts +0 -0
- /package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/useUploadState.js +0 -0
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -33,6 +33,7 @@ import FormInputRadio from "./InputRadio/index.vue";
|
|
|
33
33
|
import FormInputDateTime from "./InputDateTime/index.vue";
|
|
34
34
|
import FormInputDateTimeRange from "./InputDateTimeRange/index.vue";
|
|
35
35
|
import FormInputUploadDropzoneAuto from "./InputUploadDropzoneAuto/index.vue";
|
|
36
|
+
import FormInputUploadDropzone from "./InputUploadDropzone/index.vue";
|
|
36
37
|
import FormInputWYSIWYG from "./InputWYSIWYG/index.vue";
|
|
37
38
|
import { INPUT_TYPES } from "#core/components/Form/types";
|
|
38
39
|
import { formTheme } from "#core/theme/form";
|
|
@@ -121,7 +122,10 @@ const componentMap = {
|
|
|
121
122
|
[INPUT_TYPES.UPLOAD_FILE_CLASSIC]: void 0,
|
|
122
123
|
[INPUT_TYPES.UPLOAD_FILE_CLASSIC_AUTO]: void 0,
|
|
123
124
|
[INPUT_TYPES.UPLOAD_IMAGE_AUTO]: void 0,
|
|
124
|
-
[INPUT_TYPES.UPLOAD_DROPZONE]:
|
|
125
|
+
[INPUT_TYPES.UPLOAD_DROPZONE]: {
|
|
126
|
+
component: FormInputUploadDropzone,
|
|
127
|
+
props: {}
|
|
128
|
+
},
|
|
125
129
|
[INPUT_TYPES.UPLOAD_DROPZONE_AUTO]: {
|
|
126
130
|
component: FormInputUploadDropzoneAuto,
|
|
127
131
|
props: {}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
+
<div
|
|
4
|
+
ref="dropzoneRef"
|
|
5
|
+
:class="theme.base()"
|
|
6
|
+
>
|
|
7
|
+
<div :class="theme.wrapper()">
|
|
8
|
+
<!-- Empty State -->
|
|
9
|
+
<EmptyState
|
|
10
|
+
v-if="uploadState.isEmpty.value"
|
|
11
|
+
:theme="theme"
|
|
12
|
+
:select-file-label="selectFileLabel"
|
|
13
|
+
:select-file-sub-label="selectFileSubLabel"
|
|
14
|
+
:placeholder="placeholder"
|
|
15
|
+
@open-file="uploadState.handleOpenFile"
|
|
16
|
+
/>
|
|
17
|
+
|
|
18
|
+
<!-- Success State -->
|
|
19
|
+
<SuccessState
|
|
20
|
+
v-if="uploadState.isSuccess.value"
|
|
21
|
+
:theme="theme"
|
|
22
|
+
:value="value"
|
|
23
|
+
:disabled="wrapperProps.disabled"
|
|
24
|
+
:readonly="wrapperProps.readonly"
|
|
25
|
+
@preview="uploadState.handlePreview"
|
|
26
|
+
@download="handleDownloadFile"
|
|
27
|
+
@delete="uploadState.handleDeleteFile"
|
|
28
|
+
/>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</FieldWrapper>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup>
|
|
35
|
+
import EmptyState from "../fileState/EmptyState.vue";
|
|
36
|
+
import SuccessState from "../fileState/SuccessState.vue";
|
|
37
|
+
import { useFileState } from "../fileState/useFileState";
|
|
38
|
+
import { computed, useTemplateRef, useWatchChange } from "#imports";
|
|
39
|
+
import FieldWrapper from "#core/components/Form/FieldWrapper.vue";
|
|
40
|
+
import { useFieldHOC } from "#core/composables/useForm";
|
|
41
|
+
import { uploadFileDropzoneTheme } from "#core/theme/uploadFileDropzone";
|
|
42
|
+
import { useUiConfig } from "#core/composables/useConfig";
|
|
43
|
+
const props = defineProps({
|
|
44
|
+
accept: { type: [Array, String], required: false },
|
|
45
|
+
maxSize: { type: Number, required: false },
|
|
46
|
+
selectFileLabel: { type: String, required: false, default: "\u0E04\u0E25\u0E34\u0E01\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C" },
|
|
47
|
+
selectFileSubLabel: { type: String, required: false, default: "\u0E2B\u0E23\u0E37\u0E2D \u0E25\u0E32\u0E01\u0E41\u0E25\u0E30\u0E27\u0E32\u0E07\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48" },
|
|
48
|
+
form: { type: Object, required: false },
|
|
49
|
+
name: { type: String, required: true },
|
|
50
|
+
errorMessage: { type: String, required: false },
|
|
51
|
+
label: { type: null, required: false },
|
|
52
|
+
description: { type: String, required: false },
|
|
53
|
+
hint: { type: String, required: false },
|
|
54
|
+
rules: { type: null, required: false },
|
|
55
|
+
autoFocus: { type: Boolean, required: false },
|
|
56
|
+
placeholder: { type: String, required: false },
|
|
57
|
+
disabled: { type: Boolean, required: false },
|
|
58
|
+
readonly: { type: Boolean, required: false },
|
|
59
|
+
required: { type: Boolean, required: false },
|
|
60
|
+
help: { type: String, required: false },
|
|
61
|
+
ui: { type: null, required: false }
|
|
62
|
+
});
|
|
63
|
+
const emits = defineEmits(["change", "delete"]);
|
|
64
|
+
const {
|
|
65
|
+
wrapperProps,
|
|
66
|
+
handleChange: onChange,
|
|
67
|
+
setErrors,
|
|
68
|
+
value
|
|
69
|
+
} = useFieldHOC(props);
|
|
70
|
+
const acceptedFileTypes = computed(
|
|
71
|
+
() => typeof props.accept === "string" ? props.accept : props.accept?.join(",")
|
|
72
|
+
);
|
|
73
|
+
const dropzoneRef = useTemplateRef("dropzoneRef");
|
|
74
|
+
const uploadState = useFileState(
|
|
75
|
+
props,
|
|
76
|
+
emits,
|
|
77
|
+
onChange,
|
|
78
|
+
setErrors,
|
|
79
|
+
value,
|
|
80
|
+
acceptedFileTypes,
|
|
81
|
+
wrapperProps,
|
|
82
|
+
dropzoneRef
|
|
83
|
+
);
|
|
84
|
+
useWatchChange(() => value.value, (newValue) => {
|
|
85
|
+
if (typeof newValue === "object" && newValue !== null) {
|
|
86
|
+
onChange(newValue);
|
|
87
|
+
} else {
|
|
88
|
+
onChange(void 0);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const theme = computed(
|
|
92
|
+
() => useUiConfig(uploadFileDropzoneTheme, "uploadFileDropzone")({
|
|
93
|
+
dragover: uploadState.dropzone.isOverDropZone.value && uploadState.isEmpty.value,
|
|
94
|
+
disabled: wrapperProps.value.disabled
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
const handleDownloadFile = () => {
|
|
98
|
+
if (value.value?.url && value.value?.name) {
|
|
99
|
+
const a = document.createElement("a");
|
|
100
|
+
a.href = value.value.url;
|
|
101
|
+
a.download = value.value.name;
|
|
102
|
+
a.click();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IUploadDropzoneProps } from './types.js';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<IUploadDropzoneProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
delete: () => any;
|
|
4
|
+
change: (value: File | undefined) => any;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<IUploadDropzoneProps> & Readonly<{
|
|
6
|
+
onDelete?: (() => any) | undefined;
|
|
7
|
+
onChange?: ((value: File | undefined) => any) | undefined;
|
|
8
|
+
}>, {
|
|
9
|
+
selectFileLabel: string;
|
|
10
|
+
selectFileSubLabel: string;
|
|
11
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IFieldProps, IFormFieldBase, INPUT_TYPES } from '../types.js';
|
|
2
|
+
export interface IUploadDropzoneProps extends IFieldProps {
|
|
3
|
+
accept?: string[] | string;
|
|
4
|
+
maxSize?: number;
|
|
5
|
+
selectFileLabel?: string;
|
|
6
|
+
selectFileSubLabel?: string;
|
|
7
|
+
}
|
|
8
|
+
export type IUploadDropzoneField = IFormFieldBase<INPUT_TYPES.UPLOAD_DROPZONE, IUploadDropzoneProps, {
|
|
9
|
+
change: (value: File | undefined) => void;
|
|
10
|
+
delete: () => void;
|
|
11
|
+
}>;
|
|
File without changes
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
</template>
|
|
53
53
|
|
|
54
54
|
<script setup>
|
|
55
|
-
import EmptyState from "
|
|
56
|
-
import
|
|
57
|
-
import
|
|
58
|
-
import FailedState from "
|
|
59
|
-
import { useUploadState } from "
|
|
55
|
+
import EmptyState from "../fileState/EmptyState.vue";
|
|
56
|
+
import SuccessState from "../fileState/SuccessState.vue";
|
|
57
|
+
import LoadingState from "../fileState/LoadingState.vue";
|
|
58
|
+
import FailedState from "../fileState/FailedState.vue";
|
|
59
|
+
import { useUploadState } from "../fileState/useUploadState";
|
|
60
60
|
import { computed, useTemplateRef, useWatchChange } from "#imports";
|
|
61
61
|
import FieldWrapper from "#core/components/Form/FieldWrapper.vue";
|
|
62
62
|
import { useFieldHOC } from "#core/composables/useForm";
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</template>
|
|
24
24
|
|
|
25
25
|
<script setup>
|
|
26
|
-
import { useUiIconConfig } from "#
|
|
26
|
+
import { useUiIconConfig } from "#core/composables/useConfig";
|
|
27
27
|
defineProps({
|
|
28
28
|
theme: { type: null, required: true },
|
|
29
29
|
selectFileLabel: { type: String, required: true },
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
<script setup>
|
|
38
38
|
import { isImage } from "#core/helpers/componentHelper";
|
|
39
|
-
import { useUiIconConfig } from "#
|
|
39
|
+
import { useUiIconConfig } from "#core/composables/useConfig";
|
|
40
40
|
const props = defineProps({
|
|
41
41
|
theme: { type: null, required: true },
|
|
42
42
|
selectedFile: { type: null, required: true },
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
<script setup>
|
|
29
29
|
import { isImage } from "#core/helpers/componentHelper";
|
|
30
|
-
import { useUiIconConfig } from "#
|
|
30
|
+
import { useUiIconConfig } from "#core/composables/useConfig";
|
|
31
31
|
const props = defineProps({
|
|
32
32
|
theme: { type: null, required: true },
|
|
33
33
|
selectedFile: { type: null, required: true },
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="theme.onPreviewWrapper()">
|
|
3
|
-
<div :class="theme.
|
|
3
|
+
<div v-if="isImageFromPath(value.path)" :class="theme.onPreviewImgWrapper()">
|
|
4
4
|
<div
|
|
5
|
-
v-if="isImageFromPath(value.path)"
|
|
6
5
|
class="size-full overflow-hidden"
|
|
7
6
|
>
|
|
8
7
|
<img
|
|
9
8
|
:src="value.url"
|
|
10
|
-
:class="theme.
|
|
9
|
+
:class="theme.onPreviewImgClass()"
|
|
11
10
|
alt="img-preview"
|
|
12
11
|
/>
|
|
13
12
|
</div>
|
|
14
|
-
|
|
13
|
+
</div>
|
|
14
|
+
<div v-else :class="theme.onPreviewFileWrapper()">
|
|
15
|
+
<div >
|
|
15
16
|
<Icon
|
|
16
17
|
:name="icons.filePreviewIcon"
|
|
17
|
-
:class="theme.
|
|
18
|
+
:class="theme.onPreviewFileClass()"
|
|
18
19
|
/>
|
|
19
20
|
</div>
|
|
20
21
|
</div>
|
|
@@ -72,7 +73,7 @@ import {
|
|
|
72
73
|
isVideoFromPath,
|
|
73
74
|
useFileSize
|
|
74
75
|
} from "#core/helpers/componentHelper";
|
|
75
|
-
import { useUiIconConfig } from "#
|
|
76
|
+
import { useUiIconConfig } from "#core/composables/useConfig";
|
|
76
77
|
defineProps({
|
|
77
78
|
theme: { type: null, required: true },
|
|
78
79
|
value: { type: Object, required: true },
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TemplateRef } from 'vue';
|
|
2
|
+
import type { IUploadDropzoneProps } from '../InputUploadDropzone/types.js';
|
|
3
|
+
import type { IFileValue } from '#core/components/Form/types';
|
|
4
|
+
export declare enum UploadState {
|
|
5
|
+
EMPTY = "empty",
|
|
6
|
+
UPLOADING = "uploading",
|
|
7
|
+
SUCCESS = "success",
|
|
8
|
+
ERROR = "error"
|
|
9
|
+
}
|
|
10
|
+
export declare const useFileState: (props: IUploadDropzoneProps, emits: any, onChange: (value: IFileValue | undefined) => void, setErrors: (error: string) => void, value: any, acceptedFileTypes: any, wrapperProps: any, dropzoneRef: TemplateRef<HTMLDivElement | undefined>) => {
|
|
11
|
+
currentState: import("vue").ComputedRef<UploadState.EMPTY | UploadState.SUCCESS>;
|
|
12
|
+
isEmpty: import("vue").ComputedRef<boolean>;
|
|
13
|
+
isSuccess: import("vue").ComputedRef<boolean>;
|
|
14
|
+
selectedFile: import("vue").Ref<File | undefined, File | undefined>;
|
|
15
|
+
currentObjectUrl: import("vue").Ref<string, string>;
|
|
16
|
+
dropzone: import("@vueuse/core").UseDropZoneReturn;
|
|
17
|
+
handleInputChange: (event: Event) => void;
|
|
18
|
+
handleOpenFile: () => void;
|
|
19
|
+
handleDeleteFile: () => void;
|
|
20
|
+
handleRetryUpload: () => void;
|
|
21
|
+
handlePreview: () => void;
|
|
22
|
+
cleanup: () => void;
|
|
23
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { useDropZone, useFileDialog } from "@vueuse/core";
|
|
2
|
+
import PreviewModal from "../fileState/PreviewModal.vue";
|
|
3
|
+
import { computed, ref, useOverlay } from "#imports";
|
|
4
|
+
import { useFileAllocate } from "#core/helpers/componentHelper";
|
|
5
|
+
const overlay = useOverlay();
|
|
6
|
+
const previewModal = overlay.create(PreviewModal);
|
|
7
|
+
export var UploadState = /* @__PURE__ */ ((UploadState2) => {
|
|
8
|
+
UploadState2["EMPTY"] = "empty";
|
|
9
|
+
UploadState2["UPLOADING"] = "uploading";
|
|
10
|
+
UploadState2["SUCCESS"] = "success";
|
|
11
|
+
UploadState2["ERROR"] = "error";
|
|
12
|
+
return UploadState2;
|
|
13
|
+
})(UploadState || {});
|
|
14
|
+
export const useFileState = (props, emits, onChange, setErrors, value, acceptedFileTypes, wrapperProps, dropzoneRef) => {
|
|
15
|
+
const selectedFile = ref();
|
|
16
|
+
const currentObjectUrl = ref("");
|
|
17
|
+
const fileAllocate = useFileAllocate(selectedFile, props);
|
|
18
|
+
const validateFile = (file) => {
|
|
19
|
+
if (props.accept && fileAllocate.acceptFile.value) {
|
|
20
|
+
const acceptedTypes = fileAllocate.acceptFile.value;
|
|
21
|
+
const acceptedTypesList = acceptedTypes.split(",").map((type) => type.trim());
|
|
22
|
+
const fileExtension = file.name.toLowerCase().split(".").pop();
|
|
23
|
+
const isValidFileType = acceptedTypesList.some((acceptedType) => {
|
|
24
|
+
if (acceptedType.startsWith(".")) {
|
|
25
|
+
const extension = acceptedType.slice(1).toLowerCase();
|
|
26
|
+
return fileExtension === extension;
|
|
27
|
+
} else if (!acceptedType.includes("/") && !acceptedType.includes("*")) {
|
|
28
|
+
return fileExtension === acceptedType.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
if (acceptedType.endsWith("/*")) {
|
|
31
|
+
const baseType = acceptedType.slice(0, -2);
|
|
32
|
+
return file.type.startsWith(baseType + "/");
|
|
33
|
+
}
|
|
34
|
+
return file.type === acceptedType;
|
|
35
|
+
});
|
|
36
|
+
if (!isValidFileType) {
|
|
37
|
+
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(", ") + ")");
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (props.maxSize) {
|
|
42
|
+
const maxSizeBytes = (fileAllocate.acceptFileSizeKb.value || 0) * 1024;
|
|
43
|
+
if (file.size > maxSizeBytes) {
|
|
44
|
+
if (fileAllocate.isAcceptFileUseMb.value) {
|
|
45
|
+
setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeMb.value} MB`);
|
|
46
|
+
} else {
|
|
47
|
+
setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeKb.value} KB`);
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
setErrors("");
|
|
53
|
+
return true;
|
|
54
|
+
};
|
|
55
|
+
const processFile = (file) => {
|
|
56
|
+
if (!validateFile(file)) return;
|
|
57
|
+
selectedFile.value = file;
|
|
58
|
+
emits("change", file);
|
|
59
|
+
if (currentObjectUrl.value) {
|
|
60
|
+
URL.revokeObjectURL(currentObjectUrl.value);
|
|
61
|
+
}
|
|
62
|
+
const objectUrl = URL.createObjectURL(file);
|
|
63
|
+
currentObjectUrl.value = objectUrl;
|
|
64
|
+
value.value = file;
|
|
65
|
+
emits("success", file);
|
|
66
|
+
};
|
|
67
|
+
const handleFileDrop = (files) => {
|
|
68
|
+
if (wrapperProps.value.disabled || wrapperProps.value.readonly || !files?.length || !isEmpty.value) return;
|
|
69
|
+
const file = files[0];
|
|
70
|
+
if (file) {
|
|
71
|
+
processFile(file);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const fileDialog = useFileDialog({
|
|
75
|
+
accept: acceptedFileTypes.value || "",
|
|
76
|
+
directory: false,
|
|
77
|
+
multiple: false
|
|
78
|
+
});
|
|
79
|
+
const dropzone = useDropZone(dropzoneRef, {
|
|
80
|
+
onDrop: handleFileDrop,
|
|
81
|
+
// dataTypes: typeof props.accept === 'string' ? [props.accept] : props.accept,
|
|
82
|
+
multiple: false,
|
|
83
|
+
preventDefaultForUnhandled: false
|
|
84
|
+
});
|
|
85
|
+
const currentState = computed(() => {
|
|
86
|
+
if (value.value) return "success" /* SUCCESS */;
|
|
87
|
+
return "empty" /* EMPTY */;
|
|
88
|
+
});
|
|
89
|
+
const isEmpty = computed(() => currentState.value === "empty" /* EMPTY */);
|
|
90
|
+
const isSuccess = computed(() => currentState.value === "success" /* SUCCESS */);
|
|
91
|
+
const handleInputChange = (event) => {
|
|
92
|
+
if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
|
|
93
|
+
const file = event.target.files?.[0];
|
|
94
|
+
if (file) {
|
|
95
|
+
processFile(file);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
fileDialog.onChange((files) => {
|
|
99
|
+
if (files?.length) {
|
|
100
|
+
processFile(files[0]);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const handleOpenFile = () => {
|
|
104
|
+
if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
|
|
105
|
+
fileDialog.open();
|
|
106
|
+
};
|
|
107
|
+
const handleDeleteFile = () => {
|
|
108
|
+
fileDialog.reset();
|
|
109
|
+
if (currentObjectUrl.value) {
|
|
110
|
+
URL.revokeObjectURL(currentObjectUrl.value);
|
|
111
|
+
currentObjectUrl.value = "";
|
|
112
|
+
}
|
|
113
|
+
selectedFile.value = void 0;
|
|
114
|
+
onChange(void 0);
|
|
115
|
+
emits("delete");
|
|
116
|
+
};
|
|
117
|
+
const handleRetryUpload = () => {
|
|
118
|
+
if (selectedFile.value) {
|
|
119
|
+
processFile(selectedFile.value);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const handlePreview = () => {
|
|
123
|
+
previewModal.open({
|
|
124
|
+
value: value.value
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
const cleanup = () => {
|
|
128
|
+
if (currentObjectUrl.value) {
|
|
129
|
+
URL.revokeObjectURL(currentObjectUrl.value);
|
|
130
|
+
currentObjectUrl.value = "";
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
if (typeof window !== "undefined") {
|
|
134
|
+
window.addEventListener("beforeunload", cleanup);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
// State
|
|
138
|
+
currentState,
|
|
139
|
+
isEmpty,
|
|
140
|
+
isSuccess,
|
|
141
|
+
selectedFile,
|
|
142
|
+
currentObjectUrl,
|
|
143
|
+
// Upload utilities
|
|
144
|
+
dropzone,
|
|
145
|
+
// Handlers
|
|
146
|
+
handleInputChange,
|
|
147
|
+
handleOpenFile,
|
|
148
|
+
handleDeleteFile,
|
|
149
|
+
handleRetryUpload,
|
|
150
|
+
handlePreview,
|
|
151
|
+
// Cleanup
|
|
152
|
+
cleanup
|
|
153
|
+
};
|
|
154
|
+
};
|
package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/useUploadState.d.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TemplateRef } from 'vue';
|
|
2
|
-
import type { IUploadDropzoneAutoProps } from '
|
|
2
|
+
import type { IUploadDropzoneAutoProps } from '../InputUploadDropzoneAuto/types.js';
|
|
3
3
|
import type { IFileValue } from '#core/components/Form/types';
|
|
4
4
|
export declare enum UploadState {
|
|
5
5
|
EMPTY = "empty",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Component } from '@nuxt/schema';
|
|
2
2
|
import type { FormContext } from 'vee-validate';
|
|
3
|
+
import type { IUploadDropzoneField } from './InputUploadDropzone/types.js';
|
|
3
4
|
import type { IUploadDropzoneAutoField } from './InputUploadDropzoneAuto/types.js';
|
|
4
5
|
import type { IDateTimeRangeField } from './InputDateTimeRange/date_range_time_field.types.js';
|
|
5
6
|
import type { ITextField } from '#core/components/Form/InputText/types';
|
|
@@ -66,7 +67,7 @@ export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O>
|
|
|
66
67
|
props: P;
|
|
67
68
|
on?: O;
|
|
68
69
|
}
|
|
69
|
-
export type IFormField = ITextField | ISearchField | INumberField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IRadioField | IDateTimeField | IDateTimeRangeField | IUploadDropzoneAutoField | IWYSIWYGField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
|
|
70
|
+
export type IFormField = ITextField | ISearchField | INumberField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IRadioField | IDateTimeField | IDateTimeRangeField | IUploadDropzoneField | IUploadDropzoneAutoField | IWYSIWYGField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
|
|
70
71
|
export interface IFileValue {
|
|
71
72
|
url: string;
|
|
72
73
|
path?: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getFileIcon: (file: File) => string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { isImage } from "../helpers/componentHelper.js";
|
|
2
|
+
import { useUiIconConfig } from "./useConfig.js";
|
|
3
|
+
export const getFileIcon = (file) => {
|
|
4
|
+
const icons = useUiIconConfig("uploadFileDropzone");
|
|
5
|
+
if (isImage(file)) {
|
|
6
|
+
return icons.placeholderImgIcon;
|
|
7
|
+
}
|
|
8
|
+
return icons.filePreviewIcon;
|
|
9
|
+
};
|
|
@@ -25,9 +25,10 @@ export declare const uploadFileDropzoneTheme: {
|
|
|
25
25
|
onLoadingTextWrapper: string;
|
|
26
26
|
onLoadingLoadingIconClass: string;
|
|
27
27
|
onPreviewWrapper: string;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
onPreviewImgWrapper: string;
|
|
29
|
+
onPreviewImgClass: string;
|
|
30
|
+
onPreviewFileWrapper: string;
|
|
31
|
+
onPreviewFileClass: string;
|
|
31
32
|
onPreviewTextWrapper: string;
|
|
32
33
|
onFailedWrapper: string;
|
|
33
34
|
onFailedFailedImgWrapper: string;
|
|
@@ -27,9 +27,10 @@ export const uploadFileDropzoneTheme = {
|
|
|
27
27
|
onLoadingLoadingIconClass: "size-10 text-primary animate-spin",
|
|
28
28
|
// Preview state
|
|
29
29
|
onPreviewWrapper: "flex items-center space-x-4 rounded-md w-full",
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
onPreviewImgWrapper: "flex-shrink-0 w-16 h-16 flex justify-center items-center rounded-md overflow-hidden bg-gray-100",
|
|
31
|
+
onPreviewImgClass: "w-full h-full object-cover",
|
|
32
|
+
onPreviewFileWrapper: "flex-shrink-0 w-16 h-16 flex justify-center items-center rounded-md overflow-hidden",
|
|
33
|
+
onPreviewFileClass: "size-8 text-gray-400 m-auto",
|
|
33
34
|
onPreviewTextWrapper: "flex-1 min-w-0 flex items-center justify-between",
|
|
34
35
|
// Failed state
|
|
35
36
|
onFailedWrapper: "flex items-start space-x-4 w-full rounded-md",
|
package/package.json
CHANGED
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/EmptyState.vue.d.ts
RENAMED
|
File without changes
|
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/FailedState.vue.d.ts
RENAMED
|
File without changes
|
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/LoadingState.vue.d.ts
RENAMED
|
File without changes
|
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/PreviewModal.vue
RENAMED
|
File without changes
|
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/PreviewModal.vue.d.ts
RENAMED
|
File without changes
|
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/SuccessState.vue.d.ts
RENAMED
|
File without changes
|
/package/dist/runtime/components/Form/{InputUploadDropzoneAuto → fileState}/useUploadState.js
RENAMED
|
File without changes
|