@finema/core 1.4.50 → 1.4.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.d.mts CHANGED
@@ -9,6 +9,7 @@ declare const core: {
9
9
  is_thai_year: boolean;
10
10
  is_thai_month: boolean;
11
11
  site_name: string;
12
+ is_simple_pagination: boolean;
12
13
  };
13
14
 
14
15
  declare const config_core: typeof core;
package/dist/module.d.ts CHANGED
@@ -9,6 +9,7 @@ declare const core: {
9
9
  is_thai_year: boolean;
10
10
  is_thai_month: boolean;
11
11
  site_name: string;
12
+ is_simple_pagination: boolean;
12
13
  };
13
14
 
14
15
  declare const config_core: typeof core;
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finema/core",
3
- "version": "1.4.50",
3
+ "version": "1.4.52",
4
4
  "configKey": "core",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.7.4"
package/dist/module.mjs CHANGED
@@ -2,7 +2,7 @@ import { defineNuxtModule, createResolver, installModule, addPlugin, addComponen
2
2
  import 'lodash-es';
3
3
 
4
4
  const name = "@finema/core";
5
- const version = "1.4.50";
5
+ const version = "1.4.52";
6
6
 
7
7
  const colors = {
8
8
  black: "#20243E",
@@ -107,6 +107,14 @@
107
107
  v-bind="getFieldBinding(option)"
108
108
  v-on="option.on ?? {}"
109
109
  />
110
+ <FormInputUploadDropzoneAuto
111
+ v-else-if="option.type === INPUT_TYPES.UPLOAD_DROPZONE_AUTO"
112
+ :class="option.class"
113
+ :form="form"
114
+ :request-options="option.props.requestOptions"
115
+ v-bind="getFieldBinding(option)"
116
+ v-on="option.on ?? {}"
117
+ />
110
118
  </template>
111
119
  </div>
112
120
  </template>
@@ -10,7 +10,6 @@
10
10
  :searchable-placeholder="searchablePlaceholder"
11
11
  value-attribute="value"
12
12
  option-attribute="label"
13
- :required="isRequired"
14
13
  :icon="icon"
15
14
  :color="color"
16
15
  :size="size"
@@ -32,11 +32,11 @@
32
32
  </div>
33
33
  <Icon v-else :name="ui.default.filePreviewIcon" :class="[ui.preview.icon]" />
34
34
  <div :class="[ui.preview.filename]">
35
- <p>{{ selectedFile.name }}</p>
36
- </div>
37
- <div :class="[ui.preview.fileInfo]">
38
- {{ isSelectedFileUseMb ? `${selectedFileSizeMb} MB` : `${selectedFileSizeKb} KB` }}
35
+ <p class="truncate">{{ selectedFile.name }}</p>
39
36
  </div>
37
+ <Badge size="xs" variant="outline" class="mt-1">
38
+ {{ isSelectedFileUseMb ? `${selectedFileSizeMb} Mb` : `${selectedFileSizeKb} Kb` }}
39
+ </Badge>
40
40
  </div>
41
41
  <div v-if="!selectedFile" :class="[ui.placeholderWrapper]">
42
42
  <Icon :name="ui.default.uploadIcon" :class="[ui.labelIcon]" />
@@ -56,6 +56,7 @@
56
56
  <script lang="ts" setup>
57
57
  import { useDropZone } from '@vueuse/core'
58
58
  import { type IUploadDropzoneProps } from './types'
59
+ import { isImage, generateURL, checkMaxSize, checkFileType } from '#core/helpers/componentHelper'
59
60
  import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
60
61
  import { useFieldHOC } from '#core/composables/useForm'
61
62
  import { computed, ref, toRef, useUI, useUiConfig } from '#imports'
@@ -99,7 +100,7 @@ const onDrop = (files: File[] | null) => {
99
100
  }
100
101
  }
101
102
 
102
- const { isOverDropZone } = useDropZone(dropzoneRef, {
103
+ const { isOverDropZone } = useDropZone(dropzoneRef as unknown as HTMLElement, {
103
104
  onDrop,
104
105
  })
105
106
 
@@ -109,7 +110,7 @@ const handleChange = (e: Event) => {
109
110
  const file = (e.target as HTMLInputElement).files?.[0]
110
111
  const result = handleCheckFileCondition(file)
111
112
 
112
- if (result) {
113
+ if (result && file) {
113
114
  onChange(file)
114
115
  value.value = file
115
116
  emit('change', file)
@@ -129,7 +130,15 @@ const handleDeleteFile = () => {
129
130
  const handleCheckFileCondition = (file: File | undefined): boolean => {
130
131
  if (!file) return false
131
132
 
132
- const maxSize = checkMaxSize(file)
133
+ const fileType = checkFileType(file, acceptFile.value ?? '')
134
+
135
+ if (!fileType) {
136
+ setErrors(i18next.t('custom:invalid_file_type'))
137
+
138
+ return false
139
+ }
140
+
141
+ const maxSize = checkMaxSize(file, acceptFileSizeKb.value ?? 0)
133
142
 
134
143
  if (!maxSize) {
135
144
  if (isAcceptFileUseMb.value) {
@@ -145,26 +154,4 @@ const handleCheckFileCondition = (file: File | undefined): boolean => {
145
154
 
146
155
  return true
147
156
  }
148
-
149
- const isImage = (file: File) => {
150
- return file.type.startsWith('image/')
151
- }
152
-
153
- const checkMaxSize = (file: File): boolean => {
154
- if (acceptFileSizeKb.value) {
155
- return file.size / 1000 <= acceptFileSizeKb.value
156
- }
157
-
158
- return true
159
- }
160
-
161
- const generateURL = (file: File) => {
162
- const fileSrc = URL.createObjectURL(file)
163
-
164
- setTimeout(() => {
165
- URL.revokeObjectURL(fileSrc)
166
- }, 1000)
167
-
168
- return fileSrc
169
- }
170
157
  </script>
@@ -0,0 +1,241 @@
1
+ <template>
2
+ <FieldWrapper v-bind="wrapperProps">
3
+ <div
4
+ ref="dropzoneRef"
5
+ :class="[
6
+ ui.base,
7
+ {
8
+ [ui.disabled]: isDisabled,
9
+ [ui.background.default]: !isOverDropZone && !isDisabled,
10
+ [ui.background.dragover]: isOverDropZone && !isDisabled,
11
+ },
12
+ ]"
13
+ >
14
+ <Icon
15
+ v-if="selectedFile"
16
+ :name="ui.default.closeIcon"
17
+ :class="[ui.button.delete]"
18
+ @click="handleDeleteFile"
19
+ />
20
+ <input
21
+ ref="fileInputRef"
22
+ type="file"
23
+ class="hidden"
24
+ :accept="acceptFile"
25
+ :disabled="isDisabled"
26
+ @change="handleChange"
27
+ />
28
+ <div :class="[ui.wrapper]">
29
+ <div v-if="selectedFile" :class="[ui.preview.wrapper]">
30
+ <div
31
+ v-if="isImage(selectedFile) && upload.status.value.isLoaded"
32
+ :class="[ui.preview.image.wrapper]"
33
+ >
34
+ <img
35
+ :src="upload.data.value[responseKey || 'url']"
36
+ :class="[ui.preview.image.img]"
37
+ alt="file"
38
+ />
39
+ </div>
40
+ <Icon v-else :name="ui.default.filePreviewIcon" :class="[ui.preview.icon]" />
41
+ <div :class="[ui.preview.filename]">
42
+ <p class="truncate">{{ selectedFile.name }}</p>
43
+ </div>
44
+ <div class="flex items-center space-x-1">
45
+ <Badge size="xs" variant="outline" class="mt-1">
46
+ {{ isSelectedFileUseMb ? `${selectedFileSizeMb} MB` : `${selectedFileSizeKb} KB` }}
47
+ </Badge>
48
+ <div>
49
+ <Icon
50
+ v-if="upload.status.value.isSuccess"
51
+ name="heroicons:check-circle-20-solid"
52
+ class="text-success"
53
+ />
54
+ <Icon
55
+ v-if="upload.status.value.isError"
56
+ name="heroicons:x-circle-20-solid"
57
+ class="text-danger"
58
+ />
59
+ </div>
60
+ </div>
61
+ </div>
62
+ <div v-if="upload.status.value.isLoading" :class="[ui.uploadStatus.wrapper]">
63
+ <UProgress :class="[ui.uploadStatus.progressBar]" :value="100" />
64
+ </div>
65
+ <div v-if="!selectedFile" :class="[ui.placeholderWrapper]">
66
+ <Icon :name="ui.default.uploadIcon" :class="[ui.labelIcon]" />
67
+ <div :class="[ui.labelWrapper]">
68
+ <p class="text-primary cursor-pointer" @click="handleOpenFile">
69
+ {{ selectFileLabel ?? 'คลิกเพื่อเลือกไฟล์' }}
70
+ </p>
71
+ <p>{{ selectFileSubLabel ?? 'หรือ ลากและวางที่นี่' }}</p>
72
+ </div>
73
+ <p v-if="placeholder" :class="[ui.placeholder]">{{ placeholder }}</p>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </FieldWrapper>
78
+ </template>
79
+
80
+ <script lang="ts" setup>
81
+ import { useDropZone } from '@vueuse/core'
82
+ import { type IUploadDropzoneAutoProps } from './types'
83
+ import { isImage, checkMaxSize, checkFileType } from '#core/helpers/componentHelper'
84
+ import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
85
+ import { useFieldHOC } from '#core/composables/useForm'
86
+ import {
87
+ type IUploadRequest,
88
+ computed,
89
+ ref,
90
+ toRef,
91
+ useUI,
92
+ useUiConfig,
93
+ useUploadLoader,
94
+ useWatchTrue,
95
+ StringHelper,
96
+ } from '#imports'
97
+ import { uploadFileDropzone } from '#core/ui.config'
98
+ import i18next from 'i18next'
99
+
100
+ const config = useUiConfig<typeof uploadFileDropzone>(uploadFileDropzone, 'uploadFileDropzone')
101
+
102
+ const props = withDefaults(defineProps<IUploadDropzoneAutoProps>(), {})
103
+ const emits = defineEmits(['change', 'success', 'delete'])
104
+
105
+ const { wrapperProps, handleChange: onChange, setErrors, value } = useFieldHOC<File>(props)
106
+
107
+ const request: IUploadRequest = {
108
+ pathURL: props.uploadPathURL,
109
+ requestOptions: props.requestOptions,
110
+ }
111
+
112
+ const upload = useUploadLoader(request)
113
+
114
+ const { ui } = useUI('uploadFileDropzone', toRef(props, 'ui'), config)
115
+
116
+ const fileInputRef = ref<HTMLInputElement>()
117
+ const dropzoneRef = ref<HTMLDivElement>()
118
+ const selectedFile = ref<File | undefined>()
119
+ const percent = ref<number>(0)
120
+
121
+ const acceptFile = computed(() =>
122
+ typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
123
+ )
124
+
125
+ const acceptFileSizeKb = computed(() => props.maxSize)
126
+ const acceptFileSizeMb = computed(() => ((acceptFileSizeKb.value ?? 0) / 1024).toFixed(2))
127
+ const isAcceptFileUseMb = computed(() => acceptFileSizeKb.value && acceptFileSizeKb.value > 1024)
128
+
129
+ const selectedFileSizeKb = computed(() => ((selectedFile.value?.size || 0) / 1000).toFixed(2))
130
+ const selectedFileSizeMb = computed(() =>
131
+ ((selectedFile.value?.size || 0) / 1000 / 1000).toFixed(2)
132
+ )
133
+
134
+ const isSelectedFileUseMb = computed(() => (selectedFile.value?.size || 0) / 1000 > 1024)
135
+
136
+ const onDrop = (files: File[] | null) => {
137
+ if (props.isDisabled || files?.length === 0 || !files) return
138
+
139
+ const file = files[0]
140
+ const result = handleCheckFileCondition(file)
141
+
142
+ if (result && file) {
143
+ selectedFile.value = file
144
+ const formData = new FormData()
145
+
146
+ emits('change', file)
147
+
148
+ formData.append(props.bodyKey || 'file', file)
149
+ upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
150
+ }
151
+ }
152
+
153
+ const { isOverDropZone } = useDropZone(dropzoneRef as unknown as HTMLElement, {
154
+ onDrop,
155
+ })
156
+
157
+ const handleChange = (e: Event) => {
158
+ if (props.isDisabled) return
159
+
160
+ const file = (e.target as HTMLInputElement).files?.[0]
161
+ const result = handleCheckFileCondition(file)
162
+
163
+ if (result && file) {
164
+ selectedFile.value = file
165
+ const formData = new FormData()
166
+
167
+ emits('change', file)
168
+
169
+ formData.append(props.bodyKey || 'file', file)
170
+ upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
171
+ }
172
+ }
173
+
174
+ const handleOpenFile = () => {
175
+ fileInputRef.value?.click()
176
+ }
177
+
178
+ const handleDeleteFile = () => {
179
+ fileInputRef.value?.value && (fileInputRef.value.value = '')
180
+ selectedFile.value = undefined
181
+ onChange(undefined)
182
+ emits('delete')
183
+ }
184
+
185
+ const handleCheckFileCondition = (file: File | undefined): boolean => {
186
+ if (!file) return false
187
+
188
+ const fileType = checkFileType(file, acceptFile.value ?? '')
189
+
190
+ if (!fileType) {
191
+ setErrors(i18next.t('custom:invalid_file_type'))
192
+
193
+ return false
194
+ }
195
+
196
+ const maxSize = checkMaxSize(file, acceptFileSizeKb.value ?? 0)
197
+
198
+ if (!maxSize) {
199
+ if (isAcceptFileUseMb.value) {
200
+ setErrors(i18next.t('custom:invalid_file_size_mb', { size: acceptFileSizeMb.value }))
201
+ } else {
202
+ setErrors(i18next.t('custom:invalid_file_size_kb', { size: acceptFileSizeKb.value }))
203
+ }
204
+
205
+ return false
206
+ }
207
+
208
+ setErrors('')
209
+
210
+ return true
211
+ }
212
+
213
+ const onUploadProgress = (progressEvent: ProgressEvent) => {
214
+ percent.value = (Math.floor((progressEvent.loaded * 100) / progressEvent.total) || 0) * 0.8
215
+ }
216
+
217
+ const onDownloadProgress = (progressEvent: ProgressEvent) => {
218
+ if (progressEvent.total === 0) {
219
+ percent.value = 100
220
+
221
+ return
222
+ }
223
+
224
+ percent.value = (Math.floor((progressEvent.loaded * 100) / progressEvent.total) || 0) * 0.2 + 80
225
+ }
226
+
227
+ useWatchTrue(
228
+ () => upload.status.value.isSuccess,
229
+ () => {
230
+ value.value = upload.data.value[props.responseKey || 'url']
231
+ emits('success', upload.data.value)
232
+ }
233
+ )
234
+
235
+ useWatchTrue(
236
+ () => upload.status.value.isError,
237
+ () => {
238
+ setErrors(StringHelper.getError(upload.status.value.errorData))
239
+ }
240
+ )
241
+ </script>
@@ -0,0 +1,19 @@
1
+ import { type AxiosRequestConfig } from 'axios';
2
+ import { type IFieldProps, type IFormFieldBase, type INPUT_TYPES } from '../types';
3
+ export interface IUploadDropzoneAutoProps extends IFieldProps {
4
+ requestOptions: Omit<AxiosRequestConfig, 'baseURL'> & {
5
+ baseURL: string;
6
+ };
7
+ uploadPathURL?: string;
8
+ selectFileLabel?: string;
9
+ selectFileSubLabel?: string;
10
+ accept?: string[] | string;
11
+ bodyKey?: string;
12
+ responseKey?: string;
13
+ maxSize?: number;
14
+ }
15
+ export type IUploadDropzoneAutoField = IFormFieldBase<INPUT_TYPES.UPLOAD_DROPZONE_AUTO, IUploadDropzoneAutoProps, {
16
+ change: (value: File | undefined) => void;
17
+ success: (value: string) => void;
18
+ delete: () => void;
19
+ }>;
@@ -73,16 +73,16 @@ const fileInput = ref<HTMLInputElement>()
73
73
  const selectedFile = ref<File | undefined>()
74
74
  const percent = ref<number>(0)
75
75
 
76
- const acceptFileSizeKb = computed(() => props.maxSize)
77
- const acceptFileSizeMb = computed(() => ((acceptFileSizeKb.value ?? 0) / 1024).toFixed(2))
78
76
  const selectedFileSizeKb = computed(() => ((selectedFile.value?.size || 0) / 1000).toFixed(2))
79
77
  const selectedFileSizeMb = computed(() =>
80
78
  ((selectedFile.value?.size || 0) / 1000 / 1000).toFixed(2)
81
79
  )
82
80
 
83
81
  const isSelectedFileUseMb = computed(() => (selectedFile.value?.size || 0) / 1000 > 1024)
84
- const isAcceptFileUseMb = computed(() => acceptFileSizeKb.value && acceptFileSizeKb.value > 1024)
85
82
 
83
+ const acceptFileSizeKb = computed(() => props.maxSize)
84
+ const acceptFileSizeMb = computed(() => ((acceptFileSizeKb.value || 0) / 1024).toFixed(2))
85
+ const isAcceptFileUseMb = computed(() => acceptFileSizeKb.value && acceptFileSizeKb.value > 1024)
86
86
  const acceptFile = computed(() =>
87
87
  typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
88
88
  )
@@ -11,6 +11,7 @@ import { type IDateTimeField } from '#core/components/Form/InputDateTime/date_ti
11
11
  import { type IUploadFileClassicField } from '#core/components/Form/InputUploadFileClassic/types';
12
12
  import { type IUploadFileField } from '#core/components/Form/InputUploadFileClassicAuto/types';
13
13
  import { type IUploadDropzoneField } from '#core/components/Form/InputUploadDropzone/types';
14
+ import { type IUploadDropzoneAutoField } from '#core/components/Form/InputUploadDropzoneAuto/types';
14
15
  export declare const enum INPUT_TYPES {
15
16
  TEXT = "TEXT",
16
17
  TEXTAREA = "TEXTAREA",
@@ -25,7 +26,8 @@ export declare const enum INPUT_TYPES {
25
26
  DATE = "DATE",
26
27
  UPLOAD_FILE_CLASSIC = "UPLOAD_FILE_CLASSIC",
27
28
  UPLOAD_FILE_CLASSIC_AUTO = "UPLOAD_FILE_CLASSIC_AUTO",
28
- UPLOAD_DROPZONE = "UPLOAD_DROPZONE"
29
+ UPLOAD_DROPZONE = "UPLOAD_DROPZONE",
30
+ UPLOAD_DROPZONE_AUTO = "UPLOAD_DROPZONE_AUTO"
29
31
  }
30
32
  export interface IFieldProps {
31
33
  form?: FormContext;
@@ -54,4 +56,4 @@ export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O>
54
56
  props: P;
55
57
  on?: O;
56
58
  }
57
- export type IFormField = ITextField | IStaticField | ICheckboxField | IRadioField | ISelectField | IToggleField | ITextareaField | IDateTimeField | IUploadFileClassicField | IUploadFileField | IUploadDropzoneField;
59
+ export type IFormField = ITextField | IStaticField | ICheckboxField | IRadioField | ISelectField | IToggleField | ITextareaField | IDateTimeField | IUploadFileClassicField | IUploadFileField | IUploadDropzoneField | IUploadDropzoneAutoField;
@@ -13,5 +13,6 @@ export var INPUT_TYPES = /* @__PURE__ */ ((INPUT_TYPES2) => {
13
13
  INPUT_TYPES2["UPLOAD_FILE_CLASSIC"] = "UPLOAD_FILE_CLASSIC";
14
14
  INPUT_TYPES2["UPLOAD_FILE_CLASSIC_AUTO"] = "UPLOAD_FILE_CLASSIC_AUTO";
15
15
  INPUT_TYPES2["UPLOAD_DROPZONE"] = "UPLOAD_DROPZONE";
16
+ INPUT_TYPES2["UPLOAD_DROPZONE_AUTO"] = "UPLOAD_DROPZONE_AUTO";
16
17
  return INPUT_TYPES2;
17
18
  })(INPUT_TYPES || {});
@@ -70,6 +70,7 @@
70
70
  />
71
71
  </div>
72
72
  </template>
73
+
73
74
  <script lang="ts" setup>
74
75
  import { COLUMN_TYPES, type ITableOptions } from '#core/components/Table/types'
75
76
  import ColumnNumber from '#core/components/Table/ColumnNumber.vue'
@@ -13,7 +13,7 @@
13
13
  :raw-data="options.rawData"
14
14
  :status="options.status"
15
15
  :page-options="options.pageOptions"
16
- :is-simple-pagination="options.isSimplePagination"
16
+ :is-simple-pagination="isShowSimplePagination"
17
17
  @page-change="onPageChange"
18
18
  >
19
19
  <template v-for="(_, slot) of $slots" #[slot]="slotProps">
@@ -25,7 +25,8 @@
25
25
  <script lang="ts" setup>
26
26
  import { type PropType } from 'vue'
27
27
  import { type ITableOptions } from '#core/components/Table/types'
28
- import { _debounce, ref, watch } from '#imports'
28
+ import { _debounce, computed, ref, watch } from '#imports'
29
+ import { useCoreConfig } from '#core/composables/useConfig'
29
30
  import Base from '#core/components/Table/Base.vue'
30
31
 
31
32
  const emits = defineEmits<{
@@ -37,8 +38,14 @@ const props = defineProps({
37
38
  options: { type: Object as PropType<ITableOptions>, required: true },
38
39
  })
39
40
 
41
+ const coreConfig = useCoreConfig()
42
+
40
43
  const q = ref(props.options?.pageOptions.search ?? '')
41
44
 
45
+ const isShowSimplePagination = computed(
46
+ (): boolean => props.options.isSimplePagination ?? coreConfig.is_simple_pagination
47
+ )
48
+
42
49
  watch(
43
50
  q,
44
51
  _debounce((value) => {
@@ -7,4 +7,5 @@ export declare const core: {
7
7
  is_thai_year: boolean;
8
8
  is_thai_month: boolean;
9
9
  site_name: string;
10
+ is_simple_pagination: boolean;
10
11
  };
@@ -6,5 +6,6 @@ export const core = {
6
6
  time_format: "HH:mm",
7
7
  is_thai_year: false,
8
8
  is_thai_month: false,
9
- site_name: ""
9
+ site_name: "",
10
+ is_simple_pagination: false
10
11
  };
@@ -0,0 +1,4 @@
1
+ export declare const checkMaxSize: (file: File, acceptFileSize: number) => boolean;
2
+ export declare const checkFileType: (file: File, acceptFileType: string | string[]) => boolean;
3
+ export declare const generateURL: (file: File) => string;
4
+ export declare const isImage: (file: File) => boolean;
@@ -0,0 +1,39 @@
1
+ export const checkMaxSize = (file, acceptFileSize) => {
2
+ if (acceptFileSize) {
3
+ return file.size / 1e3 <= acceptFileSize;
4
+ }
5
+ return true;
6
+ };
7
+ export const checkFileType = (file, acceptFileType) => {
8
+ if (!acceptFileType || Array.isArray(acceptFileType) && acceptFileType.length === 0)
9
+ return true;
10
+ const result = [];
11
+ const acceptedTypes = Array.isArray(acceptFileType) ? acceptFileType : acceptFileType.split(",");
12
+ for (const acceptedType of acceptedTypes) {
13
+ if (acceptedType.startsWith(".")) {
14
+ const fileExtension = `.${file.name.split(".").pop()}`;
15
+ if (fileExtension.toLowerCase() === acceptedType.toLowerCase())
16
+ result.push(true);
17
+ } else {
18
+ const fileType = acceptedType.split("/");
19
+ const fileExtension = file.type.split("/");
20
+ if (fileType.length === 2 && fileExtension.length === 2) {
21
+ if (fileType[1] === "*") {
22
+ result.push(fileType[0].toLowerCase() === fileExtension[0].toLowerCase());
23
+ }
24
+ result.push(acceptedType.toLowerCase() === file.type.toLowerCase());
25
+ }
26
+ }
27
+ }
28
+ return result.includes(true);
29
+ };
30
+ export const generateURL = (file) => {
31
+ const fileSrc = URL.createObjectURL(file);
32
+ setTimeout(() => {
33
+ URL.revokeObjectURL(fileSrc);
34
+ }, 1e3);
35
+ return fileSrc;
36
+ };
37
+ export const isImage = (file) => {
38
+ return file.type.startsWith("image/");
39
+ };
@@ -13,7 +13,10 @@ export declare const uploadFileDropzone: {
13
13
  img: string;
14
14
  };
15
15
  filename: string;
16
- fileInfo: string;
16
+ };
17
+ uploadStatus: {
18
+ wrapper: string;
19
+ progressBar: string;
17
20
  };
18
21
  background: {
19
22
  default: string;
@@ -9,11 +9,14 @@ export const uploadFileDropzone = {
9
9
  wrapper: "flex flex-col items-center w-full",
10
10
  icon: "mb-2 h-10 w-10 text-gray-400",
11
11
  image: {
12
- wrapper: "flex justify-center mb-2 rounded overflow-hidden",
13
- img: "max-w-[300px]"
12
+ wrapper: "flex justify-center mb-2 rounded overflow-hidden max-w-[300px]",
13
+ img: "w-full object-contain"
14
14
  },
15
- filename: "flex items-center justify-center w-full font-semibold truncate",
16
- fileInfo: "text-center text-gray-400 mt-1 text-sm font-light"
15
+ filename: "flex items-center justify-center w-full font-semibold truncate"
16
+ },
17
+ uploadStatus: {
18
+ wrapper: "w-full md:w-1/2 mt-2",
19
+ progressBar: ""
17
20
  },
18
21
  background: {
19
22
  default: "bg-white border-gray-border",
@@ -26,9 +26,9 @@ export class StringHelper {
26
26
  return newStr;
27
27
  };
28
28
  static getError = (errorData, defaultErrorMessage = "\u0E21\u0E35\u0E1A\u0E32\u0E07\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14") => {
29
- let msg = errorData?.message;
29
+ let msg = errorData?.message || defaultErrorMessage;
30
30
  if (!errorData.code || !msg) {
31
- return defaultErrorMessage;
31
+ return msg;
32
32
  }
33
33
  if (errorData.code !== "INVALID_PARAMS" && !errorData.fields) {
34
34
  return msg;
package/package.json CHANGED
@@ -1,86 +1,83 @@
1
- {
2
- "name": "@finema/core",
3
- "version": "1.4.50",
4
- "repository": "https://gitlab.finema.co/finema/ui-kit",
5
- "license": "MIT",
6
- "author": "Finema Dev Core Team",
7
- "type": "module",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/types.d.ts",
11
- "import": "./dist/module.mjs",
12
- "require": "./dist/module.cjs"
13
- }
14
- },
15
- "main": "./dist/module.cjs",
16
- "types": "./dist/types.d.ts",
17
- "files": [
18
- "dist"
19
- ],
20
- "engines": {
21
- "node": ">=18.0.0"
22
- },
23
- "scripts": {
24
- "prepack": "nuxt-module-build build",
25
- "dev": "nuxi dev playground",
26
- "dev:build": "nuxi build playground",
27
- "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
28
- "lint": "eslint . --cache",
29
- "lint:fix": "eslint . --fix --cache",
30
- "test": "vitest run",
31
- "test:watch": "vitest watch",
32
- "release": "release-it --ci",
33
- "prepare": "husky install"
34
- },
35
- "dependencies": {
36
- "@nuxt/kit": "^3.7.4",
37
- "@nuxt/ui": "^2.13.0",
38
- "@pinia/nuxt": "^0.5.1",
39
- "@vee-validate/nuxt": "^4.12.4",
40
- "@vee-validate/zod": "^4.12.4",
41
- "@vuepic/vue-datepicker": "^7.4.1",
42
- "axios": "^1.6.5",
43
- "date-fns": "^3.2.0",
44
- "i18next": "^23.7.16",
45
- "lodash-es": "^4.17.21",
46
- "nuxt-security": "^1.0.0",
47
- "pinia": "^2.1.7",
48
- "qrcode.vue": "^3.4.1",
49
- "url-join": "^5.0.0",
50
- "zod": "^3.22.4",
51
- "zod-i18n-map": "^2.25.0"
52
- },
53
- "devDependencies": {
54
- "@finema/eslint-config": "^1.2.0",
55
- "@nuxt/devtools": "latest",
56
- "@nuxt/eslint-config": "^0.2.0",
57
- "@nuxt/module-builder": "^0.5.4",
58
- "@nuxt/schema": "^3.7.4",
59
- "@nuxt/test-utils": "^3.9.0",
60
- "@release-it/conventional-changelog": "^8.0.1",
61
- "@types/lodash-es": "^4.17.12",
62
- "@types/node": "^20.10.8",
63
- "@vue/test-utils": "^2.4.3",
64
- "changelogen": "^0.5.5",
65
- "eslint": "^8.56.0",
66
- "happy-dom": "^13.0.0",
67
- "husky": "^8.0.3",
68
- "lint-staged": "^15.2.0",
69
- "nuxt": "^3.9.1",
70
- "playwright-core": "^1.40.1",
71
- "prettier": "^3.1.1",
72
- "release-it": "^17.0.1",
73
- "sass": "^1.69.5",
74
- "stylelint": "^16.1.0",
75
- "stylelint-config-prettier-scss": "^1.0.0",
76
- "stylelint-config-standard-scss": "^13.0.0",
77
- "vitest": "^1.1.3"
78
- },
79
- "resolutions": {
80
- "vue": "3.3.13"
81
- },
82
- "lint-staged": {
83
- "*.{ts,vue,tsx,js}": "eslint --fix --cache",
84
- "*.{html,json}": "prettier --write"
85
- }
86
- }
1
+ {
2
+ "name": "@finema/core",
3
+ "version": "1.4.52",
4
+ "repository": "https://gitlab.finema.co/finema/ui-kit",
5
+ "license": "MIT",
6
+ "author": "Finema Dev Core Team",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types.d.ts",
11
+ "import": "./dist/module.mjs",
12
+ "require": "./dist/module.cjs"
13
+ }
14
+ },
15
+ "main": "./dist/module.cjs",
16
+ "types": "./dist/types.d.ts",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "engines": {
21
+ "node": ">=18.0.0"
22
+ },
23
+ "scripts": {
24
+ "prepack": "nuxt-module-build build",
25
+ "dev": "nuxi dev playground",
26
+ "dev:build": "nuxi build playground",
27
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
28
+ "lint": "eslint . --cache",
29
+ "lint:fix": "eslint . --fix --cache",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest watch",
32
+ "release": "release-it --ci",
33
+ "prepare": "husky install"
34
+ },
35
+ "dependencies": {
36
+ "@nuxt/kit": "^3.7.4",
37
+ "@nuxt/ui": "^2.13.0",
38
+ "@pinia/nuxt": "^0.5.1",
39
+ "@vee-validate/nuxt": "^4.12.5",
40
+ "@vee-validate/zod": "^4.12.5",
41
+ "@vuepic/vue-datepicker": "^7.4.1",
42
+ "axios": "^1.6.7",
43
+ "date-fns": "^3.3.1",
44
+ "i18next": "^23.8.2",
45
+ "lodash-es": "^4.17.21",
46
+ "nuxt-security": "^1.1.0",
47
+ "pinia": "^2.1.7",
48
+ "qrcode.vue": "^3.4.1",
49
+ "url-join": "^5.0.0",
50
+ "zod": "^3.22.4",
51
+ "zod-i18n-map": "^2.27.0"
52
+ },
53
+ "devDependencies": {
54
+ "@finema/eslint-config": "^1.2.0",
55
+ "@nuxt/devtools": "latest",
56
+ "@nuxt/eslint-config": "^0.2.0",
57
+ "@nuxt/module-builder": "^0.5.4",
58
+ "@nuxt/schema": "^3.7.4",
59
+ "@nuxt/test-utils": "^3.11.0",
60
+ "@release-it/conventional-changelog": "^8.0.1",
61
+ "@types/lodash-es": "^4.17.12",
62
+ "@types/node": "^20.10.8",
63
+ "@vue/test-utils": "^2.4.3",
64
+ "changelogen": "^0.5.5",
65
+ "eslint": "^8.56.0",
66
+ "happy-dom": "^13.0.0",
67
+ "husky": "^8.0.3",
68
+ "lint-staged": "^15.2.0",
69
+ "nuxt": "^3.10.1",
70
+ "playwright-core": "^1.40.1",
71
+ "prettier": "^3.1.1",
72
+ "release-it": "^17.0.1",
73
+ "sass": "^1.69.5",
74
+ "stylelint": "^16.1.0",
75
+ "stylelint-config-prettier-scss": "^1.0.0",
76
+ "stylelint-config-standard-scss": "^13.0.0",
77
+ "vitest": "^1.2.2"
78
+ },
79
+ "lint-staged": {
80
+ "*.{ts,vue,tsx,js}": "eslint --fix --cache",
81
+ "*.{html,json}": "prettier --write"
82
+ }
83
+ }