@finema/core 1.4.152 → 1.4.154

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 (168) hide show
  1. package/README.md +60 -60
  2. package/dist/module.json +1 -5
  3. package/dist/module.mjs +10 -2
  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 +75 -75
  10. package/dist/runtime/components/Card.vue +38 -38
  11. package/dist/runtime/components/Core.vue +37 -37
  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 +143 -143
  15. package/dist/runtime/components/FlexDeck/index.vue +68 -68
  16. package/dist/runtime/components/Form/FieldWrapper.vue +23 -23
  17. package/dist/runtime/components/Form/Fields.vue +230 -230
  18. package/dist/runtime/components/Form/InputCheckbox/index.vue +28 -28
  19. package/dist/runtime/components/Form/InputDateTime/index.vue +60 -60
  20. package/dist/runtime/components/Form/InputDateTimeRange/date_range_time_field.types.d.ts +1 -1
  21. package/dist/runtime/components/Form/InputDateTimeRange/index.vue +83 -83
  22. package/dist/runtime/components/Form/InputNumber/index.vue +27 -27
  23. package/dist/runtime/components/Form/InputRadio/index.vue +27 -27
  24. package/dist/runtime/components/Form/InputSelect/index.vue +45 -45
  25. package/dist/runtime/components/Form/InputSelectMultiple/index.vue +54 -54
  26. package/dist/runtime/components/Form/InputStatic/index.vue +16 -16
  27. package/dist/runtime/components/Form/InputTags/index.vue +145 -145
  28. package/dist/runtime/components/Form/InputText/index.vue +67 -67
  29. package/dist/runtime/components/Form/InputTextarea/index.vue +25 -25
  30. package/dist/runtime/components/Form/InputToggle/index.vue +14 -14
  31. package/dist/runtime/components/Form/InputUploadDropzone/index.vue +206 -206
  32. package/dist/runtime/components/Form/InputUploadDropzone/types.d.ts +1 -1
  33. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +342 -342
  34. package/dist/runtime/components/Form/InputUploadDropzoneAuto/types.d.ts +1 -1
  35. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/ItemUpload.vue +241 -241
  36. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/ItemView.vue +89 -89
  37. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +164 -164
  38. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/types.d.ts +1 -1
  39. package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/ItemUpload.vue +161 -161
  40. package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/ItemView.vue +64 -64
  41. package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/index.vue +172 -172
  42. package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/types.d.ts +1 -1
  43. package/dist/runtime/components/Form/InputUploadFileClassic/index.vue +95 -95
  44. package/dist/runtime/components/Form/InputUploadFileClassicAuto/index.vue +151 -151
  45. package/dist/runtime/components/Form/InputUploadFileClassicAuto/types.d.ts +1 -1
  46. package/dist/runtime/components/Form/InputUploadImageAuto/index.vue +219 -219
  47. package/dist/runtime/components/Form/InputUploadImageAuto/types.d.ts +1 -1
  48. package/dist/runtime/components/Form/InputWYSIWYG/index.vue +53 -53
  49. package/dist/runtime/components/Form/index.vue +6 -6
  50. package/dist/runtime/components/Icon.vue +23 -23
  51. package/dist/runtime/components/Image.vue +36 -36
  52. package/dist/runtime/components/Loader.vue +27 -27
  53. package/dist/runtime/components/Modal/index.vue +146 -146
  54. package/dist/runtime/components/QRCode.vue +22 -22
  55. package/dist/runtime/components/SimplePagination.vue +96 -96
  56. package/dist/runtime/components/Slideover/index.vue +110 -110
  57. package/dist/runtime/components/Table/Base.vue +139 -139
  58. package/dist/runtime/components/Table/ColumnDate.vue +16 -16
  59. package/dist/runtime/components/Table/ColumnDateTime.vue +18 -18
  60. package/dist/runtime/components/Table/ColumnImage.vue +15 -15
  61. package/dist/runtime/components/Table/ColumnNumber.vue +14 -14
  62. package/dist/runtime/components/Table/ColumnText.vue +25 -25
  63. package/dist/runtime/components/Table/Simple.vue +69 -69
  64. package/dist/runtime/components/Table/index.vue +65 -65
  65. package/dist/runtime/components/Tabs/index.vue +64 -64
  66. package/dist/runtime/components/TeleportSafe.vue +40 -40
  67. package/dist/runtime/composables/loaderList.d.ts +2 -2
  68. package/dist/runtime/composables/{loaderList.js → loaderList.mjs} +2 -2
  69. package/dist/runtime/composables/loaderObject.d.ts +1 -1
  70. package/dist/runtime/composables/{loaderObject.js → loaderObject.mjs} +2 -2
  71. package/dist/runtime/composables/loaderPage.d.ts +1 -1
  72. package/dist/runtime/composables/{loaderPage.js → loaderPage.mjs} +3 -3
  73. package/dist/runtime/composables/useConfig.d.ts +1 -1
  74. package/dist/runtime/composables/useForm.d.ts +1 -1
  75. package/dist/runtime/composables/useTable.d.ts +2 -2
  76. package/dist/runtime/composables/{useTable.js → useTable.mjs} +1 -1
  77. package/dist/runtime/composables/{useUpload.js → useUpload.mjs} +1 -1
  78. package/dist/runtime/helpers/{apiListHelper.js → apiListHelper.mjs} +1 -1
  79. package/dist/runtime/helpers/{apiObjectHelper.js → apiObjectHelper.mjs} +1 -1
  80. package/dist/runtime/helpers/apiPageHelper.d.ts +1 -1
  81. package/dist/runtime/helpers/{apiPageHelper.js → apiPageHelper.mjs} +4 -4
  82. package/dist/runtime/ui.config/index.d.ts +16 -16
  83. package/dist/runtime/ui.config/index.mjs +16 -0
  84. package/dist/runtime/ui.config/{uploadDropzoneImage.js → uploadDropzoneImage.mjs} +1 -1
  85. package/dist/runtime/utils/ArrayHelper.d.ts +1 -1
  86. package/dist/runtime/utils/{ArrayHelper.spec.js → ArrayHelper.spec.mjs} +1 -1
  87. package/dist/runtime/utils/{FileHelper.spec.js → FileHelper.spec.mjs} +1 -1
  88. package/dist/runtime/utils/ObjectHelper.d.ts +2 -2
  89. package/dist/runtime/utils/{ObjectHelper.js → ObjectHelper.mjs} +2 -2
  90. package/dist/runtime/utils/{ObjectHelper.spec.js → ObjectHelper.spec.mjs} +1 -1
  91. package/dist/runtime/utils/ParamHelper.d.ts +1 -1
  92. package/dist/runtime/utils/{ParamHelper.spec.js → ParamHelper.spec.mjs} +1 -1
  93. package/dist/runtime/utils/{StringHelper.spec.js → StringHelper.spec.mjs} +1 -1
  94. package/dist/runtime/utils/{TimeHelper.spec.js → TimeHelper.spec.mjs} +1 -1
  95. package/dist/runtime/utils/{TimeHelper.thai.spec.js → TimeHelper.thai.spec.mjs} +1 -1
  96. package/dist/types.d.mts +16 -1
  97. package/dist/types.d.ts +16 -1
  98. package/package.json +92 -93
  99. package/dist/runtime/ui.config/index.js +0 -16
  100. /package/dist/runtime/components/Dropdown/{types.js → types.mjs} +0 -0
  101. /package/dist/runtime/components/FlexDeck/{types.js → types.mjs} +0 -0
  102. /package/dist/runtime/components/Form/InputCheckbox/{types.js → types.mjs} +0 -0
  103. /package/dist/runtime/components/Form/InputDateTime/{date_time_field.types.js → date_time_field.types.mjs} +0 -0
  104. /package/dist/runtime/components/Form/InputDateTimeRange/{date_range_time_field.types.js → date_range_time_field.types.mjs} +0 -0
  105. /package/dist/runtime/components/Form/InputNumber/{types.js → types.mjs} +0 -0
  106. /package/dist/runtime/components/Form/InputRadio/{types.js → types.mjs} +0 -0
  107. /package/dist/runtime/components/Form/InputSelect/{types.js → types.mjs} +0 -0
  108. /package/dist/runtime/components/Form/InputSelectMultiple/{types.js → types.mjs} +0 -0
  109. /package/dist/runtime/components/Form/InputStatic/{types.js → types.mjs} +0 -0
  110. /package/dist/runtime/components/Form/InputTags/{types.js → types.mjs} +0 -0
  111. /package/dist/runtime/components/Form/InputText/{types.js → types.mjs} +0 -0
  112. /package/dist/runtime/components/Form/InputTextarea/{types.js → types.mjs} +0 -0
  113. /package/dist/runtime/components/Form/InputToggle/{types.js → types.mjs} +0 -0
  114. /package/dist/runtime/components/Form/InputUploadDropzone/{types.js → types.mjs} +0 -0
  115. /package/dist/runtime/components/Form/InputUploadDropzoneAuto/{types.js → types.mjs} +0 -0
  116. /package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/{types.js → types.mjs} +0 -0
  117. /package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/{types.js → types.mjs} +0 -0
  118. /package/dist/runtime/components/Form/InputUploadFileClassic/{types.js → types.mjs} +0 -0
  119. /package/dist/runtime/components/Form/InputUploadFileClassicAuto/{types.js → types.mjs} +0 -0
  120. /package/dist/runtime/components/Form/InputUploadImageAuto/{types.js → types.mjs} +0 -0
  121. /package/dist/runtime/components/Form/InputWYSIWYG/{types.js → types.mjs} +0 -0
  122. /package/dist/runtime/components/Form/{types.js → types.mjs} +0 -0
  123. /package/dist/runtime/components/Table/{types.js → types.mjs} +0 -0
  124. /package/dist/runtime/composables/{useApp.js → useApp.mjs} +0 -0
  125. /package/dist/runtime/composables/{useConfig.js → useConfig.mjs} +0 -0
  126. /package/dist/runtime/composables/{useDialog.js → useDialog.mjs} +0 -0
  127. /package/dist/runtime/composables/{useFlexDeck.js → useFlexDeck.mjs} +0 -0
  128. /package/dist/runtime/composables/{useForm.js → useForm.mjs} +0 -0
  129. /package/dist/runtime/composables/{useNotification.js → useNotification.mjs} +0 -0
  130. /package/dist/runtime/composables/{useWatch.js → useWatch.mjs} +0 -0
  131. /package/dist/runtime/{core.config.js → core.config.mjs} +0 -0
  132. /package/dist/runtime/helpers/{componentHelper.js → componentHelper.mjs} +0 -0
  133. /package/dist/runtime/lib/{Requester.js → Requester.mjs} +0 -0
  134. /package/dist/runtime/{plugin.js → plugin.mjs} +0 -0
  135. /package/dist/runtime/{quill.plugin.js → quill.plugin.mjs} +0 -0
  136. /package/dist/runtime/types/{common.js → common.mjs} +0 -0
  137. /package/dist/runtime/types/{config.js → config.mjs} +0 -0
  138. /package/dist/runtime/types/{lib.js → lib.mjs} +0 -0
  139. /package/dist/runtime/ui.config/{alert.js → alert.mjs} +0 -0
  140. /package/dist/runtime/ui.config/{badge.js → badge.mjs} +0 -0
  141. /package/dist/runtime/ui.config/{breadcrumb.js → breadcrumb.mjs} +0 -0
  142. /package/dist/runtime/ui.config/{button.js → button.mjs} +0 -0
  143. /package/dist/runtime/ui.config/{buttonGroup.js → buttonGroup.mjs} +0 -0
  144. /package/dist/runtime/ui.config/{card.js → card.mjs} +0 -0
  145. /package/dist/runtime/ui.config/{checkbox.js → checkbox.mjs} +0 -0
  146. /package/dist/runtime/ui.config/{formGroup.js → formGroup.mjs} +0 -0
  147. /package/dist/runtime/ui.config/{icon.js → icon.mjs} +0 -0
  148. /package/dist/runtime/ui.config/{input.js → input.mjs} +0 -0
  149. /package/dist/runtime/ui.config/{modal.js → modal.mjs} +0 -0
  150. /package/dist/runtime/ui.config/{notification.js → notification.mjs} +0 -0
  151. /package/dist/runtime/ui.config/{pagination.js → pagination.mjs} +0 -0
  152. /package/dist/runtime/ui.config/{select.js → select.mjs} +0 -0
  153. /package/dist/runtime/ui.config/{selectMenu.js → selectMenu.mjs} +0 -0
  154. /package/dist/runtime/ui.config/{slideover.js → slideover.mjs} +0 -0
  155. /package/dist/runtime/ui.config/{table.js → table.mjs} +0 -0
  156. /package/dist/runtime/ui.config/{tabs.js → tabs.mjs} +0 -0
  157. /package/dist/runtime/ui.config/{tags.js → tags.mjs} +0 -0
  158. /package/dist/runtime/ui.config/{textarea.js → textarea.mjs} +0 -0
  159. /package/dist/runtime/ui.config/{toggle.js → toggle.mjs} +0 -0
  160. /package/dist/runtime/ui.config/{uploadFileDropzone.js → uploadFileDropzone.mjs} +0 -0
  161. /package/dist/runtime/ui.config/{uploadFileInputClassicAuto.js → uploadFileInputClassicAuto.mjs} +0 -0
  162. /package/dist/runtime/ui.config/{uploadImage.js → uploadImage.mjs} +0 -0
  163. /package/dist/runtime/utils/{ArrayHelper.js → ArrayHelper.mjs} +0 -0
  164. /package/dist/runtime/utils/{FileHelper.js → FileHelper.mjs} +0 -0
  165. /package/dist/runtime/utils/{ParamHelper.js → ParamHelper.mjs} +0 -0
  166. /package/dist/runtime/utils/{StringHelper.js → StringHelper.mjs} +0 -0
  167. /package/dist/runtime/utils/{TimeHelper.js → TimeHelper.mjs} +0 -0
  168. /package/dist/runtime/utils/{lodash.js → lodash.mjs} +0 -0
@@ -1,219 +1,219 @@
1
- <template>
2
- <FieldWrapper v-bind="wrapperProps">
3
- <div :class="[ui.base]">
4
- <input
5
- ref="fileInputRef"
6
- type="file"
7
- class="hidden"
8
- :name="name"
9
- :accept="acceptFile"
10
- :disabled="isDisabled"
11
- @change="handleChange"
12
- />
13
-
14
- <div :class="[ui.imageItem.wrapper]">
15
- <div v-if="!selectedFile && !value" class="w-full">
16
- <div :class="[ui.action.addingWrapper]" @click="handleOpenFile">
17
- <Icon :name="ui.action.addingIcon" :class="[ui.action.addingBtnClass]" />
18
- <p :class="[ui.action.addingTextClass]">{{ uploadAddLabel }}</p>
19
- </div>
20
- </div>
21
-
22
- <!-- Loading State -->
23
- <div v-if="selectedFile && upload.status.value.isLoading" class="w-full">
24
- <div :class="[ui.imageItem.onLoading.wrapper]">
25
- <div :class="[ui.imageItem.onLoading.percentClass]">{{ percent }}%</div>
26
- <UProgress :value="percent" />
27
- </div>
28
- </div>
29
-
30
- <!-- Success State -->
31
- <div v-if="(selectedFile && upload.status.value.isSuccess) || value" class="w-full">
32
- <div :class="[ui.imageItem.onPreview.wrapper]">
33
- <img :class="[ui.imageItem.onPreview.previewImgClass]" :src="value?.url" alt="img" />
34
- <div :class="[ui.imageItem.onPreview.previewActionWrapper]">
35
- <Icon
36
- title="ดูตัวอย่าง"
37
- :name="ui.action.previewIcon"
38
- :class="[ui.imageItem.onPreview.actionBtnClass]"
39
- @click="() => (isPreviewOpen = true)"
40
- />
41
- <Icon
42
- title="ลบไฟล์"
43
- :name="ui.action.deleteIcon"
44
- :class="[ui.imageItem.onPreview.actionBtnClass]"
45
- @click="handleDeleteFile"
46
- />
47
- <Modal v-model="isPreviewOpen" size="xl">
48
- <div class="absolute -top-8 left-0 flex w-full justify-between text-gray-600">
49
- <p>{{ selectedFile?.name }}</p>
50
- <Icon
51
- name="i-heroicons-x-mark"
52
- class="size-6 cursor-pointer hover:text-gray-400"
53
- @click="() => (isPreviewOpen = false)"
54
- />
55
- </div>
56
- <img :src="value?.url" alt="img-preview" class="w-full rounded-lg" />
57
- </Modal>
58
- </div>
59
- </div>
60
-
61
- <div v-if="selectedFile" :class="[ui.imageItem.onPreview.previewTextWrapper]">
62
- <p :class="[ui.imageItem.onPreview.previewText]">{{ selectedFile.name }}</p>
63
- </div>
64
- </div>
65
-
66
- <!-- Failed State -->
67
- <div v-if="selectedFile && upload.status.value.isError" class="w-full">
68
- <div :class="[ui.imageItem.onFailed.wrapper]">
69
- <img
70
- :class="[ui.imageItem.onFailed.failedImgClass]"
71
- :src="generateURL(selectedFile)"
72
- alt="img"
73
- />
74
- <div :class="[ui.imageItem.onFailed.failedActionWrapper]">
75
- <Icon
76
- title="ลบไฟล์"
77
- :name="ui.action.deleteIcon"
78
- :class="[ui.imageItem.onFailed.actionBtnClass]"
79
- @click="handleDeleteFile"
80
- />
81
- </div>
82
- </div>
83
- </div>
84
- </div>
85
- </div>
86
- </FieldWrapper>
87
- </template>
88
-
89
- <script lang="ts" setup>
90
- import { type IUploadImageAutoProps } from './types'
91
- import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
92
- import { useFieldHOC } from '#core/composables/useForm'
93
- import {
94
- computed,
95
- ref,
96
- toRef,
97
- useUI,
98
- useUiConfig,
99
- useWatchTrue,
100
- useUploadLoader,
101
- _get,
102
- type IUploadRequest,
103
- } from '#imports'
104
- import { uploadImage } from '#core/ui.config'
105
- import {
106
- checkMaxSize,
107
- generateURL,
108
- useFileAllocate,
109
- useFileProgress,
110
- } from '#core/helpers/componentHelper'
111
- import type { IFileValue } from '#core/components/Form/types'
112
- import i18next from 'i18next'
113
-
114
- const config = useUiConfig<typeof uploadImage>(uploadImage, 'uploadImage')
115
-
116
- const props = withDefaults(defineProps<IUploadImageAutoProps>(), {
117
- accept: 'image/*',
118
- bodyKey: 'file',
119
- responseURL: 'url',
120
- responsePath: 'path',
121
- uploadAddLabel: 'อัพโหลด',
122
- })
123
-
124
- const emits = defineEmits(['change', 'success', 'delete', 'error'])
125
-
126
- const request: IUploadRequest = {
127
- pathURL: props.uploadPathURL,
128
- requestOptions: props.requestOptions,
129
- }
130
-
131
- const selectedFile = ref<File>()
132
- const isPreviewOpen = ref<boolean>(false)
133
-
134
- const { wrapperProps, value, errorMessage } = useFieldHOC<IFileValue | undefined>(props)
135
-
136
- const upload = useUploadLoader(request)
137
- const { ui } = useUI('uploadImage', toRef(props, 'ui'), config)
138
-
139
- const fileInputRef = ref<HTMLInputElement | null>()
140
-
141
- const fileAllocate = useFileAllocate(toRef(selectedFile), props)
142
- const { onUploadProgress, onDownloadProgress, percent } = useFileProgress()
143
- const acceptFile = computed(() =>
144
- typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
145
- )
146
-
147
- const handleChange = (e: Event) => {
148
- if (props.isDisabled) return
149
-
150
- const file = (e.target as HTMLInputElement).files?.[0]
151
- const result = handleCheckFileCondition(file)
152
-
153
- if (result && file) {
154
- selectedFile.value = file
155
- emits('change', selectedFile.value)
156
- const formData = new FormData()
157
-
158
- formData.append(props.bodyKey, file)
159
- upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
160
- }
161
- }
162
-
163
- const handleCheckFileCondition = (file: File | undefined): boolean => {
164
- if (!file) return false
165
- const maxSize = checkMaxSize(file, fileAllocate.acceptFileSizeKb.value)
166
-
167
- if (!maxSize) {
168
- if (fileAllocate.isAcceptFileUseMb.value) {
169
- errorMessage.value = i18next.t('custom:invalid_file_size_mb', {
170
- size: fileAllocate.acceptFileSizeMb.value,
171
- })
172
- } else {
173
- errorMessage.value = i18next.t('custom:invalid_file_size_kb', {
174
- size: fileAllocate.acceptFileSizeKb.value,
175
- })
176
- }
177
-
178
- return false
179
- }
180
-
181
- errorMessage.value = ''
182
-
183
- return true
184
- }
185
-
186
- const handleOpenFile = () => {
187
- fileInputRef.value?.click()
188
- }
189
-
190
- const handleDeleteFile = () => {
191
- fileInputRef.value!.value = ''
192
- selectedFile.value = undefined
193
- value.value = undefined
194
- emits('change', undefined)
195
-
196
- emits('delete')
197
- }
198
-
199
- useWatchTrue(
200
- () => upload.status.value.isSuccess,
201
- () => {
202
- value.value = {
203
- url: _get(upload.data.value, props.responseURL),
204
- path: _get(upload.data.value, props.responsePath),
205
- name: upload.data.value.name,
206
- size: upload.data.value.size,
207
- }
208
-
209
- emits('success', value.value)
210
- }
211
- )
212
-
213
- useWatchTrue(
214
- () => upload.status.value.isError,
215
- () => {
216
- emits('error', upload.status.value.errorData)
217
- }
218
- )
219
- </script>
1
+ <template>
2
+ <FieldWrapper v-bind="wrapperProps">
3
+ <div :class="[ui.base]">
4
+ <input
5
+ ref="fileInputRef"
6
+ type="file"
7
+ class="hidden"
8
+ :name="name"
9
+ :accept="acceptFile"
10
+ :disabled="isDisabled"
11
+ @change="handleChange"
12
+ />
13
+
14
+ <div :class="[ui.imageItem.wrapper]">
15
+ <div v-if="!selectedFile && !value" class="w-full">
16
+ <div :class="[ui.action.addingWrapper]" @click="handleOpenFile">
17
+ <Icon :name="ui.action.addingIcon" :class="[ui.action.addingBtnClass]" />
18
+ <p :class="[ui.action.addingTextClass]">{{ uploadAddLabel }}</p>
19
+ </div>
20
+ </div>
21
+
22
+ <!-- Loading State -->
23
+ <div v-if="selectedFile && upload.status.value.isLoading" class="w-full">
24
+ <div :class="[ui.imageItem.onLoading.wrapper]">
25
+ <div :class="[ui.imageItem.onLoading.percentClass]">{{ percent }}%</div>
26
+ <UProgress :value="percent" />
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Success State -->
31
+ <div v-if="(selectedFile && upload.status.value.isSuccess) || value" class="w-full">
32
+ <div :class="[ui.imageItem.onPreview.wrapper]">
33
+ <img :class="[ui.imageItem.onPreview.previewImgClass]" :src="value?.url" alt="img" />
34
+ <div :class="[ui.imageItem.onPreview.previewActionWrapper]">
35
+ <Icon
36
+ title="ดูตัวอย่าง"
37
+ :name="ui.action.previewIcon"
38
+ :class="[ui.imageItem.onPreview.actionBtnClass]"
39
+ @click="() => (isPreviewOpen = true)"
40
+ />
41
+ <Icon
42
+ title="ลบไฟล์"
43
+ :name="ui.action.deleteIcon"
44
+ :class="[ui.imageItem.onPreview.actionBtnClass]"
45
+ @click="handleDeleteFile"
46
+ />
47
+ <Modal v-model="isPreviewOpen" size="xl">
48
+ <div class="absolute -top-8 left-0 flex w-full justify-between text-gray-600">
49
+ <p>{{ selectedFile?.name }}</p>
50
+ <Icon
51
+ name="i-heroicons-x-mark"
52
+ class="size-6 cursor-pointer hover:text-gray-400"
53
+ @click="() => (isPreviewOpen = false)"
54
+ />
55
+ </div>
56
+ <img :src="value?.url" alt="img-preview" class="w-full rounded-lg" />
57
+ </Modal>
58
+ </div>
59
+ </div>
60
+
61
+ <div v-if="selectedFile" :class="[ui.imageItem.onPreview.previewTextWrapper]">
62
+ <p :class="[ui.imageItem.onPreview.previewText]">{{ selectedFile.name }}</p>
63
+ </div>
64
+ </div>
65
+
66
+ <!-- Failed State -->
67
+ <div v-if="selectedFile && upload.status.value.isError" class="w-full">
68
+ <div :class="[ui.imageItem.onFailed.wrapper]">
69
+ <img
70
+ :class="[ui.imageItem.onFailed.failedImgClass]"
71
+ :src="generateURL(selectedFile)"
72
+ alt="img"
73
+ />
74
+ <div :class="[ui.imageItem.onFailed.failedActionWrapper]">
75
+ <Icon
76
+ title="ลบไฟล์"
77
+ :name="ui.action.deleteIcon"
78
+ :class="[ui.imageItem.onFailed.actionBtnClass]"
79
+ @click="handleDeleteFile"
80
+ />
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ </FieldWrapper>
87
+ </template>
88
+
89
+ <script lang="ts" setup>
90
+ import { type IUploadImageAutoProps } from './types'
91
+ import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
92
+ import { useFieldHOC } from '#core/composables/useForm'
93
+ import {
94
+ computed,
95
+ ref,
96
+ toRef,
97
+ useUI,
98
+ useUiConfig,
99
+ useWatchTrue,
100
+ useUploadLoader,
101
+ _get,
102
+ type IUploadRequest,
103
+ } from '#imports'
104
+ import { uploadImage } from '#core/ui.config'
105
+ import {
106
+ checkMaxSize,
107
+ generateURL,
108
+ useFileAllocate,
109
+ useFileProgress,
110
+ } from '#core/helpers/componentHelper'
111
+ import type { IFileValue } from '#core/components/Form/types'
112
+ import i18next from 'i18next'
113
+
114
+ const config = useUiConfig<typeof uploadImage>(uploadImage, 'uploadImage')
115
+
116
+ const props = withDefaults(defineProps<IUploadImageAutoProps>(), {
117
+ accept: 'image/*',
118
+ bodyKey: 'file',
119
+ responseURL: 'url',
120
+ responsePath: 'path',
121
+ uploadAddLabel: 'อัพโหลด',
122
+ })
123
+
124
+ const emits = defineEmits(['change', 'success', 'delete', 'error'])
125
+
126
+ const request: IUploadRequest = {
127
+ pathURL: props.uploadPathURL,
128
+ requestOptions: props.requestOptions,
129
+ }
130
+
131
+ const selectedFile = ref<File>()
132
+ const isPreviewOpen = ref<boolean>(false)
133
+
134
+ const { wrapperProps, value, errorMessage } = useFieldHOC<IFileValue | undefined>(props)
135
+
136
+ const upload = useUploadLoader(request)
137
+ const { ui } = useUI('uploadImage', toRef(props, 'ui'), config)
138
+
139
+ const fileInputRef = ref<HTMLInputElement | null>()
140
+
141
+ const fileAllocate = useFileAllocate(toRef(selectedFile), props)
142
+ const { onUploadProgress, onDownloadProgress, percent } = useFileProgress()
143
+ const acceptFile = computed(() =>
144
+ typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
145
+ )
146
+
147
+ const handleChange = (e: Event) => {
148
+ if (props.isDisabled) return
149
+
150
+ const file = (e.target as HTMLInputElement).files?.[0]
151
+ const result = handleCheckFileCondition(file)
152
+
153
+ if (result && file) {
154
+ selectedFile.value = file
155
+ emits('change', selectedFile.value)
156
+ const formData = new FormData()
157
+
158
+ formData.append(props.bodyKey, file)
159
+ upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
160
+ }
161
+ }
162
+
163
+ const handleCheckFileCondition = (file: File | undefined): boolean => {
164
+ if (!file) return false
165
+ const maxSize = checkMaxSize(file, fileAllocate.acceptFileSizeKb.value)
166
+
167
+ if (!maxSize) {
168
+ if (fileAllocate.isAcceptFileUseMb.value) {
169
+ errorMessage.value = i18next.t('custom:invalid_file_size_mb', {
170
+ size: fileAllocate.acceptFileSizeMb.value,
171
+ })
172
+ } else {
173
+ errorMessage.value = i18next.t('custom:invalid_file_size_kb', {
174
+ size: fileAllocate.acceptFileSizeKb.value,
175
+ })
176
+ }
177
+
178
+ return false
179
+ }
180
+
181
+ errorMessage.value = ''
182
+
183
+ return true
184
+ }
185
+
186
+ const handleOpenFile = () => {
187
+ fileInputRef.value?.click()
188
+ }
189
+
190
+ const handleDeleteFile = () => {
191
+ fileInputRef.value!.value = ''
192
+ selectedFile.value = undefined
193
+ value.value = undefined
194
+ emits('change', undefined)
195
+
196
+ emits('delete')
197
+ }
198
+
199
+ useWatchTrue(
200
+ () => upload.status.value.isSuccess,
201
+ () => {
202
+ value.value = {
203
+ url: _get(upload.data.value, props.responseURL),
204
+ path: _get(upload.data.value, props.responsePath),
205
+ name: upload.data.value.name,
206
+ size: upload.data.value.size,
207
+ }
208
+
209
+ emits('success', value.value)
210
+ }
211
+ )
212
+
213
+ useWatchTrue(
214
+ () => upload.status.value.isError,
215
+ () => {
216
+ emits('error', upload.status.value.errorData)
217
+ }
218
+ )
219
+ </script>
@@ -1,5 +1,5 @@
1
1
  import { type AxiosRequestConfig } from 'axios';
2
- import { type IFieldProps, type IFormFieldBase, type INPUT_TYPES } from '../types.js';
2
+ import { type IFieldProps, type IFormFieldBase, type INPUT_TYPES } from '../types';
3
3
  export interface IUploadImageAutoProps extends IFieldProps {
4
4
  requestOptions: Omit<AxiosRequestConfig, 'baseURL'> & {
5
5
  baseURL: string;
@@ -1,55 +1,55 @@
1
- <template>
2
- <FieldWrapper v-bind="wrapperProps">
3
- <ClientOnly>
4
- <QuillEditor
5
- v-model:content="value"
6
- :placeholder="placeholder ?? label"
7
- :autofocus="autoFocus"
8
- :disabled="isDisabled || isReadonly"
9
- :name="name"
10
- class="ql-snow focus:ring-primary-500 min-h-[300px] rounded-b-md ring-1 ring-inset ring-gray-300 focus:ring-2"
11
- content-type="html"
12
- :options="options"
13
- />
14
- </ClientOnly>
15
- </FieldWrapper>
16
- </template>
17
- <script lang="ts" setup>
18
- import { useFieldHOC } from '#core/composables/useForm'
19
- import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
20
- import '@vueup/vue-quill/dist/vue-quill.snow.css'
21
- import type { IWYSIWYGFieldProps } from '#core/components/Form/InputWYSIWYG/types'
22
-
23
- const props = withDefaults(defineProps<IWYSIWYGFieldProps>(), {})
24
- const { value, wrapperProps } = useFieldHOC<string>(props)
25
-
26
- const options = {
27
- modules: {
28
- toolbar: [
29
- // [{ size: ['small', false, 'large', 'huge'] }], // custom dropdown
30
- ['bold', 'italic', 'underline'], // toggled buttons
31
- // ['blockquote', 'code-block'],
32
- // ['link', 'image', 'video'], // link and image, video
33
- ['link'],
34
-
35
- // [{ header: 1 }, { header: 2 }], // custom button values
36
- // [{ list: 'ordered' }, { list: 'bullet' }],
37
- // [{ script: 'sub' }, { script: 'super' }], // superscript/subscript
38
- // [{ indent: '-1' }, { indent: '+1' }], // outdent/indent
39
- // [{ direction: 'rtl' }], // text direction
40
-
41
- // [{ header: [1, 2, 3, 4, 5, 6, false] }],
42
-
43
- [{ color: [] }, { background: [] }], // dropdown with defaults from theme
44
- // [{ font: [] }],
45
- // [{ align: [] }],
46
- //
47
- ['clean'], // remove formatting button
48
- ],
49
- },
50
- theme: 'snow',
51
- }
52
- </script>
1
+ <template>
2
+ <FieldWrapper v-bind="wrapperProps">
3
+ <ClientOnly>
4
+ <QuillEditor
5
+ v-model:content="value"
6
+ :placeholder="placeholder ?? label"
7
+ :autofocus="autoFocus"
8
+ :disabled="isDisabled || isReadonly"
9
+ :name="name"
10
+ class="ql-snow focus:ring-primary-500 min-h-[300px] rounded-b-md ring-1 ring-inset ring-gray-300 focus:ring-2"
11
+ content-type="html"
12
+ :options="options"
13
+ />
14
+ </ClientOnly>
15
+ </FieldWrapper>
16
+ </template>
17
+ <script lang="ts" setup>
18
+ import { useFieldHOC } from '#core/composables/useForm'
19
+ import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
20
+ import '@vueup/vue-quill/dist/vue-quill.snow.css'
21
+ import type { IWYSIWYGFieldProps } from '#core/components/Form/InputWYSIWYG/types'
22
+
23
+ const props = withDefaults(defineProps<IWYSIWYGFieldProps>(), {})
24
+ const { value, wrapperProps } = useFieldHOC<string>(props)
25
+
26
+ const options = {
27
+ modules: {
28
+ toolbar: [
29
+ // [{ size: ['small', false, 'large', 'huge'] }], // custom dropdown
30
+ ['bold', 'italic', 'underline'], // toggled buttons
31
+ // ['blockquote', 'code-block'],
32
+ // ['link', 'image', 'video'], // link and image, video
33
+ ['link'],
34
+
35
+ // [{ header: 1 }, { header: 2 }], // custom button values
36
+ // [{ list: 'ordered' }, { list: 'bullet' }],
37
+ // [{ script: 'sub' }, { script: 'super' }], // superscript/subscript
38
+ // [{ indent: '-1' }, { indent: '+1' }], // outdent/indent
39
+ // [{ direction: 'rtl' }], // text direction
40
+
41
+ // [{ header: [1, 2, 3, 4, 5, 6, false] }],
42
+
43
+ [{ color: [] }, { background: [] }], // dropdown with defaults from theme
44
+ // [{ font: [] }],
45
+ // [{ align: [] }],
46
+ //
47
+ ['clean'], // remove formatting button
48
+ ],
49
+ },
50
+ theme: 'snow',
51
+ }
52
+ </script>
53
53
  <style>
54
54
  .ql-toolbar.ql-snow{@apply rounded-t-md border-b-0}.ql-container.ql-snow,.ql-snow{@apply border-0}
55
- </style>
55
+ </style>
@@ -1,6 +1,6 @@
1
- <template>
2
- <form class="form">
3
- <slot />
4
- </form>
5
- </template>
6
- <script lang="ts" setup></script>
1
+ <template>
2
+ <form class="form">
3
+ <slot />
4
+ </form>
5
+ </template>
6
+ <script lang="ts" setup></script>
@@ -1,23 +1,23 @@
1
- <template>
2
- <UIcon :name="name" :dynamic="dynamicValue" />
3
- </template>
4
-
5
- <script lang="ts" setup>
6
- import { computed, useUiConfig } from '#imports'
7
- import { icon } from '#core/ui.config'
8
-
9
- const props = defineProps({
10
- name: {
11
- type: String,
12
- required: true,
13
- },
14
- dynamic: {
15
- type: Boolean,
16
- default: true,
17
- },
18
- })
19
-
20
- const config = useUiConfig<typeof icon>(icon, 'icon')
21
-
22
- const dynamicValue = computed(() => props.dynamic || config.dynamic)
23
- </script>
1
+ <template>
2
+ <UIcon :name="name" :dynamic="dynamicValue" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import { computed, useUiConfig } from '#imports'
7
+ import { icon } from '#core/ui.config'
8
+
9
+ const props = defineProps({
10
+ name: {
11
+ type: String,
12
+ required: true,
13
+ },
14
+ dynamic: {
15
+ type: Boolean,
16
+ default: true,
17
+ },
18
+ })
19
+
20
+ const config = useUiConfig<typeof icon>(icon, 'icon')
21
+
22
+ const dynamicValue = computed(() => props.dynamic || config.dynamic)
23
+ </script>