@finema/core 1.4.98 → 1.4.100

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.
Files changed (63) hide show
  1. package/README.md +60 -60
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +1 -1
  4. package/dist/runtime/components/Alert.vue +48 -48
  5. package/dist/runtime/components/Avatar.vue +27 -27
  6. package/dist/runtime/components/Badge.vue +11 -11
  7. package/dist/runtime/components/Breadcrumb.vue +44 -44
  8. package/dist/runtime/components/Button/Group.vue +37 -37
  9. package/dist/runtime/components/Button/index.vue +76 -76
  10. package/dist/runtime/components/Card.vue +38 -38
  11. package/dist/runtime/components/Core.vue +13 -13
  12. package/dist/runtime/components/Dialog/index.vue +108 -108
  13. package/dist/runtime/components/Dropdown/index.vue +70 -70
  14. package/dist/runtime/components/FlexDeck/Base.vue +90 -90
  15. package/dist/runtime/components/FlexDeck/index.vue +66 -66
  16. package/dist/runtime/components/Form/FieldWrapper.vue +23 -23
  17. package/dist/runtime/components/Form/Fields.vue +177 -177
  18. package/dist/runtime/components/Form/InputCheckbox/index.vue +21 -21
  19. package/dist/runtime/components/Form/InputDateTime/index.vue +60 -60
  20. package/dist/runtime/components/Form/InputNumber/index.vue +27 -27
  21. package/dist/runtime/components/Form/InputRadio/index.vue +27 -27
  22. package/dist/runtime/components/Form/InputSelect/index.vue +36 -36
  23. package/dist/runtime/components/Form/InputStatic/index.vue +16 -16
  24. package/dist/runtime/components/Form/InputText/index.vue +67 -67
  25. package/dist/runtime/components/Form/InputTextarea/index.vue +25 -25
  26. package/dist/runtime/components/Form/InputToggle/index.vue +14 -14
  27. package/dist/runtime/components/Form/InputUploadDropzone/index.vue +206 -205
  28. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +333 -355
  29. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/Item.vue +260 -283
  30. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +140 -126
  31. package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/index.vue +148 -134
  32. package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/item.vue +167 -198
  33. package/dist/runtime/components/Form/InputUploadFileClassic/index.vue +95 -103
  34. package/dist/runtime/components/Form/InputUploadFileClassicAuto/index.vue +143 -178
  35. package/dist/runtime/components/Form/index.vue +6 -6
  36. package/dist/runtime/components/Icon.vue +23 -23
  37. package/dist/runtime/components/Image.vue +36 -36
  38. package/dist/runtime/components/Loader.vue +27 -27
  39. package/dist/runtime/components/Modal/index.vue +146 -146
  40. package/dist/runtime/components/QRCode.vue +1 -1
  41. package/dist/runtime/components/SimplePagination.vue +96 -96
  42. package/dist/runtime/components/Slideover/index.vue +110 -110
  43. package/dist/runtime/components/Table/Base.vue +139 -139
  44. package/dist/runtime/components/Table/ColumnDate.vue +16 -16
  45. package/dist/runtime/components/Table/ColumnDateTime.vue +18 -18
  46. package/dist/runtime/components/Table/ColumnImage.vue +15 -15
  47. package/dist/runtime/components/Table/ColumnNumber.vue +14 -14
  48. package/dist/runtime/components/Table/ColumnText.vue +25 -25
  49. package/dist/runtime/components/Table/Simple.vue +69 -69
  50. package/dist/runtime/components/Table/index.vue +65 -65
  51. package/dist/runtime/components/Tabs/index.vue +64 -64
  52. package/dist/runtime/helpers/componentHelper.d.ts +18 -8
  53. package/dist/runtime/helpers/componentHelper.mjs +47 -8
  54. package/dist/runtime/utils/ArrayHelper.spec.mjs +1 -5
  55. package/dist/runtime/utils/FileHelper.spec.d.ts +1 -0
  56. package/dist/runtime/utils/FileHelper.spec.mjs +14 -0
  57. package/dist/runtime/utils/ObjectHelper.spec.d.ts +1 -0
  58. package/dist/runtime/utils/ObjectHelper.spec.mjs +52 -0
  59. package/dist/runtime/utils/ParamHelper.spec.d.ts +1 -0
  60. package/dist/runtime/utils/ParamHelper.spec.mjs +78 -0
  61. package/dist/runtime/utils/StringHelper.spec.d.ts +1 -0
  62. package/dist/runtime/utils/StringHelper.spec.mjs +76 -0
  63. package/package.json +89 -89
@@ -1,198 +1,167 @@
1
- <template>
2
- <div :class="[ui.imageItem.wrapper]">
3
- <div v-if="isAddingBtn" class="w-full">
4
- <div :class="[ui.action.addingWrapper]" @click="$emit('add')">
5
- <Icon :name="ui.action.addingIcon" :class="[ui.action.addingBtnClass]" />
6
- <p :class="[ui.action.addingTextClass]">{{ uploadAddLabel }}</p>
7
- </div>
8
- </div>
9
-
10
- <!-- Loading State -->
11
- <div v-if="selectedFile && upload.status.value.isLoading" class="w-full">
12
- <div :class="[ui.imageItem.onLoading.wrapper]">
13
- <div :class="[ui.imageItem.onLoading.percentClass]">{{ percent }}%</div>
14
- <UProgress :value="percent" />
15
- </div>
16
- </div>
17
-
18
- <!-- Success State -->
19
- <div v-if="selectedFile && upload.status.value.isSuccess" class="w-full">
20
- <div :class="[ui.imageItem.onPreview.wrapper]">
21
- <img
22
- :class="[ui.imageItem.onPreview.previewImgClass]"
23
- :src="upload.data.value[responseKey]"
24
- alt="img"
25
- />
26
- <div :class="[ui.imageItem.onPreview.previewActionWrapper]">
27
- <Icon
28
- title="ดูตัวอย่าง"
29
- :name="ui.action.previewIcon"
30
- :class="[ui.imageItem.onPreview.actionBtnClass]"
31
- @click="() => (isPreviewOpen = true)"
32
- />
33
- <Icon
34
- title="ลบไฟล์"
35
- :name="ui.action.deleteIcon"
36
- :class="[ui.imageItem.onPreview.actionBtnClass]"
37
- @click="handleDeleteFile"
38
- />
39
- <Modal v-model="isPreviewOpen" :title="selectedFile?.name">
40
- <img :src="upload.data.value[responseKey]" alt="image-preview" />
41
- </Modal>
42
- </div>
43
- </div>
44
-
45
- <div :class="[ui.imageItem.onPreview.previewTextWrapper]">
46
- <p :class="[ui.imageItem.onPreview.previewText]">{{ selectedFile.name }}</p>
47
- </div>
48
- </div>
49
-
50
- <!-- Failed State -->
51
- <div v-if="selectedFile && upload.status.value.isError" class="w-full">
52
- <div :class="[ui.imageItem.onFailed.wrapper]">
53
- <img
54
- :class="[ui.imageItem.onFailed.failedImgClass]"
55
- :src="generateURL(selectedFile)"
56
- alt="img"
57
- />
58
- <div :class="[ui.imageItem.onFailed.failedActionWrapper]">
59
- <Icon
60
- title="ลบไฟล์"
61
- :name="ui.action.deleteIcon"
62
- :class="[ui.imageItem.onFailed.actionBtnClass]"
63
- @click="handleDeleteFile"
64
- />
65
- </div>
66
- </div>
67
- </div>
68
- </div>
69
- </template>
70
-
71
- <script lang="ts" setup>
72
- import {
73
- checkFileType,
74
- checkMaxSize,
75
- generateURL,
76
- getFileAllocate,
77
- } from '#core/helpers/componentHelper'
78
- import { type uploadFileDropzoneImage } from '#core/ui.config'
79
- import type { IUploadDropzoneImageAutoMultipleProps } from '#core/components/Form/InputUploadDropzoneImageAutoMultiple/types'
80
- import {
81
- computed,
82
- type IUploadRequest,
83
- onMounted,
84
- ref,
85
- StringHelper,
86
- useUploadLoader,
87
- useWatchTrue,
88
- } from '#imports'
89
- import i18next from 'i18next'
90
-
91
- const emits = defineEmits(['success', 'error', 'delete', 'add'])
92
- const props = defineProps<
93
- {
94
- ui: typeof uploadFileDropzoneImage
95
- selectedFile?: File
96
- isAddingBtn?: boolean
97
- } & IUploadDropzoneImageAutoMultipleProps
98
- >()
99
-
100
- const request: IUploadRequest = {
101
- pathURL: props.uploadPathURL,
102
- requestOptions: props.requestOptions,
103
- }
104
-
105
- const isPreviewOpen = ref<boolean>(false)
106
- const percent = ref<number | string>(0)
107
- const upload = useUploadLoader(request)
108
- const errMsg = ref<string>('')
109
-
110
- const acceptFile = computed(() =>
111
- typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
112
- )
113
-
114
- const fileAllocate = computed(() =>
115
- getFileAllocate(props.maxSize ?? 0, props.selectedFile?.size ?? 0)
116
- )
117
-
118
- const handleDeleteFile = () => {
119
- emits('delete')
120
- }
121
-
122
- const onUploadProgress = (progressEvent: ProgressEvent) => {
123
- percent.value = StringHelper.withFixed(
124
- (Math.floor((progressEvent.loaded * 100) / progressEvent.total) || 0) * 0.8
125
- )
126
- }
127
-
128
- const onDownloadProgress = (progressEvent: ProgressEvent) => {
129
- if (progressEvent.total === 0) {
130
- percent.value = 100
131
-
132
- return
133
- }
134
-
135
- percent.value = StringHelper.withFixed(
136
- (Math.floor((progressEvent.loaded * 100) / progressEvent.total) || 0) * 0.2 + 80
137
- )
138
- }
139
-
140
- const handleCheckFileCondition = (file: File | undefined): boolean => {
141
- if (!file) return false
142
-
143
- const fileType = checkFileType(file, acceptFile.value ?? '')
144
-
145
- if (!fileType) {
146
- errMsg.value = i18next.t('custom:invalid_file_type')
147
-
148
- return false
149
- }
150
-
151
- const maxSize = checkMaxSize(file, fileAllocate.value.acceptFileSizeKb ?? 0)
152
-
153
- if (!maxSize) {
154
- if (fileAllocate.value.isAcceptFileUseMb) {
155
- errMsg.value = i18next.t('custom:invalid_file_size_mb', {
156
- size: fileAllocate.value.acceptFileSizeMb,
157
- })
158
- } else {
159
- errMsg.value = i18next.t('custom:invalid_file_size_kb', {
160
- size: fileAllocate.value.acceptFileSizeKb,
161
- })
162
- }
163
-
164
- return false
165
- }
166
-
167
- errMsg.value = ''
168
-
169
- return true
170
- }
171
-
172
- onMounted(() => {
173
- if (props.isAddingBtn) return
174
-
175
- const result = handleCheckFileCondition(props.selectedFile)
176
-
177
- if (result) {
178
- const formData = new FormData()
179
-
180
- formData.append(props.bodyKey!, props.selectedFile!)
181
- upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
182
- }
183
- })
184
-
185
- useWatchTrue(
186
- () => upload.status.value.isSuccess,
187
- () => {
188
- emits('success', upload.data.value)
189
- }
190
- )
191
-
192
- useWatchTrue(
193
- () => upload.status.value.isError,
194
- () => {
195
- emits('error', upload.status.value.errorData)
196
- }
197
- )
198
- </script>
1
+ <template>
2
+ <div :class="[ui.imageItem.wrapper]">
3
+ <div v-if="isAddingBtn" class="w-full">
4
+ <div :class="[ui.action.addingWrapper]" @click="$emit('add')">
5
+ <Icon :name="ui.action.addingIcon" :class="[ui.action.addingBtnClass]" />
6
+ <p :class="[ui.action.addingTextClass]">{{ uploadAddLabel }}</p>
7
+ </div>
8
+ </div>
9
+
10
+ <!-- Loading State -->
11
+ <div v-if="selectedFile && upload.status.value.isLoading" class="w-full">
12
+ <div :class="[ui.imageItem.onLoading.wrapper]">
13
+ <div :class="[ui.imageItem.onLoading.percentClass]">{{ percent }}%</div>
14
+ <UProgress :value="percent" />
15
+ </div>
16
+ </div>
17
+
18
+ <!-- Success State -->
19
+ <div v-if="selectedFile && upload.status.value.isSuccess" class="w-full">
20
+ <div :class="[ui.imageItem.onPreview.wrapper]">
21
+ <img
22
+ :class="[ui.imageItem.onPreview.previewImgClass]"
23
+ :src="upload.data.value[responseKey]"
24
+ alt="img"
25
+ />
26
+ <div :class="[ui.imageItem.onPreview.previewActionWrapper]">
27
+ <Icon
28
+ title="ดูตัวอย่าง"
29
+ :name="ui.action.previewIcon"
30
+ :class="[ui.imageItem.onPreview.actionBtnClass]"
31
+ @click="() => (isPreviewOpen = true)"
32
+ />
33
+ <Icon
34
+ title="ลบไฟล์"
35
+ :name="ui.action.deleteIcon"
36
+ :class="[ui.imageItem.onPreview.actionBtnClass]"
37
+ @click="handleDeleteFile"
38
+ />
39
+ <Modal v-model="isPreviewOpen" :title="selectedFile?.name">
40
+ <img :src="upload.data.value[responseKey]" alt="image-preview" />
41
+ </Modal>
42
+ </div>
43
+ </div>
44
+
45
+ <div :class="[ui.imageItem.onPreview.previewTextWrapper]">
46
+ <p :class="[ui.imageItem.onPreview.previewText]">{{ selectedFile.name }}</p>
47
+ </div>
48
+ </div>
49
+
50
+ <!-- Failed State -->
51
+ <div v-if="selectedFile && upload.status.value.isError" class="w-full">
52
+ <div :class="[ui.imageItem.onFailed.wrapper]">
53
+ <img
54
+ :class="[ui.imageItem.onFailed.failedImgClass]"
55
+ :src="generateURL(selectedFile)"
56
+ alt="img"
57
+ />
58
+ <div :class="[ui.imageItem.onFailed.failedActionWrapper]">
59
+ <Icon
60
+ title="ลบไฟล์"
61
+ :name="ui.action.deleteIcon"
62
+ :class="[ui.imageItem.onFailed.actionBtnClass]"
63
+ @click="handleDeleteFile"
64
+ />
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </template>
70
+
71
+ <script lang="ts" setup>
72
+ import {
73
+ checkFileType,
74
+ checkMaxSize,
75
+ generateURL,
76
+ useFileAllocate,
77
+ useFileProgress,
78
+ } from '#core/helpers/componentHelper'
79
+ import { type uploadFileDropzoneImage } from '#core/ui.config'
80
+ import type { IUploadDropzoneImageAutoMultipleProps } from '#core/components/Form/InputUploadDropzoneImageAutoMultiple/types'
81
+ import { type IUploadRequest, onMounted, ref, toRef, useUploadLoader, useWatchTrue } from '#imports'
82
+ import i18next from 'i18next'
83
+
84
+ const emits = defineEmits(['success', 'error', 'delete', 'add'])
85
+ const props = defineProps<
86
+ {
87
+ ui: typeof uploadFileDropzoneImage
88
+ selectedFile?: File
89
+ isAddingBtn?: boolean
90
+ } & IUploadDropzoneImageAutoMultipleProps
91
+ >()
92
+
93
+ const request: IUploadRequest = {
94
+ pathURL: props.uploadPathURL,
95
+ requestOptions: props.requestOptions,
96
+ }
97
+
98
+ const isPreviewOpen = ref<boolean>(false)
99
+ const upload = useUploadLoader(request)
100
+ const errMsg = ref<string>('')
101
+
102
+ const { onUploadProgress, onDownloadProgress, percent } = useFileProgress()
103
+ const fileAllocate = useFileAllocate(toRef(props.selectedFile), props)
104
+
105
+ const handleDeleteFile = () => {
106
+ emits('delete')
107
+ }
108
+
109
+ const handleCheckFileCondition = (file: File | undefined): boolean => {
110
+ if (!file) return false
111
+
112
+ const fileType = checkFileType(file, fileAllocate.acceptFile.value ?? '')
113
+
114
+ if (!fileType) {
115
+ errMsg.value = i18next.t('custom:invalid_file_type')
116
+
117
+ return false
118
+ }
119
+
120
+ const maxSize = checkMaxSize(file, fileAllocate.acceptFileSizeKb.value)
121
+
122
+ if (!maxSize) {
123
+ if (fileAllocate.isAcceptFileUseMb.value) {
124
+ errMsg.value = i18next.t('custom:invalid_file_size_mb', {
125
+ size: fileAllocate.acceptFileSizeMb.value,
126
+ })
127
+ } else {
128
+ errMsg.value = i18next.t('custom:invalid_file_size_kb', {
129
+ size: fileAllocate.acceptFileSizeKb.value,
130
+ })
131
+ }
132
+
133
+ return false
134
+ }
135
+
136
+ errMsg.value = ''
137
+
138
+ return true
139
+ }
140
+
141
+ onMounted(() => {
142
+ if (props.isAddingBtn) return
143
+
144
+ const result = handleCheckFileCondition(props.selectedFile)
145
+
146
+ if (result) {
147
+ const formData = new FormData()
148
+
149
+ formData.append(props.bodyKey!, props.selectedFile!)
150
+ upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
151
+ }
152
+ })
153
+
154
+ useWatchTrue(
155
+ () => upload.status.value.isSuccess,
156
+ () => {
157
+ emits('success', upload.data.value)
158
+ }
159
+ )
160
+
161
+ useWatchTrue(
162
+ () => upload.status.value.isError,
163
+ () => {
164
+ emits('error', upload.status.value.errorData)
165
+ }
166
+ )
167
+ </script>
@@ -1,103 +1,95 @@
1
- <template>
2
- <FieldWrapper v-bind="wrapperProps">
3
- <div :class="[ui.base]">
4
- <input
5
- ref="fileInput"
6
- type="file"
7
- class="hidden"
8
- :name="name"
9
- :accept="acceptFile"
10
- :disabled="isDisabled"
11
- @change="handleChange"
12
- />
13
- <div :class="[ui.wrapper]">
14
- <div :class="[ui.selectFileBox]">
15
- <Button size="2xs" @click="handleOpenFile">{{ selectFileLabel }}</Button>
16
- <p :class="ui.placeholder">
17
- {{ value?.name ?? placeholder ?? 'ยังไม่ได้เลือกไฟล์' }}
18
- </p>
19
- <Badge v-if="value" size="xs" variant="outline">
20
- {{ isSelectedFileUseMb ? `${selectedFileSizeMb} MB` : `${selectedFileSizeKb} KB` }}
21
- </Badge>
22
- </div>
23
- </div>
24
- </div>
25
- </FieldWrapper>
26
- </template>
27
- <script lang="ts" setup>
28
- import { useFieldHOC } from '#core/composables/useForm'
29
- import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
30
- import { type IUploadFileClassicFieldProps } from '#core/components/Form/InputUploadFileClassic/types'
31
- import { useUiConfig } from '#core/composables/useConfig'
32
- import { uploadFileInputClassicAuto } from '#core/ui.config'
33
- import { computed, ref, toRef, useUI } from '#imports'
34
- import i18next from 'i18next'
35
-
36
- const config = useUiConfig<typeof uploadFileInputClassicAuto>(
37
- uploadFileInputClassicAuto,
38
- 'uploadFileInputClassicAuto'
39
- )
40
-
41
- const emits = defineEmits(['change'])
42
- const props = withDefaults(defineProps<IUploadFileClassicFieldProps>(), {
43
- selectFileLabel: 'เลือกไฟล์',
44
- })
45
-
46
- const { value, wrapperProps, setErrors } = useFieldHOC<File | undefined>(props)
47
- const selectedFileSizeKb = computed(() => ((value.value?.size || 0) / 1000).toFixed(2))
48
- const selectedFileSizeMb = computed(() => ((value.value?.size || 0) / 1000 / 1000).toFixed(2))
49
-
50
- const isSelectedFileUseMb = computed(() => (value.value?.size || 0) / 1000 > 1024)
51
- const isAcceptFileUseMb = computed(() => acceptFileSizeKb.value && acceptFileSizeKb.value > 1024)
52
- const acceptFileSizeMb = computed(() => ((acceptFileSizeKb.value || 0) / 1024).toFixed(2))
53
- const acceptFileSizeKb = computed(() => props.maxSize)
54
- const acceptFile = computed(() =>
55
- typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
56
- )
57
-
58
- const fileInput = ref<HTMLInputElement>()
59
-
60
- const handleOpenFile = () => {
61
- fileInput.value?.click()
62
- }
63
-
64
- const { ui } = useUI('uploadFileInputClassicAuto', toRef(props, 'ui'), config)
65
-
66
- const checkMaxSize = (file: File): boolean => {
67
- if (acceptFileSizeKb.value) {
68
- return file.size / 1000 <= acceptFileSizeKb.value
69
- }
70
-
71
- return true
72
- }
73
-
74
- const handleCheckFileCondition = (file: File | undefined): boolean => {
75
- if (!file) return false
76
-
77
- const maxSize = checkMaxSize(file)
78
-
79
- if (!maxSize) {
80
- if (isAcceptFileUseMb.value) {
81
- setErrors(i18next.t('custom:invalid_file_size_mb', { size: acceptFileSizeMb.value }))
82
- } else {
83
- setErrors(i18next.t('custom:invalid_file_size_kb', { size: acceptFileSizeKb.value }))
84
- }
85
-
86
- return false
87
- }
88
-
89
- setErrors('')
90
-
91
- return true
92
- }
93
-
94
- const handleChange = (e: Event) => {
95
- const file = (e.target as HTMLInputElement).files?.[0]
96
- const result = handleCheckFileCondition(file)
97
-
98
- if (result && file) {
99
- value.value = file
100
- emits('change', file)
101
- }
102
- }
103
- </script>
1
+ <template>
2
+ <FieldWrapper v-bind="wrapperProps">
3
+ <div :class="[ui.base]">
4
+ <input
5
+ ref="fileInput"
6
+ type="file"
7
+ class="hidden"
8
+ :name="name"
9
+ :accept="fileAllocate.acceptFile.value"
10
+ :disabled="isDisabled"
11
+ @change="handleChange"
12
+ />
13
+ <div :class="[ui.wrapper]">
14
+ <div :class="[ui.selectFileBox]">
15
+ <Button size="2xs" @click="handleOpenFile">{{ selectFileLabel }}</Button>
16
+ <p :class="ui.placeholder">
17
+ {{ value?.name ?? placeholder ?? 'ยังไม่ได้เลือกไฟล์' }}
18
+ </p>
19
+ <Badge v-if="value" size="xs" variant="outline">
20
+ {{
21
+ fileAllocate.isSelectedFileUseMb.value
22
+ ? `${fileAllocate.selectedFileSizeMb.value} MB`
23
+ : `${fileAllocate.selectedFileSizeKb.value} KB`
24
+ }}
25
+ </Badge>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </FieldWrapper>
30
+ </template>
31
+ <script lang="ts" setup>
32
+ import { useFieldHOC } from '#core/composables/useForm'
33
+ import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
34
+ import { type IUploadFileClassicFieldProps } from '#core/components/Form/InputUploadFileClassic/types'
35
+ import { useUiConfig } from '#core/composables/useConfig'
36
+ import { uploadFileInputClassicAuto } from '#core/ui.config'
37
+ import { ref, toRef, useUI } from '#imports'
38
+ import i18next from 'i18next'
39
+ import { checkMaxSize, useFileAllocate } from '#core/helpers/componentHelper'
40
+
41
+ const config = useUiConfig<typeof uploadFileInputClassicAuto>(
42
+ uploadFileInputClassicAuto,
43
+ 'uploadFileInputClassicAuto'
44
+ )
45
+
46
+ const emits = defineEmits(['change'])
47
+ const props = withDefaults(defineProps<IUploadFileClassicFieldProps>(), {
48
+ selectFileLabel: 'เลือกไฟล์',
49
+ })
50
+
51
+ const { value, wrapperProps, setErrors } = useFieldHOC<File | undefined>(props)
52
+ const fileAllocate = useFileAllocate(value, props)
53
+
54
+ const fileInput = ref<HTMLInputElement>()
55
+
56
+ const handleOpenFile = () => {
57
+ fileInput.value?.click()
58
+ }
59
+
60
+ const { ui } = useUI('uploadFileInputClassicAuto', toRef(props, 'ui'), config)
61
+
62
+ const handleCheckFileCondition = (file: File | undefined): boolean => {
63
+ if (!file) return false
64
+
65
+ const maxSize = checkMaxSize(file, props.maxSize)
66
+
67
+ if (!maxSize) {
68
+ if (fileAllocate.isAcceptFileUseMb.value) {
69
+ setErrors(
70
+ i18next.t('custom:invalid_file_size_mb', { size: fileAllocate.acceptFileSizeMb.value })
71
+ )
72
+ } else {
73
+ setErrors(
74
+ i18next.t('custom:invalid_file_size_kb', { size: fileAllocate.acceptFileSizeKb.value })
75
+ )
76
+ }
77
+
78
+ return false
79
+ }
80
+
81
+ setErrors('')
82
+
83
+ return true
84
+ }
85
+
86
+ const handleChange = (e: Event) => {
87
+ const file = (e.target as HTMLInputElement).files?.[0]
88
+ const result = handleCheckFileCondition(file)
89
+
90
+ if (result && file) {
91
+ value.value = file
92
+ emits('change', file)
93
+ }
94
+ }
95
+ </script>