@finema/core 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +1 -1
  3. package/dist/runtime/components/Form/FieldWrapper.vue +13 -13
  4. package/dist/runtime/components/Form/Fields.vue +18 -14
  5. package/dist/runtime/components/Form/InputCheckbox/index.vue +18 -18
  6. package/dist/runtime/components/Form/InputCurrency/index.vue +49 -49
  7. package/dist/runtime/components/Form/InputNumber/index.vue +20 -20
  8. package/dist/runtime/components/Form/InputSelect/index.vue +38 -38
  9. package/dist/runtime/components/Form/InputSelectMultiple/index.vue +43 -43
  10. package/dist/runtime/components/Form/InputTags/index.vue +23 -23
  11. package/dist/runtime/components/Form/InputTextarea/index.vue +18 -18
  12. package/dist/runtime/components/Form/InputTime/index.vue +38 -38
  13. package/dist/runtime/components/Form/InputToggle/index.vue +17 -17
  14. package/dist/runtime/components/Form/InputUploadDropzone/index.vue +30 -30
  15. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +50 -50
  16. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +31 -31
  17. package/dist/runtime/components/Form/InputUploadImageAuto/index.d.vue.ts +26 -0
  18. package/dist/runtime/components/Form/InputUploadImageAuto/index.vue +131 -0
  19. package/dist/runtime/components/Form/InputUploadImageAuto/index.vue.d.ts +26 -0
  20. package/dist/runtime/components/Form/InputUploadImageAuto/types.d.ts +37 -0
  21. package/dist/runtime/components/Form/InputUploadImageAuto/types.js +0 -0
  22. package/dist/runtime/components/Form/InputWYSIWYG/types.d.ts +15 -1
  23. package/dist/runtime/components/Form/fileState/EmptyState.vue +21 -21
  24. package/dist/runtime/components/Form/fileState/FailedState.vue +33 -33
  25. package/dist/runtime/components/Form/fileState/LoadingState.vue +24 -24
  26. package/dist/runtime/components/Form/fileState/MultipleFilesState.vue +145 -145
  27. package/dist/runtime/components/Form/fileState/PreviewModal.vue +23 -23
  28. package/dist/runtime/components/Form/fileState/useUploadImageState.d.ts +25 -0
  29. package/dist/runtime/components/Form/fileState/useUploadImageState.js +257 -0
  30. package/dist/runtime/components/Form/index.vue +5 -5
  31. package/dist/runtime/components/Form/types.d.ts +2 -1
  32. package/dist/runtime/components/Image.vue +28 -28
  33. package/dist/runtime/components/Log/index.vue +17 -17
  34. package/dist/runtime/components/Table/ColumnDate.vue +1 -1
  35. package/dist/runtime/components/Table/ColumnDateTime.vue +1 -1
  36. package/dist/runtime/components/Table/ColumnImage.vue +4 -4
  37. package/dist/runtime/components/Table/ColumnText.vue +1 -1
  38. package/dist/runtime/components/Table/Pagination.vue +46 -46
  39. package/dist/runtime/components/Table/Simple.vue +17 -17
  40. package/dist/runtime/helpers/apiPageHelper.js +4 -4
  41. package/dist/runtime/server/tsconfig.json +3 -3
  42. package/package.json +1 -1
@@ -0,0 +1,257 @@
1
+ import { useDropZone, useFileDialog } from "@vueuse/core";
2
+ import { useWatchTrue } from "#core/composables/useWatch";
3
+ import PreviewModal from "./PreviewModal.vue";
4
+ import { computed, ref, useOverlay } from "#imports";
5
+ import { useUploadLoader } from "#core/composables/useUpload";
6
+ import { useFileAllocate, useFileProgress } from "#core/helpers/componentHelper";
7
+ import { StringHelper } from "#core/utils/StringHelper";
8
+ import { _get } from "#core/utils/lodash";
9
+ export var UploadState = /* @__PURE__ */ ((UploadState2) => {
10
+ UploadState2["EMPTY"] = "empty";
11
+ UploadState2["UPLOADING"] = "uploading";
12
+ UploadState2["SUCCESS"] = "success";
13
+ UploadState2["ERROR"] = "error";
14
+ return UploadState2;
15
+ })(UploadState || {});
16
+ export const useUploadImageState = (props, emits, onChange, setErrors, value, acceptedFileTypes, wrapperProps, dropzoneRef) => {
17
+ const overlay = useOverlay();
18
+ const previewModal = overlay.create(PreviewModal);
19
+ const selectedFile = ref();
20
+ const fileAllocate = useFileAllocate(selectedFile, props);
21
+ const {
22
+ percent,
23
+ onDownloadProgress,
24
+ onUploadProgress
25
+ } = useFileProgress();
26
+ const request = {
27
+ requestOptions: {
28
+ ...props.requestOptions,
29
+ onDownloadProgress,
30
+ onUploadProgress
31
+ },
32
+ pathURL: props.uploadPathURL
33
+ };
34
+ const upload = useUploadLoader(request);
35
+ const validateImageDimensions = (file) => {
36
+ return new Promise((resolve) => {
37
+ if (!props.dimensions) {
38
+ resolve(true);
39
+ return;
40
+ }
41
+ const img = new Image();
42
+ const url = URL.createObjectURL(file);
43
+ img.onload = () => {
44
+ URL.revokeObjectURL(url);
45
+ const {
46
+ width,
47
+ height
48
+ } = img;
49
+ const dimensions = props.dimensions;
50
+ if (dimensions.width !== void 0 && width !== dimensions.width) {
51
+ setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E01\u0E27\u0E49\u0E32\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 ${dimensions.width}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${width}px)`);
52
+ resolve(false);
53
+ return;
54
+ }
55
+ if (dimensions.height !== void 0 && height !== dimensions.height) {
56
+ setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E39\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 ${dimensions.height}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${height}px)`);
57
+ resolve(false);
58
+ return;
59
+ }
60
+ if (dimensions.minWidth !== void 0 && width < dimensions.minWidth) {
61
+ setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E01\u0E27\u0E49\u0E32\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32 ${dimensions.minWidth}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${width}px)`);
62
+ resolve(false);
63
+ return;
64
+ }
65
+ if (dimensions.minHeight !== void 0 && height < dimensions.minHeight) {
66
+ setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E39\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32 ${dimensions.minHeight}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${height}px)`);
67
+ resolve(false);
68
+ return;
69
+ }
70
+ if (dimensions.maxWidth !== void 0 && width > dimensions.maxWidth) {
71
+ setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E01\u0E27\u0E49\u0E32\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${dimensions.maxWidth}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${width}px)`);
72
+ resolve(false);
73
+ return;
74
+ }
75
+ if (dimensions.maxHeight !== void 0 && height > dimensions.maxHeight) {
76
+ setErrors(`\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E39\u0E07\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${dimensions.maxHeight}px (\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${height}px)`);
77
+ resolve(false);
78
+ return;
79
+ }
80
+ if (dimensions.aspectRatio !== void 0) {
81
+ const actualRatio = width / height;
82
+ const tolerance = dimensions.aspectRatioTolerance ?? 0.01;
83
+ const expectedRatio = dimensions.aspectRatio;
84
+ if (Math.abs(actualRatio - expectedRatio) > tolerance) {
85
+ setErrors(`\u0E2D\u0E31\u0E15\u0E23\u0E32\u0E2A\u0E48\u0E27\u0E19\u0E02\u0E2D\u0E07\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 (\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23: ${expectedRatio.toFixed(2)}, \u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19: ${actualRatio.toFixed(2)})`);
86
+ resolve(false);
87
+ return;
88
+ }
89
+ }
90
+ setErrors("");
91
+ resolve(true);
92
+ };
93
+ img.onerror = () => {
94
+ URL.revokeObjectURL(url);
95
+ setErrors("\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E42\u0E2B\u0E25\u0E14\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E44\u0E14\u0E49");
96
+ resolve(false);
97
+ };
98
+ img.src = url;
99
+ });
100
+ };
101
+ const validateFile = async (file) => {
102
+ if (props.accept && fileAllocate.acceptFile.value) {
103
+ const acceptedTypes = fileAllocate.acceptFile.value;
104
+ const acceptedTypesList = acceptedTypes.split(",").map((type) => type.trim());
105
+ const fileExtension = file.name.toLowerCase().split(".").pop();
106
+ const isValidFileType = acceptedTypesList.some((acceptedType) => {
107
+ if (acceptedType.startsWith(".")) {
108
+ const extension = acceptedType.slice(1).toLowerCase();
109
+ return fileExtension === extension;
110
+ } else if (!acceptedType.includes("/") && !acceptedType.includes("*")) {
111
+ return fileExtension === acceptedType.toLowerCase();
112
+ }
113
+ if (acceptedType.endsWith("/*")) {
114
+ const baseType = acceptedType.slice(0, -2);
115
+ return file.type.startsWith(baseType + "/");
116
+ }
117
+ return file.type === acceptedType;
118
+ });
119
+ if (!isValidFileType) {
120
+ setErrors("\u0E1B\u0E23\u0E30\u0E40\u0E20\u0E17\u0E44\u0E1F\u0E25\u0E4C\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 (\u0E23\u0E2D\u0E07\u0E23\u0E31\u0E1A\u0E40\u0E09\u0E1E\u0E32\u0E30 " + acceptedTypesList.join(", ") + ")");
121
+ return false;
122
+ }
123
+ }
124
+ if (props.maxSize) {
125
+ const maxSizeBytes = (fileAllocate.acceptFileSizeKb.value || 0) * 1024;
126
+ if (file.size > maxSizeBytes) {
127
+ if (fileAllocate.isAcceptFileUseMb.value) {
128
+ setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeMb.value} MB`);
129
+ } else {
130
+ setErrors(`\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${fileAllocate.acceptFileSizeKb.value} KB`);
131
+ }
132
+ return false;
133
+ }
134
+ }
135
+ const isDimensionsValid = await validateImageDimensions(file);
136
+ if (!isDimensionsValid) {
137
+ return false;
138
+ }
139
+ setErrors("");
140
+ return true;
141
+ };
142
+ const processFile = async (file) => {
143
+ const isValid = await validateFile(file);
144
+ if (!isValid) return;
145
+ selectedFile.value = file;
146
+ emits("change", file);
147
+ const formData = new FormData();
148
+ formData.append(props.bodyKey, file);
149
+ upload.run({
150
+ data: formData
151
+ });
152
+ };
153
+ const handleFileDrop = (files) => {
154
+ if (wrapperProps.value.disabled || wrapperProps.value.readonly || !files?.length || !isEmpty.value) return;
155
+ const file = files[0];
156
+ if (file) {
157
+ processFile(file);
158
+ }
159
+ };
160
+ const fileDialog = useFileDialog({
161
+ accept: acceptedFileTypes.value || "image/*",
162
+ directory: false,
163
+ multiple: false
164
+ });
165
+ const dropzone = useDropZone(dropzoneRef, {
166
+ onDrop: handleFileDrop,
167
+ multiple: false,
168
+ preventDefaultForUnhandled: false
169
+ });
170
+ const currentState = computed(() => {
171
+ if (value.value) return "success" /* SUCCESS */;
172
+ if (selectedFile.value && upload.status.value.isLoading) return "uploading" /* UPLOADING */;
173
+ if (selectedFile.value && upload.status.value.isError) return "error" /* ERROR */;
174
+ return "empty" /* EMPTY */;
175
+ });
176
+ const isEmpty = computed(() => currentState.value === "empty" /* EMPTY */);
177
+ const isUploading = computed(() => currentState.value === "uploading" /* UPLOADING */);
178
+ const isSuccess = computed(() => currentState.value === "success" /* SUCCESS */);
179
+ const isError = computed(() => currentState.value === "error" /* ERROR */);
180
+ const handleInputChange = (event) => {
181
+ if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
182
+ const file = event.target.files?.[0];
183
+ if (file) {
184
+ processFile(file);
185
+ }
186
+ };
187
+ fileDialog.onChange((files) => {
188
+ const file = files?.[0];
189
+ if (file) {
190
+ processFile(file);
191
+ }
192
+ });
193
+ const handleOpenFile = () => {
194
+ if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
195
+ fileDialog.open();
196
+ };
197
+ const handleDeleteFile = () => {
198
+ fileDialog.reset();
199
+ upload.clear();
200
+ selectedFile.value = void 0;
201
+ onChange(void 0);
202
+ emits("delete");
203
+ };
204
+ const handleRetryUpload = () => {
205
+ if (selectedFile.value) {
206
+ const formData = new FormData();
207
+ formData.append(props.bodyKey, selectedFile.value);
208
+ upload.run(formData);
209
+ }
210
+ };
211
+ const handlePreview = () => {
212
+ previewModal.open({
213
+ value: value.value
214
+ });
215
+ };
216
+ useWatchTrue(
217
+ () => upload.status.value.isSuccess,
218
+ () => {
219
+ if (upload.data.value) {
220
+ const fileValue = {
221
+ url: _get(upload.data.value, props.responseURL),
222
+ path: _get(upload.data.value, props.responsePath),
223
+ name: _get(upload.data.value, props.responseName) || selectedFile.value?.name,
224
+ size: Number(_get(upload.data.value, props.responseSize) || selectedFile.value?.size),
225
+ id: _get(upload.data.value, props.responseID)
226
+ };
227
+ value.value = fileValue;
228
+ emits("success", fileValue);
229
+ }
230
+ }
231
+ );
232
+ useWatchTrue(
233
+ () => upload.status.value.isError,
234
+ () => {
235
+ setErrors("\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14: " + StringHelper.getError(upload.status.value.errorData));
236
+ }
237
+ );
238
+ return {
239
+ // State
240
+ currentState,
241
+ isEmpty,
242
+ isUploading,
243
+ isSuccess,
244
+ isError,
245
+ selectedFile,
246
+ // Upload utilities
247
+ upload,
248
+ dropzone,
249
+ percent,
250
+ // Handlers
251
+ handleInputChange,
252
+ handleOpenFile,
253
+ handleDeleteFile,
254
+ handleRetryUpload,
255
+ handlePreview
256
+ };
257
+ };
@@ -1,5 +1,5 @@
1
- <template>
2
- <form class="form">
3
- <slot />
4
- </form>
5
- </template>
1
+ <template>
2
+ <form class="form">
3
+ <slot />
4
+ </form>
5
+ </template>
@@ -3,6 +3,7 @@ import type { FormContext } from 'vee-validate';
3
3
  import type { IUploadDropzoneField } from './InputUploadDropzone/types.js';
4
4
  import type { IUploadDropzoneAutoField } from './InputUploadDropzoneAuto/types.js';
5
5
  import type { IUploadDropzoneAutoMultipleField } from './InputUploadDropzoneAutoMultiple/types.js';
6
+ import type { IUploadImageAutoField } from './InputUploadImageAuto/types.js';
6
7
  import type { IDateTimeRangeField } from './InputDateTimeRange/date_range_time_field.types.js';
7
8
  import type { ITextField } from '#core/components/Form/InputText/types';
8
9
  import type { ISearchField } from '#core/components/Form/InputSearch/types';
@@ -76,7 +77,7 @@ export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O>
76
77
  props: P;
77
78
  on?: O;
78
79
  }
79
- export type IFormField = ITextField | ISearchField | INumberField | ICurrencyField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IRadioField | IDateTimeField | ITimeField | IMonthField | IDateTimeRangeField | IUploadDropzoneField | IUploadDropzoneAutoField | IUploadDropzoneAutoMultipleField | IWYSIWYGField | IComponentField | ITagsField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
80
+ export type IFormField = ITextField | ISearchField | INumberField | ICurrencyField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IRadioField | IDateTimeField | ITimeField | IMonthField | IDateTimeRangeField | IUploadDropzoneField | IUploadDropzoneAutoField | IUploadDropzoneAutoMultipleField | IUploadImageAutoField | IWYSIWYGField | IComponentField | ITagsField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
80
81
  export interface IFileValue {
81
82
  url: string;
82
83
  path?: string;
@@ -1,32 +1,32 @@
1
1
  <template>
2
- <UseImage v-bind="$props">
3
- <template #loading>
4
- <slot name="loading">
5
- <div
6
- class="flex h-full w-full items-center justify-center"
7
- >
8
- <Loader
9
- :loading="true"
10
- />
11
- </div>
12
- </slot>
13
- </template>
14
-
15
- <template #error>
16
- <slot name="error">
17
- <div
18
- class="flex h-full w-full items-center justify-center"
19
- >
20
- <p class="text-error-400">
21
- <Icon
22
- name="i-heroicons:exclamation-circle-solid"
23
- class="text-error-400 size-8"
24
- />
25
- </p>
26
- </div>
27
- </slot>
28
- </template>
29
- </UseImage>
2
+ <UseImage v-bind="$props">
3
+ <template #loading>
4
+ <slot name="loading">
5
+ <div
6
+ class="flex h-full w-full items-center justify-center"
7
+ >
8
+ <Loader
9
+ :loading="true"
10
+ />
11
+ </div>
12
+ </slot>
13
+ </template>
14
+
15
+ <template #error>
16
+ <slot name="error">
17
+ <div
18
+ class="flex h-full w-full items-center justify-center"
19
+ >
20
+ <p class="text-error-400">
21
+ <Icon
22
+ name="i-heroicons:exclamation-circle-solid"
23
+ class="text-error-400 size-8"
24
+ />
25
+ </p>
26
+ </div>
27
+ </slot>
28
+ </template>
29
+ </UseImage>
30
30
  </template>
31
31
 
32
32
  <script setup>
@@ -1,21 +1,21 @@
1
1
  <template>
2
- <DevOnly>
3
- <TeleportSafe
4
- to="#dev-logs"
5
- >
6
- <LogItem
7
- v-if="typeof data !== 'undefined'"
8
- :data="data"
9
- :title="title"
10
- />
11
- <LogItem
12
- v-for="(item, index) in dataItems"
13
- :key="index"
14
- :data="item"
15
- :title="`${title} #${index + 1}`"
16
- />
17
- </TeleportSafe>
18
- </DevOnly>
2
+ <DevOnly>
3
+ <TeleportSafe
4
+ to="#dev-logs"
5
+ >
6
+ <LogItem
7
+ v-if="typeof data !== 'undefined'"
8
+ :data="data"
9
+ :title="title"
10
+ />
11
+ <LogItem
12
+ v-for="(item, index) in dataItems"
13
+ :key="index"
14
+ :data="item"
15
+ :title="`${title} #${index + 1}`"
16
+ />
17
+ </TeleportSafe>
18
+ </DevOnly>
19
19
  </template>
20
20
 
21
21
  <script setup>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- {{ getValue || "-" }}
2
+ {{ getValue || "-" }}
3
3
  </template>
4
4
 
5
5
  <script setup>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- {{ getValue || "-" }}
2
+ {{ getValue || "-" }}
3
3
  </template>
4
4
 
5
5
  <script setup>
@@ -1,8 +1,8 @@
1
1
  <template>
2
- <Image
3
- class="h-12 rounded"
4
- :src="getValue"
5
- />
2
+ <Image
3
+ class="h-12 rounded"
4
+ :src="getValue"
5
+ />
6
6
  </template>
7
7
 
8
8
  <script setup>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- {{ getValue }}
2
+ {{ getValue }}
3
3
  </template>
4
4
 
5
5
  <script setup>
@@ -1,70 +1,70 @@
1
1
  <template>
2
- <div
2
+ <div
3
3
  :class="
4
4
  theme.paginationContainer({
5
5
  class: [ui?.paginationContainer]
6
6
  })
7
- "
8
- >
9
- <div
7
+ "
8
+ >
9
+ <div
10
10
  :class="
11
11
  theme.paginationInfoWrapper({
12
12
  class: [ui?.paginationInfoWrapper]
13
13
  })
14
- "
15
- >
16
- <USelect
17
- v-if="options.pageOptions && !options.isHideLimitSelect"
18
- size="lg"
19
- trailing="รายการ"
14
+ "
15
+ >
16
+ <USelect
17
+ v-if="options.pageOptions && !options.isHideLimitSelect"
18
+ size="lg"
19
+ trailing="รายการ"
20
20
  :class="
21
21
  theme.paginationLimitSelect({
22
22
  class: [ui?.paginationLimitSelect, 'cursor-pointer']
23
23
  })
24
- "
25
- :items="pageLimitItems"
26
- :model-value="pageLimit"
27
- @update:modelValue="emits('pageLimitChange', $event)"
28
- >
29
- <template #default="{ modelValue }">
30
- <p
24
+ "
25
+ :items="pageLimitItems"
26
+ :model-value="pageLimit"
27
+ @update:modelValue="emits('pageLimitChange', $event)"
28
+ >
29
+ <template #default="{ modelValue }">
30
+ <p
31
31
  :class="
32
32
  theme.paginationLimitSelectLabel({
33
33
  class: [ui?.paginationLimitSelectLabel]
34
34
  })
35
- "
36
- >
37
- {{ modelValue }} รายการ
38
- </p>
39
- </template>
40
- </USelect>
41
- <p
35
+ "
36
+ >
37
+ {{ modelValue }} รายการ
38
+ </p>
39
+ </template>
40
+ </USelect>
41
+ <p
42
42
  :class="
43
43
  theme.paginationInfo({
44
44
  class: [ui?.paginationInfo, '']
45
45
  })
46
- "
47
- >
48
- <span v-if="options.pageOptions">{{ pageBetween }} จากทั้งหมด {{ totalCountWithComma }}</span>
49
- <span v-else>ทั้งหมด {{ options.rawData.length }} รายการ</span>
50
- </p>
51
- </div>
52
-
53
- <UPagination
54
- v-if="options.pageOptions && options.pageOptions.totalPage > 1"
55
- :page="page"
56
- :default-page="options.pageOptions?.currentPage || 1"
57
- :items-per-page="options.pageOptions.limit"
58
- :total="options.pageOptions.totalCount"
59
- :to="options.isRouteChange ? to : void 0"
60
- show-edges
61
- variant="outline"
62
- color="neutral"
63
- active-color="neutral"
64
- active-variant="subtle"
65
- @update:page="emits('pageChange', $event)"
66
- />
67
- </div>
46
+ "
47
+ >
48
+ <span v-if="options.pageOptions">{{ pageBetween }} จากทั้งหมด {{ totalCountWithComma }}</span>
49
+ <span v-else>ทั้งหมด {{ options.rawData.length }} รายการ</span>
50
+ </p>
51
+ </div>
52
+
53
+ <UPagination
54
+ v-if="options.pageOptions && options.pageOptions.totalPage > 1"
55
+ :page="page"
56
+ :default-page="options.pageOptions?.currentPage || 1"
57
+ :items-per-page="options.pageOptions.limit"
58
+ :total="options.pageOptions.totalCount"
59
+ :to="options.isRouteChange ? to : void 0"
60
+ show-edges
61
+ variant="outline"
62
+ color="neutral"
63
+ active-color="neutral"
64
+ active-variant="subtle"
65
+ @update:page="emits('pageChange', $event)"
66
+ />
67
+ </div>
68
68
  </template>
69
69
 
70
70
  <script setup>
@@ -1,25 +1,25 @@
1
1
  <template>
2
- <Base
3
- v-bind="$attrs"
2
+ <Base
3
+ v-bind="$attrs"
4
4
  :options="{
5
5
  ...options,
6
6
  pageOptions,
7
7
  isHideLimitSelect: true
8
- }"
9
- :ui="ui"
10
- :raw-data="itemsByPage"
11
- @page-change="onPageChange"
12
- >
13
- <template
14
- v-for="(_, slot) of $slots"
15
- #[slot]="slotProps"
16
- >
17
- <slot
18
- :name="slot"
19
- v-bind="slotProps || {}"
20
- />
21
- </template>
22
- </Base>
8
+ }"
9
+ :ui="ui"
10
+ :raw-data="itemsByPage"
11
+ @page-change="onPageChange"
12
+ >
13
+ <template
14
+ v-for="(_, slot) of $slots"
15
+ #[slot]="slotProps"
16
+ >
17
+ <slot
18
+ :name="slot"
19
+ v-bind="slotProps || {}"
20
+ />
21
+ </template>
22
+ </Base>
23
23
  </template>
24
24
 
25
25
  <script setup>
@@ -162,21 +162,21 @@ export const apiFetchHelper = async (state, onUpdateStatus, onUpdateOptions, onU
162
162
  ...moreOptions
163
163
  } = response;
164
164
  onUpdateItems(items);
165
- onUpdateOptions({
165
+ onUpdateOptions(JSON.parse(JSON.stringify({
166
166
  ...getOptions(moreOptions),
167
167
  _timestamp: Date.now(),
168
168
  _status: status,
169
169
  request: requestOptions
170
- });
170
+ })));
171
171
  onUpdateStatus(updateLoaderState.setSuccess(state().status));
172
172
  },
173
173
  onError: (error) => {
174
174
  onUpdateStatus(updateLoaderState.setError(state().status, error));
175
- onUpdateOptions({
175
+ onUpdateOptions(JSON.parse(JSON.stringify({
176
176
  ...state().options,
177
177
  _status: error.response?.status,
178
178
  request: requestOptions
179
- });
179
+ })));
180
180
  },
181
181
  onComplete: () => {
182
182
  onUpdateStatus(updateLoaderState.setComplete(state().status));
@@ -1,3 +1,3 @@
1
- {
2
- "extends": "../../../.nuxt/tsconfig.server.json",
3
- }
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json",
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finema/core",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "repository": "https://gitlab.finema.co/finema/ui-kit",
5
5
  "license": "MIT",
6
6
  "author": "Finema Dev Core Team",