@finema/core 1.4.103 → 1.4.104
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/README.md +60 -60
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/Alert.vue +48 -48
- package/dist/runtime/components/Avatar.vue +27 -27
- package/dist/runtime/components/Badge.vue +11 -11
- package/dist/runtime/components/Breadcrumb.vue +44 -44
- package/dist/runtime/components/Button/Group.vue +37 -37
- package/dist/runtime/components/Button/index.vue +76 -76
- package/dist/runtime/components/Card.vue +38 -38
- package/dist/runtime/components/Core.vue +13 -13
- package/dist/runtime/components/Dialog/index.vue +108 -108
- package/dist/runtime/components/Dropdown/index.vue +70 -70
- package/dist/runtime/components/FlexDeck/Base.vue +90 -90
- package/dist/runtime/components/FlexDeck/index.vue +66 -66
- package/dist/runtime/components/Form/FieldWrapper.vue +23 -23
- package/dist/runtime/components/Form/Fields.vue +199 -199
- package/dist/runtime/components/Form/InputCheckbox/index.vue +21 -21
- package/dist/runtime/components/Form/InputDateTime/index.vue +60 -60
- package/dist/runtime/components/Form/InputDateTimeRange/index.vue +83 -83
- package/dist/runtime/components/Form/InputNumber/index.vue +27 -27
- package/dist/runtime/components/Form/InputRadio/index.vue +27 -27
- package/dist/runtime/components/Form/InputSelect/index.vue +36 -36
- package/dist/runtime/components/Form/InputStatic/index.vue +16 -16
- package/dist/runtime/components/Form/InputText/index.vue +67 -67
- package/dist/runtime/components/Form/InputTextarea/index.vue +25 -25
- package/dist/runtime/components/Form/InputToggle/index.vue +14 -14
- package/dist/runtime/components/Form/InputUploadDropzone/index.vue +206 -206
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +333 -333
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/Item.vue +260 -260
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +140 -140
- package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/index.vue +148 -148
- package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/item.vue +167 -167
- package/dist/runtime/components/Form/InputUploadFileClassic/index.vue +95 -95
- package/dist/runtime/components/Form/InputUploadFileClassicAuto/index.vue +143 -143
- package/dist/runtime/components/Form/InputWYSIWYG/index.vue +40 -40
- package/dist/runtime/components/Form/index.vue +6 -6
- package/dist/runtime/components/Icon.vue +23 -23
- package/dist/runtime/components/Image.vue +36 -36
- package/dist/runtime/components/Loader.vue +27 -27
- package/dist/runtime/components/Modal/index.vue +146 -146
- package/dist/runtime/components/SimplePagination.vue +96 -96
- package/dist/runtime/components/Slideover/index.vue +110 -110
- package/dist/runtime/components/Table/Base.vue +139 -139
- package/dist/runtime/components/Table/ColumnDate.vue +16 -16
- package/dist/runtime/components/Table/ColumnDateTime.vue +18 -18
- package/dist/runtime/components/Table/ColumnImage.vue +15 -15
- package/dist/runtime/components/Table/ColumnNumber.vue +14 -14
- package/dist/runtime/components/Table/ColumnText.vue +25 -25
- package/dist/runtime/components/Table/Simple.vue +69 -69
- package/dist/runtime/components/Table/index.vue +65 -65
- package/dist/runtime/components/Tabs/index.vue +64 -64
- package/package.json +90 -90
|
@@ -1,140 +1,140 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
-
<div class="space-y-3">
|
|
4
|
-
<div
|
|
5
|
-
ref="dropzoneRef"
|
|
6
|
-
:class="[
|
|
7
|
-
ui.base,
|
|
8
|
-
{
|
|
9
|
-
[ui.disabled]: isDisabled,
|
|
10
|
-
[ui.background.default]: !isOverDropZone && !isDisabled,
|
|
11
|
-
[ui.background.dragover]: isOverDropZone && !isDisabled,
|
|
12
|
-
},
|
|
13
|
-
]"
|
|
14
|
-
>
|
|
15
|
-
<input
|
|
16
|
-
ref="fileInputRef"
|
|
17
|
-
type="file"
|
|
18
|
-
class="hidden"
|
|
19
|
-
:name="name"
|
|
20
|
-
:accept="acceptFile"
|
|
21
|
-
:disabled="isDisabled"
|
|
22
|
-
multiple
|
|
23
|
-
@change="handleChange"
|
|
24
|
-
/>
|
|
25
|
-
<div :class="[ui.wrapper]">
|
|
26
|
-
<div :class="[ui.placeholderWrapper]">
|
|
27
|
-
<Icon :name="ui.default.uploadIcon" :class="[ui.labelIcon]" />
|
|
28
|
-
<div :class="[ui.labelWrapper]">
|
|
29
|
-
<p class="text-primary cursor-pointer" @click="handleOpenFile">
|
|
30
|
-
{{ selectFileLabel }}
|
|
31
|
-
</p>
|
|
32
|
-
<p>{{ selectFileSubLabel }}</p>
|
|
33
|
-
</div>
|
|
34
|
-
<p v-if="placeholder" :class="[ui.placeholder]">{{ placeholder }}</p>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
<Item
|
|
39
|
-
v-for="(file, index) in selectedFiles"
|
|
40
|
-
:key="file.key"
|
|
41
|
-
v-bind="$props"
|
|
42
|
-
:ui="ui"
|
|
43
|
-
:selected-file="file.file"
|
|
44
|
-
@success="handleSuccess(index, $event)"
|
|
45
|
-
@delete="handleDeleteFile(index)"
|
|
46
|
-
@error="handleError(index, $event)"
|
|
47
|
-
/>
|
|
48
|
-
</div>
|
|
49
|
-
</FieldWrapper>
|
|
50
|
-
</template>
|
|
51
|
-
|
|
52
|
-
<script lang="ts" setup>
|
|
53
|
-
import { useDropZone } from '@vueuse/core'
|
|
54
|
-
import { type IUploadDropzoneAutoMultipleProps } from './types'
|
|
55
|
-
import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
|
|
56
|
-
import { useFieldHOC } from '#core/composables/useForm'
|
|
57
|
-
import { _get, computed, ref, toRef, useUI, useUiConfig, StringHelper } from '#imports'
|
|
58
|
-
import { uploadFileDropzone } from '#core/ui.config'
|
|
59
|
-
import Item from './Item.vue'
|
|
60
|
-
|
|
61
|
-
const config = useUiConfig<typeof uploadFileDropzone>(uploadFileDropzone, 'uploadFileDropzone')
|
|
62
|
-
const props = withDefaults(defineProps<IUploadDropzoneAutoMultipleProps>(), {
|
|
63
|
-
bodyKey: 'file',
|
|
64
|
-
responseKey: 'url',
|
|
65
|
-
selectFileLabel: 'คลิกเพื่อเลือกไฟล์',
|
|
66
|
-
selectFileSubLabel: 'หรือ ลากและวางที่นี่',
|
|
67
|
-
retryLabel: 'ลองอีกครั้ง',
|
|
68
|
-
uploadingLabel: 'กำลังอัพโหลด...',
|
|
69
|
-
uploadFailedLabel: 'อัพโหลดล้มเหลว, กรุณาลองอีกครั้ง',
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const emits = defineEmits(['change', 'success', 'delete'])
|
|
73
|
-
const selectedFiles = ref<Array<{ file: File; key: string }>>([])
|
|
74
|
-
const { wrapperProps, handleChange: onChange, setErrors, value } = useFieldHOC<File[]>(props)
|
|
75
|
-
|
|
76
|
-
const { ui } = useUI('uploadFileDropzone', toRef(props, 'ui'), config)
|
|
77
|
-
|
|
78
|
-
const fileInputRef = ref<HTMLInputElement | null>()
|
|
79
|
-
const dropzoneRef = ref<HTMLDivElement>()
|
|
80
|
-
|
|
81
|
-
const acceptFile = computed(() =>
|
|
82
|
-
typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
const onDrop = (files: File[] | null) => {
|
|
86
|
-
if (props.isDisabled || files?.length === 0 || !files) return
|
|
87
|
-
|
|
88
|
-
for (const file of files) {
|
|
89
|
-
selectedFiles.value = [
|
|
90
|
-
{
|
|
91
|
-
file,
|
|
92
|
-
key: StringHelper.genString(),
|
|
93
|
-
},
|
|
94
|
-
...selectedFiles.value,
|
|
95
|
-
]
|
|
96
|
-
|
|
97
|
-
emits('change', value.value)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const { isOverDropZone } = useDropZone(dropzoneRef as unknown as HTMLElement, {
|
|
102
|
-
onDrop,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
const handleChange = (e: Event) => {
|
|
106
|
-
if (props.isDisabled) return
|
|
107
|
-
|
|
108
|
-
for (const file of (e.target as HTMLInputElement).files ?? []) {
|
|
109
|
-
selectedFiles.value = [
|
|
110
|
-
{
|
|
111
|
-
file,
|
|
112
|
-
key: StringHelper.genString(),
|
|
113
|
-
},
|
|
114
|
-
...selectedFiles.value,
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
emits('change', value.value)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
fileInputRef.value?.value && (fileInputRef.value.value = '')
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const handleOpenFile = () => {
|
|
124
|
-
fileInputRef.value?.click()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const handleDeleteFile = (index: number) => {
|
|
128
|
-
selectedFiles.value.splice(index, 1)
|
|
129
|
-
onChange(undefined)
|
|
130
|
-
emits('delete')
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const handleError = (index: number, error: any) => {}
|
|
134
|
-
|
|
135
|
-
const handleSuccess = (index: number, any: any) => {
|
|
136
|
-
value.value = [_get(any, props.responseKey), ...(value.value || [])]
|
|
137
|
-
emits('change', value.value)
|
|
138
|
-
emits('success', value.value)
|
|
139
|
-
}
|
|
140
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
+
<div class="space-y-3">
|
|
4
|
+
<div
|
|
5
|
+
ref="dropzoneRef"
|
|
6
|
+
:class="[
|
|
7
|
+
ui.base,
|
|
8
|
+
{
|
|
9
|
+
[ui.disabled]: isDisabled,
|
|
10
|
+
[ui.background.default]: !isOverDropZone && !isDisabled,
|
|
11
|
+
[ui.background.dragover]: isOverDropZone && !isDisabled,
|
|
12
|
+
},
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<input
|
|
16
|
+
ref="fileInputRef"
|
|
17
|
+
type="file"
|
|
18
|
+
class="hidden"
|
|
19
|
+
:name="name"
|
|
20
|
+
:accept="acceptFile"
|
|
21
|
+
:disabled="isDisabled"
|
|
22
|
+
multiple
|
|
23
|
+
@change="handleChange"
|
|
24
|
+
/>
|
|
25
|
+
<div :class="[ui.wrapper]">
|
|
26
|
+
<div :class="[ui.placeholderWrapper]">
|
|
27
|
+
<Icon :name="ui.default.uploadIcon" :class="[ui.labelIcon]" />
|
|
28
|
+
<div :class="[ui.labelWrapper]">
|
|
29
|
+
<p class="text-primary cursor-pointer" @click="handleOpenFile">
|
|
30
|
+
{{ selectFileLabel }}
|
|
31
|
+
</p>
|
|
32
|
+
<p>{{ selectFileSubLabel }}</p>
|
|
33
|
+
</div>
|
|
34
|
+
<p v-if="placeholder" :class="[ui.placeholder]">{{ placeholder }}</p>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<Item
|
|
39
|
+
v-for="(file, index) in selectedFiles"
|
|
40
|
+
:key="file.key"
|
|
41
|
+
v-bind="$props"
|
|
42
|
+
:ui="ui"
|
|
43
|
+
:selected-file="file.file"
|
|
44
|
+
@success="handleSuccess(index, $event)"
|
|
45
|
+
@delete="handleDeleteFile(index)"
|
|
46
|
+
@error="handleError(index, $event)"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
</FieldWrapper>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script lang="ts" setup>
|
|
53
|
+
import { useDropZone } from '@vueuse/core'
|
|
54
|
+
import { type IUploadDropzoneAutoMultipleProps } from './types'
|
|
55
|
+
import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
|
|
56
|
+
import { useFieldHOC } from '#core/composables/useForm'
|
|
57
|
+
import { _get, computed, ref, toRef, useUI, useUiConfig, StringHelper } from '#imports'
|
|
58
|
+
import { uploadFileDropzone } from '#core/ui.config'
|
|
59
|
+
import Item from './Item.vue'
|
|
60
|
+
|
|
61
|
+
const config = useUiConfig<typeof uploadFileDropzone>(uploadFileDropzone, 'uploadFileDropzone')
|
|
62
|
+
const props = withDefaults(defineProps<IUploadDropzoneAutoMultipleProps>(), {
|
|
63
|
+
bodyKey: 'file',
|
|
64
|
+
responseKey: 'url',
|
|
65
|
+
selectFileLabel: 'คลิกเพื่อเลือกไฟล์',
|
|
66
|
+
selectFileSubLabel: 'หรือ ลากและวางที่นี่',
|
|
67
|
+
retryLabel: 'ลองอีกครั้ง',
|
|
68
|
+
uploadingLabel: 'กำลังอัพโหลด...',
|
|
69
|
+
uploadFailedLabel: 'อัพโหลดล้มเหลว, กรุณาลองอีกครั้ง',
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const emits = defineEmits(['change', 'success', 'delete'])
|
|
73
|
+
const selectedFiles = ref<Array<{ file: File; key: string }>>([])
|
|
74
|
+
const { wrapperProps, handleChange: onChange, setErrors, value } = useFieldHOC<File[]>(props)
|
|
75
|
+
|
|
76
|
+
const { ui } = useUI('uploadFileDropzone', toRef(props, 'ui'), config)
|
|
77
|
+
|
|
78
|
+
const fileInputRef = ref<HTMLInputElement | null>()
|
|
79
|
+
const dropzoneRef = ref<HTMLDivElement>()
|
|
80
|
+
|
|
81
|
+
const acceptFile = computed(() =>
|
|
82
|
+
typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const onDrop = (files: File[] | null) => {
|
|
86
|
+
if (props.isDisabled || files?.length === 0 || !files) return
|
|
87
|
+
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
selectedFiles.value = [
|
|
90
|
+
{
|
|
91
|
+
file,
|
|
92
|
+
key: StringHelper.genString(),
|
|
93
|
+
},
|
|
94
|
+
...selectedFiles.value,
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
emits('change', value.value)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { isOverDropZone } = useDropZone(dropzoneRef as unknown as HTMLElement, {
|
|
102
|
+
onDrop,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const handleChange = (e: Event) => {
|
|
106
|
+
if (props.isDisabled) return
|
|
107
|
+
|
|
108
|
+
for (const file of (e.target as HTMLInputElement).files ?? []) {
|
|
109
|
+
selectedFiles.value = [
|
|
110
|
+
{
|
|
111
|
+
file,
|
|
112
|
+
key: StringHelper.genString(),
|
|
113
|
+
},
|
|
114
|
+
...selectedFiles.value,
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
emits('change', value.value)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fileInputRef.value?.value && (fileInputRef.value.value = '')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const handleOpenFile = () => {
|
|
124
|
+
fileInputRef.value?.click()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const handleDeleteFile = (index: number) => {
|
|
128
|
+
selectedFiles.value.splice(index, 1)
|
|
129
|
+
onChange(undefined)
|
|
130
|
+
emits('delete')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const handleError = (index: number, error: any) => {}
|
|
134
|
+
|
|
135
|
+
const handleSuccess = (index: number, any: any) => {
|
|
136
|
+
value.value = [_get(any, props.responseKey), ...(value.value || [])]
|
|
137
|
+
emits('change', value.value)
|
|
138
|
+
emits('success', value.value)
|
|
139
|
+
}
|
|
140
|
+
</script>
|
|
@@ -1,148 +1,148 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
-
<div class="space-y-3">
|
|
4
|
-
<div
|
|
5
|
-
ref="dropzoneRef"
|
|
6
|
-
:class="[
|
|
7
|
-
ui.base,
|
|
8
|
-
{
|
|
9
|
-
[ui.disabled]: isDisabled,
|
|
10
|
-
[ui.background.default]: !isOverDropZone && !isDisabled,
|
|
11
|
-
[ui.background.dragover]: isOverDropZone && !isDisabled,
|
|
12
|
-
},
|
|
13
|
-
]"
|
|
14
|
-
>
|
|
15
|
-
<input
|
|
16
|
-
ref="fileInputRef"
|
|
17
|
-
type="file"
|
|
18
|
-
class="hidden"
|
|
19
|
-
:name="name"
|
|
20
|
-
:accept="acceptFile"
|
|
21
|
-
:disabled="isDisabled"
|
|
22
|
-
multiple
|
|
23
|
-
@change="handleChange"
|
|
24
|
-
/>
|
|
25
|
-
<div :class="[ui.wrapper]">
|
|
26
|
-
<div v-if="selectedFiles.length === 0" :class="[ui.placeholderWrapper]">
|
|
27
|
-
<Icon :name="ui.default.uploadIcon" :class="[ui.labelIcon]" />
|
|
28
|
-
<div :class="[ui.labelWrapper]">
|
|
29
|
-
<p class="text-primary cursor-pointer" @click="handleOpenFile">
|
|
30
|
-
{{ selectFileLabel }}
|
|
31
|
-
</p>
|
|
32
|
-
<p>{{ selectFileSubLabel }}</p>
|
|
33
|
-
</div>
|
|
34
|
-
<p v-if="placeholder" :class="[ui.placeholder]">{{ placeholder }}</p>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<div v-else :class="ui.imageItemWrapper">
|
|
38
|
-
<Item
|
|
39
|
-
v-for="(file, index) in selectedFiles"
|
|
40
|
-
:key="file.key"
|
|
41
|
-
v-bind="$props"
|
|
42
|
-
:ui="ui"
|
|
43
|
-
:selected-file="file.file"
|
|
44
|
-
@success="handleSuccess(index, $event)"
|
|
45
|
-
@delete="handleDeleteFile(index)"
|
|
46
|
-
@error="handleError(index, $event)"
|
|
47
|
-
/>
|
|
48
|
-
<Item v-bind="$props" is-adding-btn :ui="ui" @add="handleOpenFile" />
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</FieldWrapper>
|
|
54
|
-
</template>
|
|
55
|
-
|
|
56
|
-
<script lang="ts" setup>
|
|
57
|
-
import { useDropZone } from '@vueuse/core'
|
|
58
|
-
import { type IUploadDropzoneImageAutoMultipleProps } from './types'
|
|
59
|
-
import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
|
|
60
|
-
import { useFieldHOC } from '#core/composables/useForm'
|
|
61
|
-
import { _get, computed, ref, toRef, StringHelper, useUI, useUiConfig } from '#imports'
|
|
62
|
-
import { uploadFileDropzoneImage } from '#core/ui.config'
|
|
63
|
-
import Item from './item.vue'
|
|
64
|
-
|
|
65
|
-
const config = useUiConfig<typeof uploadFileDropzoneImage>(
|
|
66
|
-
uploadFileDropzoneImage,
|
|
67
|
-
'uploadFileDropzoneImage'
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
const props = withDefaults(defineProps<IUploadDropzoneImageAutoMultipleProps>(), {
|
|
71
|
-
accept: 'image/*',
|
|
72
|
-
bodyKey: 'file',
|
|
73
|
-
responseKey: 'url',
|
|
74
|
-
selectFileLabel: 'คลิกเพื่อเลือกไฟล์',
|
|
75
|
-
selectFileSubLabel: 'หรือ ลากและวางที่นี่',
|
|
76
|
-
uploadAddLabel: 'อัพโหลด',
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
const emits = defineEmits(['change', 'success', 'delete'])
|
|
80
|
-
const selectedFiles = ref<Array<{ file: File; key: string }>>([])
|
|
81
|
-
|
|
82
|
-
const { wrapperProps, handleChange: onChange, value } = useFieldHOC<File[]>(props)
|
|
83
|
-
|
|
84
|
-
const { ui } = useUI('uploadFileDropzoneImage', toRef(props, 'ui'), config)
|
|
85
|
-
|
|
86
|
-
const fileInputRef = ref<HTMLInputElement | null>()
|
|
87
|
-
const dropzoneRef = ref<HTMLDivElement>()
|
|
88
|
-
|
|
89
|
-
const acceptFile = computed(() =>
|
|
90
|
-
typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
const onDrop = (files: File[] | null) => {
|
|
94
|
-
if (props.isDisabled || files?.length === 0 || !files) return
|
|
95
|
-
|
|
96
|
-
for (const file of files) {
|
|
97
|
-
selectedFiles.value = [
|
|
98
|
-
...selectedFiles.value,
|
|
99
|
-
{
|
|
100
|
-
file,
|
|
101
|
-
key: StringHelper.genString(),
|
|
102
|
-
},
|
|
103
|
-
]
|
|
104
|
-
|
|
105
|
-
emits('change', value.value)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const { isOverDropZone } = useDropZone(dropzoneRef as unknown as HTMLElement, {
|
|
110
|
-
onDrop,
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
const handleChange = (e: Event) => {
|
|
114
|
-
if (props.isDisabled) return
|
|
115
|
-
|
|
116
|
-
for (const file of (e.target as HTMLInputElement).files ?? []) {
|
|
117
|
-
selectedFiles.value = [
|
|
118
|
-
...selectedFiles.value,
|
|
119
|
-
{
|
|
120
|
-
file,
|
|
121
|
-
key: StringHelper.genString(),
|
|
122
|
-
},
|
|
123
|
-
]
|
|
124
|
-
|
|
125
|
-
emits('change', value.value)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
fileInputRef.value?.value && (fileInputRef.value.value = '')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const handleOpenFile = () => {
|
|
132
|
-
fileInputRef.value?.click()
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const handleDeleteFile = (index: number) => {
|
|
136
|
-
selectedFiles.value.splice(index, 1)
|
|
137
|
-
onChange(undefined)
|
|
138
|
-
emits('delete')
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const handleError = (index: number, error: any) => {}
|
|
142
|
-
|
|
143
|
-
const handleSuccess = (index: number, any: any) => {
|
|
144
|
-
value.value = [_get(any, props.responseKey), ...(value.value || [])]
|
|
145
|
-
emits('change', value.value)
|
|
146
|
-
emits('success', value.value)
|
|
147
|
-
}
|
|
148
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
+
<div class="space-y-3">
|
|
4
|
+
<div
|
|
5
|
+
ref="dropzoneRef"
|
|
6
|
+
:class="[
|
|
7
|
+
ui.base,
|
|
8
|
+
{
|
|
9
|
+
[ui.disabled]: isDisabled,
|
|
10
|
+
[ui.background.default]: !isOverDropZone && !isDisabled,
|
|
11
|
+
[ui.background.dragover]: isOverDropZone && !isDisabled,
|
|
12
|
+
},
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<input
|
|
16
|
+
ref="fileInputRef"
|
|
17
|
+
type="file"
|
|
18
|
+
class="hidden"
|
|
19
|
+
:name="name"
|
|
20
|
+
:accept="acceptFile"
|
|
21
|
+
:disabled="isDisabled"
|
|
22
|
+
multiple
|
|
23
|
+
@change="handleChange"
|
|
24
|
+
/>
|
|
25
|
+
<div :class="[ui.wrapper]">
|
|
26
|
+
<div v-if="selectedFiles.length === 0" :class="[ui.placeholderWrapper]">
|
|
27
|
+
<Icon :name="ui.default.uploadIcon" :class="[ui.labelIcon]" />
|
|
28
|
+
<div :class="[ui.labelWrapper]">
|
|
29
|
+
<p class="text-primary cursor-pointer" @click="handleOpenFile">
|
|
30
|
+
{{ selectFileLabel }}
|
|
31
|
+
</p>
|
|
32
|
+
<p>{{ selectFileSubLabel }}</p>
|
|
33
|
+
</div>
|
|
34
|
+
<p v-if="placeholder" :class="[ui.placeholder]">{{ placeholder }}</p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div v-else :class="ui.imageItemWrapper">
|
|
38
|
+
<Item
|
|
39
|
+
v-for="(file, index) in selectedFiles"
|
|
40
|
+
:key="file.key"
|
|
41
|
+
v-bind="$props"
|
|
42
|
+
:ui="ui"
|
|
43
|
+
:selected-file="file.file"
|
|
44
|
+
@success="handleSuccess(index, $event)"
|
|
45
|
+
@delete="handleDeleteFile(index)"
|
|
46
|
+
@error="handleError(index, $event)"
|
|
47
|
+
/>
|
|
48
|
+
<Item v-bind="$props" is-adding-btn :ui="ui" @add="handleOpenFile" />
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</FieldWrapper>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script lang="ts" setup>
|
|
57
|
+
import { useDropZone } from '@vueuse/core'
|
|
58
|
+
import { type IUploadDropzoneImageAutoMultipleProps } from './types'
|
|
59
|
+
import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
|
|
60
|
+
import { useFieldHOC } from '#core/composables/useForm'
|
|
61
|
+
import { _get, computed, ref, toRef, StringHelper, useUI, useUiConfig } from '#imports'
|
|
62
|
+
import { uploadFileDropzoneImage } from '#core/ui.config'
|
|
63
|
+
import Item from './item.vue'
|
|
64
|
+
|
|
65
|
+
const config = useUiConfig<typeof uploadFileDropzoneImage>(
|
|
66
|
+
uploadFileDropzoneImage,
|
|
67
|
+
'uploadFileDropzoneImage'
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const props = withDefaults(defineProps<IUploadDropzoneImageAutoMultipleProps>(), {
|
|
71
|
+
accept: 'image/*',
|
|
72
|
+
bodyKey: 'file',
|
|
73
|
+
responseKey: 'url',
|
|
74
|
+
selectFileLabel: 'คลิกเพื่อเลือกไฟล์',
|
|
75
|
+
selectFileSubLabel: 'หรือ ลากและวางที่นี่',
|
|
76
|
+
uploadAddLabel: 'อัพโหลด',
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const emits = defineEmits(['change', 'success', 'delete'])
|
|
80
|
+
const selectedFiles = ref<Array<{ file: File; key: string }>>([])
|
|
81
|
+
|
|
82
|
+
const { wrapperProps, handleChange: onChange, value } = useFieldHOC<File[]>(props)
|
|
83
|
+
|
|
84
|
+
const { ui } = useUI('uploadFileDropzoneImage', toRef(props, 'ui'), config)
|
|
85
|
+
|
|
86
|
+
const fileInputRef = ref<HTMLInputElement | null>()
|
|
87
|
+
const dropzoneRef = ref<HTMLDivElement>()
|
|
88
|
+
|
|
89
|
+
const acceptFile = computed(() =>
|
|
90
|
+
typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
const onDrop = (files: File[] | null) => {
|
|
94
|
+
if (props.isDisabled || files?.length === 0 || !files) return
|
|
95
|
+
|
|
96
|
+
for (const file of files) {
|
|
97
|
+
selectedFiles.value = [
|
|
98
|
+
...selectedFiles.value,
|
|
99
|
+
{
|
|
100
|
+
file,
|
|
101
|
+
key: StringHelper.genString(),
|
|
102
|
+
},
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
emits('change', value.value)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { isOverDropZone } = useDropZone(dropzoneRef as unknown as HTMLElement, {
|
|
110
|
+
onDrop,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const handleChange = (e: Event) => {
|
|
114
|
+
if (props.isDisabled) return
|
|
115
|
+
|
|
116
|
+
for (const file of (e.target as HTMLInputElement).files ?? []) {
|
|
117
|
+
selectedFiles.value = [
|
|
118
|
+
...selectedFiles.value,
|
|
119
|
+
{
|
|
120
|
+
file,
|
|
121
|
+
key: StringHelper.genString(),
|
|
122
|
+
},
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
emits('change', value.value)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fileInputRef.value?.value && (fileInputRef.value.value = '')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const handleOpenFile = () => {
|
|
132
|
+
fileInputRef.value?.click()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const handleDeleteFile = (index: number) => {
|
|
136
|
+
selectedFiles.value.splice(index, 1)
|
|
137
|
+
onChange(undefined)
|
|
138
|
+
emits('delete')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const handleError = (index: number, error: any) => {}
|
|
142
|
+
|
|
143
|
+
const handleSuccess = (index: number, any: any) => {
|
|
144
|
+
value.value = [_get(any, props.responseKey), ...(value.value || [])]
|
|
145
|
+
emits('change', value.value)
|
|
146
|
+
emits('success', value.value)
|
|
147
|
+
}
|
|
148
|
+
</script>
|