@finema/core 3.22.0 → 3.24.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 (130) hide show
  1. package/README.md +22 -2
  2. package/dist/module.d.mts +2 -0
  3. package/dist/module.json +2 -2
  4. package/dist/module.mjs +18 -15
  5. package/dist/runtime/components/App.vue +1 -1
  6. package/dist/runtime/components/DevToolsWindow/index.vue +24 -26
  7. package/dist/runtime/components/Dialog/index.d.vue.ts +1 -4
  8. package/dist/runtime/components/Dialog/index.vue +17 -17
  9. package/dist/runtime/components/Dialog/index.vue.d.ts +1 -4
  10. package/dist/runtime/components/Empty.d.vue.ts +1 -2
  11. package/dist/runtime/components/Empty.vue +19 -11
  12. package/dist/runtime/components/Empty.vue.d.ts +1 -2
  13. package/dist/runtime/components/FlexDeck/index.vue +21 -23
  14. package/dist/runtime/components/Form/FieldWrapper.vue +1 -1
  15. package/dist/runtime/components/Form/Fields.d.vue.ts +1 -1
  16. package/dist/runtime/components/Form/Fields.vue +26 -20
  17. package/dist/runtime/components/Form/Fields.vue.d.ts +1 -1
  18. package/dist/runtime/components/Form/InputCheckbox/index.vue +3 -6
  19. package/dist/runtime/components/Form/InputCheckboxGroup/index.vue +3 -6
  20. package/dist/runtime/components/Form/InputComponent/index.vue +2 -1
  21. package/dist/runtime/components/Form/InputCurrency/index.vue +11 -11
  22. package/dist/runtime/components/Form/InputDateTime/date_time_field.types.d.ts +3 -1
  23. package/dist/runtime/components/Form/InputDateTime/index.vue +12 -17
  24. package/dist/runtime/components/Form/InputDateTimeRange/date_range_time_field.types.d.ts +1 -1
  25. package/dist/runtime/components/Form/InputDateTimeRange/index.vue +28 -20
  26. package/dist/runtime/components/Form/InputMonth/index.vue +14 -12
  27. package/dist/runtime/components/Form/InputMonth/types.d.ts +1 -1
  28. package/dist/runtime/components/Form/InputNumber/index.vue +3 -6
  29. package/dist/runtime/components/Form/InputRadio/index.vue +3 -6
  30. package/dist/runtime/components/Form/InputRating/index.vue +3 -6
  31. package/dist/runtime/components/Form/InputSearch/index.vue +6 -7
  32. package/dist/runtime/components/Form/InputSelect/index.vue +6 -15
  33. package/dist/runtime/components/Form/InputSelectMultiple/index.vue +7 -18
  34. package/dist/runtime/components/Form/InputTags/index.vue +3 -6
  35. package/dist/runtime/components/Form/InputText/index.vue +41 -51
  36. package/dist/runtime/components/Form/InputTextarea/index.vue +3 -6
  37. package/dist/runtime/components/Form/InputTime/index.vue +32 -27
  38. package/dist/runtime/components/Form/InputTime/types.d.ts +1 -1
  39. package/dist/runtime/components/Form/InputToggle/index.vue +3 -5
  40. package/dist/runtime/components/Form/InputUploadDropzone/index.d.vue.ts +1 -4
  41. package/dist/runtime/components/Form/InputUploadDropzone/index.vue +25 -23
  42. package/dist/runtime/components/Form/InputUploadDropzone/index.vue.d.ts +1 -4
  43. package/dist/runtime/components/Form/InputUploadDropzone/types.d.ts +2 -2
  44. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.d.vue.ts +0 -5
  45. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +22 -23
  46. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue.d.ts +0 -5
  47. package/dist/runtime/components/Form/InputUploadDropzoneAuto/types.d.ts +3 -3
  48. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.d.vue.ts +0 -5
  49. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +26 -24
  50. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue.d.ts +0 -5
  51. package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/types.d.ts +3 -3
  52. package/dist/runtime/components/Form/InputUploadImageAuto/index.d.vue.ts +1 -6
  53. package/dist/runtime/components/Form/InputUploadImageAuto/index.vue +22 -23
  54. package/dist/runtime/components/Form/InputUploadImageAuto/index.vue.d.ts +1 -6
  55. package/dist/runtime/components/Form/InputUploadImageAuto/types.d.ts +3 -3
  56. package/dist/runtime/components/Form/InputWYSIWYG/EditorImagePasteExtension.js +7 -6
  57. package/dist/runtime/components/Form/InputWYSIWYG/EditorImageUploadExtension.js +13 -12
  58. package/dist/runtime/components/Form/InputWYSIWYG/EditorImageUploadNode.vue +3 -1
  59. package/dist/runtime/components/Form/InputWYSIWYG/EditorLinkPopover.vue +20 -22
  60. package/dist/runtime/components/Form/InputWYSIWYG/index.vue +140 -118
  61. package/dist/runtime/components/Form/fileState/EmptyState.vue +1 -1
  62. package/dist/runtime/components/Form/fileState/FailedState.vue +4 -2
  63. package/dist/runtime/components/Form/fileState/MultipleFilesState.d.vue.ts +4 -4
  64. package/dist/runtime/components/Form/fileState/MultipleFilesState.vue +5 -5
  65. package/dist/runtime/components/Form/fileState/MultipleFilesState.vue.d.ts +4 -4
  66. package/dist/runtime/components/Form/fileState/SuccessState.d.vue.ts +2 -2
  67. package/dist/runtime/components/Form/fileState/SuccessState.vue +8 -13
  68. package/dist/runtime/components/Form/fileState/SuccessState.vue.d.ts +2 -2
  69. package/dist/runtime/components/Form/fileState/useFilePicker.d.ts +34 -0
  70. package/dist/runtime/components/Form/fileState/useFilePicker.js +48 -0
  71. package/dist/runtime/components/Form/fileState/useFileState.d.ts +7 -9
  72. package/dist/runtime/components/Form/fileState/useFileState.js +32 -120
  73. package/dist/runtime/components/Form/fileState/useUploadImageState.d.ts +7 -8
  74. package/dist/runtime/components/Form/fileState/useUploadImageState.js +27 -301
  75. package/dist/runtime/components/Form/fileState/useUploadState.d.ts +11 -7
  76. package/dist/runtime/components/Form/fileState/useUploadState.js +52 -136
  77. package/dist/runtime/components/Form/fileState/useUploadStateMultiple.d.ts +12 -18
  78. package/dist/runtime/components/Form/fileState/useUploadStateMultiple.js +88 -226
  79. package/dist/runtime/components/Form/types.d.ts +2 -0
  80. package/dist/runtime/components/Image.vue +4 -10
  81. package/dist/runtime/components/Loader.d.vue.ts +2 -1
  82. package/dist/runtime/components/Loader.vue +10 -7
  83. package/dist/runtime/components/Loader.vue.d.ts +2 -1
  84. package/dist/runtime/components/Log/LogItem.vue +1 -3
  85. package/dist/runtime/components/Log/index.vue +1 -3
  86. package/dist/runtime/components/Table/Base.d.vue.ts +15 -1
  87. package/dist/runtime/components/Table/Base.vue +9 -29
  88. package/dist/runtime/components/Table/Base.vue.d.ts +15 -1
  89. package/dist/runtime/components/Table/ColumnText.d.vue.ts +2 -3
  90. package/dist/runtime/components/Table/ColumnText.vue +1 -1
  91. package/dist/runtime/components/Table/ColumnText.vue.d.ts +2 -3
  92. package/dist/runtime/components/Table/Pagination.vue +19 -22
  93. package/dist/runtime/components/Table/index.d.vue.ts +1 -1
  94. package/dist/runtime/components/Table/index.vue +5 -7
  95. package/dist/runtime/components/Table/index.vue.d.ts +1 -1
  96. package/dist/runtime/composables/loaderList.d.ts +2 -1
  97. package/dist/runtime/composables/loaderList.js +3 -4
  98. package/dist/runtime/composables/loaderObject.d.ts +2 -1
  99. package/dist/runtime/composables/loaderObject.js +2 -1
  100. package/dist/runtime/composables/loaderPage.js +223 -350
  101. package/dist/runtime/composables/useConfig.js +4 -3
  102. package/dist/runtime/composables/useDialog.js +3 -1
  103. package/dist/runtime/composables/useForm.d.ts +2 -2
  104. package/dist/runtime/composables/useForm.js +2 -4
  105. package/dist/runtime/composables/useMessages.d.ts +10 -0
  106. package/dist/runtime/composables/useMessages.js +10 -0
  107. package/dist/runtime/composables/useTable.js +2 -14
  108. package/dist/runtime/helpers/apiBaseHelper.js +6 -24
  109. package/dist/runtime/helpers/apiListHelper.js +2 -5
  110. package/dist/runtime/helpers/apiObjectHelper.js +2 -5
  111. package/dist/runtime/helpers/apiPageHelper.d.ts +0 -1
  112. package/dist/runtime/helpers/apiPageHelper.js +19 -38
  113. package/dist/runtime/helpers/componentHelper.js +2 -6
  114. package/dist/runtime/helpers/uploadCore.d.ts +54 -0
  115. package/dist/runtime/helpers/uploadCore.js +81 -0
  116. package/dist/runtime/i18n/valibot.d.ts +5 -68
  117. package/dist/runtime/i18n/valibot.js +33 -29
  118. package/dist/runtime/locale/en.d.ts +2 -0
  119. package/dist/runtime/locale/en.js +42 -0
  120. package/dist/runtime/locale/index.d.ts +7 -0
  121. package/dist/runtime/locale/index.js +5 -0
  122. package/dist/runtime/locale/th.d.ts +43 -0
  123. package/dist/runtime/locale/th.js +42 -0
  124. package/dist/runtime/server/tsconfig.json +1 -1
  125. package/dist/runtime/styles/main.css +1 -1
  126. package/dist/runtime/utils/ParamHelper.js +1 -1
  127. package/dist/runtime/utils/StringHelper.js +1 -4
  128. package/dist/runtime/utils/TimeHelper.js +2 -2
  129. package/dist/runtime/utils/lodash.js +2 -2
  130. package/package.json +57 -36
@@ -1,211 +1,121 @@
1
- import { useDropZone, useFileDialog } from "@vueuse/core";
2
- import PreviewModal from "./PreviewModal.vue";
3
- import { ArrayHelper, computed, ref, useOverlay, watch } from "#imports";
1
+ import { useFilePicker } from "./useFilePicker.js";
2
+ import { toFileValue, toUploadFormData, UploadState, validateFile } from "#core/helpers/uploadCore";
3
+ import { useCoreMessages } from "#core/composables/useMessages";
4
4
  import { useUploadLoader } from "#core/composables/useUpload";
5
- import { useFileAllocate, useFileProgress } from "#core/helpers/componentHelper";
5
+ import { useFileProgress } from "#core/helpers/componentHelper";
6
6
  import { StringHelper } from "#core/utils/StringHelper";
7
- import { _get } from "#core/utils/lodash";
8
- export var UploadState = /* @__PURE__ */ ((UploadState2) => {
9
- UploadState2["EMPTY"] = "empty";
10
- UploadState2["UPLOADING"] = "uploading";
11
- UploadState2["SUCCESS"] = "success";
12
- UploadState2["ERROR"] = "error";
13
- return UploadState2;
14
- })(UploadState || {});
15
- export const useUploadStateMultiple = (props, emits, onChange, setErrors, value, acceptedFileTypes, wrapperProps, dropzoneRef) => {
16
- const overlay = useOverlay();
17
- const previewModal = overlay.create(PreviewModal);
7
+ import { ArrayHelper, computed, ref, watch } from "#imports";
8
+ export { UploadState };
9
+ export const useUploadStateMultiple = (context) => {
10
+ const { props, emits, onChange, setErrors, value } = context;
11
+ const { messages, format } = useCoreMessages();
18
12
  const fileItems = ref([]);
19
- const fileAllocate = useFileAllocate(computed(() => fileItems.value[0]?.file), props);
20
- const validateFile = (file) => {
21
- if (props.accept && fileAllocate.acceptFile.value) {
22
- const acceptedTypes = fileAllocate.acceptFile.value;
23
- const acceptedTypesList = acceptedTypes.split(",").map((type) => type.trim());
24
- const fileExtension = file.name.toLowerCase().split(".").pop();
25
- const isValidFileType = acceptedTypesList.some((acceptedType) => {
26
- if (acceptedType.startsWith(".")) {
27
- return fileExtension === acceptedType.slice(1).toLowerCase();
28
- }
29
- if (!acceptedType.includes("/") && !acceptedType.includes("*")) {
30
- return fileExtension === acceptedType.toLowerCase();
31
- }
32
- if (acceptedType.endsWith("/*")) {
33
- return file.type.startsWith(acceptedType.slice(0, -2) + "/");
34
- }
35
- return file.type === acceptedType;
36
- });
37
- if (!isValidFileType) {
38
- return {
39
- valid: false,
40
- error: `\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(", ")})`
41
- };
42
- }
43
- }
44
- if (props.maxSize) {
45
- const maxSizeBytes = (fileAllocate.acceptFileSizeKb.value || 0) * 1024;
46
- if (file.size > maxSizeBytes) {
47
- const sizeLabel = fileAllocate.isAcceptFileUseMb.value ? `${fileAllocate.acceptFileSizeMb.value} MB` : `${fileAllocate.acceptFileSizeKb.value} KB`;
48
- return {
49
- valid: false,
50
- error: `\u0E02\u0E19\u0E32\u0E14\u0E44\u0E1F\u0E25\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 ${sizeLabel}`
51
- };
52
- }
53
- }
54
- return {
55
- valid: true
56
- };
57
- };
58
- const updateFileItem = (index, updates) => {
13
+ let nextId = 0;
14
+ const updateFileItem = (id, updates) => {
59
15
  fileItems.value = fileItems.value.map(
60
- (item, i) => i === index ? {
16
+ (item) => item.id === id ? {
61
17
  ...item,
62
18
  ...updates
63
19
  } : item
64
20
  );
65
21
  };
66
- const setupUpload = (fileItem, index) => {
67
- const {
68
- percent,
69
- onDownloadProgress,
70
- onUploadProgress
71
- } = useFileProgress();
72
- const request = {
22
+ const removeFileItem = (id) => {
23
+ fileItems.value = fileItems.value.filter((item) => item.id !== id);
24
+ };
25
+ const isFull = () => !!props.maxFiles && fileItems.value.length >= props.maxFiles;
26
+ const setMaxFilesError = () => {
27
+ setErrors(
28
+ format(messages.value.upload.maxFiles, {
29
+ max: props.maxFiles
30
+ })
31
+ );
32
+ };
33
+ const uploadFile = async (id, file) => {
34
+ const { percent, onDownloadProgress, onUploadProgress } = useFileProgress();
35
+ const uploadLoader = useUploadLoader({
73
36
  requestOptions: {
74
37
  ...props.requestOptions,
75
38
  onDownloadProgress,
76
39
  onUploadProgress
77
40
  },
78
41
  pathURL: props.uploadPathURL
79
- };
80
- const uploadLoader = useUploadLoader(request);
81
- updateFileItem(index, {
82
- uploadLoader,
83
- percentRef: percent
84
42
  });
85
- const stopProgressWatch = watch(percent, (newProgress) => {
86
- updateFileItem(index, {
87
- progress: newProgress
43
+ const stopProgressWatch = watch(
44
+ percent,
45
+ (progress) => updateFileItem(id, {
46
+ progress
47
+ })
48
+ );
49
+ try {
50
+ await uploadLoader.run({
51
+ data: toUploadFormData(props.bodyKey, file)
88
52
  });
89
- });
90
- updateFileItem(index, {
91
- cleanupWatchers: [stopProgressWatch]
92
- });
93
- return uploadLoader;
94
- };
95
- const processFile = (file) => {
96
- processFileAsync(file).catch((error) => {
97
- console.error("Error processing file:", error);
53
+ } finally {
54
+ stopProgressWatch();
55
+ }
56
+ if (uploadLoader.status.value.isSuccess && uploadLoader.data.value) {
57
+ const fileValue = toFileValue(uploadLoader.data.value, props, file);
58
+ removeFileItem(id);
59
+ onChange([fileValue, ...ArrayHelper.toArray(value.value)]);
60
+ emits("success", fileValue);
61
+ return;
62
+ }
63
+ updateFileItem(id, {
64
+ state: UploadState.ERROR,
65
+ error: format(messages.value.upload.error, {
66
+ message: StringHelper.getError(uploadLoader.status.value.errorData, messages.value.common.somethingWentWrong)
67
+ })
98
68
  });
99
69
  };
100
- const processFileAsync = async (file) => {
101
- const validation = validateFile(file);
102
- if (!validation.valid) {
103
- setErrors(validation.error || "Invalid file");
70
+ const processFile = async (file) => {
71
+ const error = validateFile(file, props, messages.value.upload);
72
+ if (error) {
73
+ setErrors(error);
104
74
  return;
105
75
  }
106
- if (props.maxFiles && fileItems.value.length >= props.maxFiles) {
107
- setErrors(`\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E2D\u0E31\u0E1E\u0E42\u0E2B\u0E25\u0E14\u0E44\u0E14\u0E49\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14 ${props.maxFiles} \u0E44\u0E1F\u0E25\u0E4C`);
76
+ if (isFull()) {
77
+ setMaxFilesError();
108
78
  return;
109
79
  }
110
80
  setErrors("");
111
- const fileItem = {
112
- file,
113
- state: "uploading" /* UPLOADING */,
114
- progress: 0
115
- };
116
- fileItems.value = [...fileItems.value, fileItem];
117
- const newIndex = fileItems.value.length - 1;
118
- const uploadLoader = setupUpload(fileItem, newIndex);
119
- const formData = new FormData();
120
- formData.append(props.bodyKey, file);
121
- await new Promise((resolve, reject) => {
122
- const stopSuccessWatch = watch(
123
- () => uploadLoader.status.value.isSuccess,
124
- (isSuccess) => {
125
- if (isSuccess && uploadLoader.data.value) {
126
- const fileValue = {
127
- url: _get(uploadLoader.data.value, props.responseURL),
128
- path: _get(uploadLoader.data.value, props.responsePath),
129
- name: _get(uploadLoader.data.value, props.responseName) || fileItem.file.name,
130
- size: Number(_get(uploadLoader.data.value, props.responseSize) || fileItem.file.size),
131
- id: _get(uploadLoader.data.value, props.responseID)
132
- };
133
- fileItems.value = fileItems.value.filter((_, i) => i !== newIndex);
134
- onChange([fileValue, ...ArrayHelper.toArray(value.value)]);
135
- emits("success", fileValue);
136
- stopSuccessWatch();
137
- stopErrorWatch();
138
- resolve();
139
- }
140
- }
141
- );
142
- const stopErrorWatch = watch(
143
- () => uploadLoader.status.value.isError,
144
- (isError) => {
145
- if (isError) {
146
- updateFileItem(newIndex, {
147
- state: "error" /* ERROR */,
148
- error: "\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14: " + StringHelper.getError(
149
- uploadLoader.status.value.errorData
150
- )
151
- });
152
- stopSuccessWatch();
153
- stopErrorWatch();
154
- reject(new Error("Upload failed"));
155
- }
156
- }
157
- );
158
- uploadLoader.run({
159
- data: formData
160
- });
161
- });
162
- emits("change", fileItems.value.map((item) => item.file));
163
- };
164
- const handleFileDrop = async (files) => {
165
- if (wrapperProps.value.disabled || wrapperProps.value.readonly || !files?.length) return;
166
- for (const file of files) {
167
- await processFileAsync(file);
168
- }
81
+ const id = nextId++;
82
+ fileItems.value = [
83
+ ...fileItems.value,
84
+ {
85
+ id,
86
+ file,
87
+ state: UploadState.UPLOADING,
88
+ progress: 0
89
+ }
90
+ ];
91
+ await uploadFile(id, file);
92
+ emits(
93
+ "change",
94
+ fileItems.value.map((item) => item.file)
95
+ );
169
96
  };
170
- const fileDialog = useFileDialog({
171
- accept: acceptedFileTypes.value || "",
172
- directory: false,
173
- multiple: true
174
- });
175
- const dropzone = useDropZone(dropzoneRef, {
176
- onDrop: handleFileDrop,
97
+ const picker = useFilePicker(context, {
177
98
  multiple: true,
178
- preventDefaultForUnhandled: false
99
+ onFiles: async (files) => {
100
+ for (const file of files) {
101
+ await processFile(file);
102
+ }
103
+ }
179
104
  });
180
105
  const isEmpty = computed(() => fileItems.value.length === 0);
181
- const hasUploading = computed(
182
- () => fileItems.value.some((item) => item.state === "uploading" /* UPLOADING */)
183
- );
106
+ const hasUploading = computed(() => fileItems.value.some((item) => item.state === UploadState.UPLOADING));
184
107
  const allSuccess = computed(
185
- () => fileItems.value.length > 0 && fileItems.value.every((item) => item.state === "success" /* SUCCESS */)
108
+ () => fileItems.value.length > 0 && fileItems.value.every((item) => item.state === UploadState.SUCCESS)
186
109
  );
187
- fileDialog.onChange(async (files) => {
188
- if (files?.length) {
189
- for (const file of Array.from(files)) {
190
- await processFileAsync(file);
191
- }
192
- fileDialog.reset();
193
- }
194
- });
195
110
  const handleOpenFile = () => {
196
- if (props.maxFiles && fileItems.value.length >= props.maxFiles) {
197
- setErrors(`\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E2D\u0E31\u0E1E\u0E42\u0E2B\u0E25\u0E14\u0E44\u0E14\u0E49\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14 ${props.maxFiles} \u0E44\u0E1F\u0E25\u0E4C`);
111
+ if (isFull()) {
112
+ setMaxFilesError();
198
113
  return;
199
114
  }
200
- if (wrapperProps.value.disabled || wrapperProps.value.readonly) return;
201
- fileDialog.open();
115
+ picker.handleOpenFile();
202
116
  };
203
117
  const handleDeleteFile = (index) => {
204
- const fileItem = fileItems.value[index];
205
- if (fileItem?.cleanupWatchers) {
206
- fileItem.cleanupWatchers.forEach((cleanup) => cleanup());
207
- }
208
- fileItems.value.splice(index, 1);
118
+ fileItems.value = fileItems.value.filter((_, itemIndex) => itemIndex !== index);
209
119
  if (fileItems.value.length === 0) {
210
120
  setErrors("");
211
121
  }
@@ -214,60 +124,12 @@ export const useUploadStateMultiple = (props, emits, onChange, setErrors, value,
214
124
  const handleRetryUpload = async (index) => {
215
125
  const fileItem = fileItems.value[index];
216
126
  if (!fileItem) return;
217
- updateFileItem(index, {
218
- state: "uploading" /* UPLOADING */,
127
+ updateFileItem(fileItem.id, {
128
+ state: UploadState.UPLOADING,
219
129
  error: void 0,
220
130
  progress: 0
221
131
  });
222
- const uploadLoader = setupUpload(fileItem, index);
223
- const formData = new FormData();
224
- formData.append(props.bodyKey, fileItem.file);
225
- await new Promise((resolve, reject) => {
226
- const stopSuccessWatch = watch(
227
- () => uploadLoader.status.value.isSuccess,
228
- (isSuccess) => {
229
- if (isSuccess && uploadLoader.data.value) {
230
- const fileValue = {
231
- url: _get(uploadLoader.data.value, props.responseURL),
232
- path: _get(uploadLoader.data.value, props.responsePath),
233
- name: _get(uploadLoader.data.value, props.responseName) || fileItem.file.name,
234
- size: Number(_get(uploadLoader.data.value, props.responseSize) || fileItem.file.size),
235
- id: _get(uploadLoader.data.value, props.responseID)
236
- };
237
- fileItems.value = fileItems.value.filter((_, i) => i !== index);
238
- onChange([fileValue, ...ArrayHelper.toArray(value.value)]);
239
- emits("success", fileValue);
240
- stopSuccessWatch();
241
- stopErrorWatch();
242
- resolve();
243
- }
244
- }
245
- );
246
- const stopErrorWatch = watch(
247
- () => uploadLoader.status.value.isError,
248
- (isError) => {
249
- if (isError) {
250
- updateFileItem(index, {
251
- state: "error" /* ERROR */,
252
- error: "\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14: " + StringHelper.getError(
253
- uploadLoader.status.value.errorData
254
- )
255
- });
256
- stopSuccessWatch();
257
- stopErrorWatch();
258
- reject(new Error("Upload failed"));
259
- }
260
- }
261
- );
262
- uploadLoader.run({
263
- data: formData
264
- });
265
- });
266
- };
267
- const handlePreview = (fileValue) => {
268
- previewModal.open({
269
- value: fileValue
270
- });
132
+ await uploadFile(fileItem.id, fileItem.file);
271
133
  };
272
134
  return {
273
135
  // State
@@ -276,11 +138,11 @@ export const useUploadStateMultiple = (props, emits, onChange, setErrors, value,
276
138
  hasUploading,
277
139
  allSuccess,
278
140
  // Upload utilities
279
- dropzone,
141
+ dropzone: picker.dropzone,
280
142
  // Handlers
281
143
  handleOpenFile,
282
144
  handleDeleteFile,
283
145
  handleRetryUpload,
284
- handlePreview
146
+ handlePreview: picker.openPreview
285
147
  };
286
148
  };
@@ -71,6 +71,8 @@ export interface IFieldProps {
71
71
  required?: boolean;
72
72
  help?: string;
73
73
  ui?: object | any;
74
+ /** Classes for the FormField wrapper (label, hint, error); set by FormFields from the field's `ui` */
75
+ containerUi?: object | any;
74
76
  }
75
77
  export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O> {
76
78
  type: I;
@@ -2,25 +2,19 @@
2
2
  <UseImage v-bind="$props">
3
3
  <template #loading>
4
4
  <slot name="loading">
5
- <div
6
- class="flex h-full w-full items-center justify-center"
7
- >
8
- <Loader
9
- :loading="true"
10
- />
5
+ <div class="flex h-full w-full items-center justify-center">
6
+ <Loader :loading="true" />
11
7
  </div>
12
8
  </slot>
13
9
  </template>
14
10
 
15
11
  <template #error>
16
12
  <slot name="error">
17
- <div
18
- class="flex h-full w-full items-center justify-center"
19
- >
13
+ <div class="flex h-full w-full items-center justify-center">
20
14
  <p class="text-error-400">
21
15
  <Icon
22
16
  name="i-heroicons:exclamation-circle-solid"
23
- class="text-error-400 size-8"
17
+ class="size-8 text-error-400"
24
18
  />
25
19
  </p>
26
20
  </div>
@@ -2,11 +2,12 @@ import { loaderTheme } from '#core/theme/loader';
2
2
  type __VLS_Props = {
3
3
  loading?: boolean;
4
4
  icon?: string;
5
- ui?: typeof loaderTheme['slots'];
5
+ ui?: (typeof loaderTheme)['slots'];
6
6
  class?: any;
7
7
  };
8
8
  type __VLS_Slots = {
9
9
  loading: () => any;
10
+ default: () => any;
10
11
  };
11
12
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
12
13
  loading: boolean;
@@ -4,16 +4,19 @@
4
4
  name="loading"
5
5
  >
6
6
  <div
7
-
8
- :class="theme.base({
9
- class: [ui?.base, props.class]
10
- })"
7
+ :class="
8
+ theme.base({
9
+ class: [ui?.base, props.class]
10
+ })
11
+ "
11
12
  >
12
13
  <Icon
13
14
  :name="icon"
14
- :class="[theme.icon({
15
- class: [ui?.icon]
16
- })]"
15
+ :class="[
16
+ theme.icon({
17
+ class: [ui?.icon]
18
+ })
19
+ ]"
17
20
  />
18
21
  </div>
19
22
  </slot>
@@ -2,11 +2,12 @@ import { loaderTheme } from '#core/theme/loader';
2
2
  type __VLS_Props = {
3
3
  loading?: boolean;
4
4
  icon?: string;
5
- ui?: typeof loaderTheme['slots'];
5
+ ui?: (typeof loaderTheme)['slots'];
6
6
  class?: any;
7
7
  };
8
8
  type __VLS_Slots = {
9
9
  loading: () => any;
10
+ default: () => any;
10
11
  };
11
12
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
12
13
  loading: boolean;
@@ -1,9 +1,7 @@
1
1
  <template>
2
2
  <div class="text-xs">
3
3
  <div class="mb-2 flex items-center justify-between">
4
- <p
5
- class="font-semibold"
6
- >
4
+ <p class="font-semibold">
7
5
  {{ title || "Log" }}
8
6
  </p>
9
7
  <Icon
@@ -1,8 +1,6 @@
1
1
  <template>
2
2
  <DevOnly>
3
- <TeleportSafe
4
- to="#dev-logs"
5
- >
3
+ <TeleportSafe to="#dev-logs">
6
4
  <LogItem
7
5
  v-if="typeof data !== 'undefined'"
8
6
  :data="data"
@@ -7,7 +7,21 @@ type __VLS_Props = {
7
7
  target?: string | ((row: any) => string | undefined);
8
8
  preserveQuery?: boolean;
9
9
  };
10
- declare var __VLS_21: {}, __VLS_28: {}, __VLS_30: {}, __VLS_44: `${string}-cell`, __VLS_45: any, __VLS_64: string, __VLS_65: any;
10
+ declare var __VLS_21: {}, __VLS_28: {}, __VLS_30: {}, __VLS_44: `${string}-cell`, __VLS_45: {
11
+ cell: import("@tanstack/table-core").Cell<any, unknown>;
12
+ column: import("@tanstack/table-core").Column<any, unknown>;
13
+ getValue: import("@tanstack/table-core").Getter<unknown>;
14
+ renderValue: import("@tanstack/table-core").Getter<unknown>;
15
+ row: import("@tanstack/table-core").Row<any>;
16
+ table: import("@tanstack/table-core").Table<any>;
17
+ }, __VLS_64: string, __VLS_65: {
18
+ cell: import("@tanstack/table-core").Cell<any, unknown>;
19
+ column: import("@tanstack/table-core").Column<any, unknown>;
20
+ getValue: import("@tanstack/table-core").Getter<unknown>;
21
+ renderValue: import("@tanstack/table-core").Getter<unknown>;
22
+ row: import("@tanstack/table-core").Row<any>;
23
+ table: import("@tanstack/table-core").Table<any>;
24
+ };
11
25
  type __VLS_Slots = {} & {
12
26
  [K in NonNullable<typeof __VLS_44>]?: (props: typeof __VLS_45) => any;
13
27
  } & {
@@ -38,9 +38,7 @@
38
38
  v-else-if="options.status.isError"
39
39
  name="error"
40
40
  >
41
- <div
42
- class="text-error-400 flex h-[200px] items-center justify-center text-2xl"
43
- >
41
+ <div class="flex h-[200px] items-center justify-center text-2xl text-error-400">
44
42
  {{ StringHelper.getError(options.status.errorData) }}
45
43
  </div>
46
44
  </slot>
@@ -61,18 +59,12 @@
61
59
  v-if="to && column.accessorKey !== 'actions'"
62
60
  :to="resolveTo(slotProps.row.original)"
63
61
  :target="resolveTarget(slotProps.row.original)"
64
- :rel="
65
- resolveTarget(slotProps.row.original) === '_blank' ? 'noopener noreferrer' : void 0
66
- "
62
+ :rel="resolveTarget(slotProps.row.original) === '_blank' ? 'noopener noreferrer' : void 0"
67
63
  class="absolute inset-0"
68
64
  tabindex="-1"
69
65
  aria-hidden="true"
70
66
  />
71
- <div
72
- :class="
73
- to && column.accessorKey !== 'actions' ? 'pointer-events-none relative z-10' : 'relative z-10'
74
- "
75
- >
67
+ <div :class="to && column.accessorKey !== 'actions' ? 'pointer-events-none relative z-10' : 'relative z-10'">
76
68
  <slot
77
69
  :name="`${column.accessorKey}-cell`"
78
70
  v-bind="slotProps"
@@ -86,9 +78,7 @@
86
78
  />
87
79
  <component
88
80
  :is="columnTypeComponents[column.type]"
89
- v-else-if="
90
- column.type !== COLUMN_TYPES.COMPONENT && columnTypeComponents[column.type]
91
- "
81
+ v-else-if="column.type !== COLUMN_TYPES.COMPONENT && columnTypeComponents[column.type]"
92
82
  :value="transformValue(column, slotProps.row)"
93
83
  :column="column"
94
84
  :row="slotProps.row"
@@ -135,18 +125,12 @@ import {
135
125
  } from "#core/components/Table/types";
136
126
  import ColumnNumber from "#core/components/Table/ColumnNumber.vue";
137
127
  import ColumnImage from "#core/components/Table/ColumnImage.vue";
138
- import {
139
- useAppConfig,
140
- useRoute,
141
- useUiConfig,
142
- useWatchChange,
143
- StringHelper
144
- } from "#imports";
128
+ import { useAppConfig, useRoute, useUiConfig, useWatchChange, StringHelper } from "#imports";
145
129
  import ColumnDateTime from "#core/components/Table/ColumnDateTime.vue";
146
130
  import Empty from "#core/components/Empty.vue";
147
131
  import ColumnDate from "#core/components/Table/ColumnDate.vue";
148
132
  import ColumnText from "#core/components/Table/ColumnText.vue";
149
- import UTable from "#ui/components/Table";
133
+ import UTable from "#ui/components/Table.vue";
150
134
  import Pagination from "./Pagination.vue";
151
135
  import { tableTheme } from "#core/theme/table";
152
136
  const emits = defineEmits(["pageChange", "search"]);
@@ -170,9 +154,7 @@ const VNodeRenderer = defineComponent({
170
154
  });
171
155
  const route = useRoute();
172
156
  const slots = useSlots();
173
- const forwardedSlotNames = computed(
174
- () => Object.keys(slots).filter((name) => !name.endsWith("-cell"))
175
- );
157
+ const forwardedSlotNames = computed(() => Object.keys(slots).filter((name) => !name.endsWith("-cell")));
176
158
  const columnTypeComponents = {
177
159
  [COLUMN_TYPES.NUMBER]: ColumnNumber,
178
160
  [COLUMN_TYPES.IMAGE]: ColumnImage,
@@ -183,9 +165,7 @@ const columnTypeComponents = {
183
165
  const theme = computed(() => useUiConfig(tableTheme, "table")());
184
166
  const config = useAppConfig();
185
167
  const page = ref(props.options.pageOptions?.currentPage || 1);
186
- const pageLimit = ref(
187
- props.options.pageOptions?.limit || config.core.limit_per_page
188
- );
168
+ const pageLimit = ref(props.options.pageOptions?.limit || config.core.limit_per_page);
189
169
  const uTableCompatibleColumns = computed(
190
170
  () => props.options.columns.map((col) => ({
191
171
  ...col,
@@ -216,7 +196,7 @@ const resolveTo = (rowOriginal) => {
216
196
  ...resolved,
217
197
  query: {
218
198
  ...route.query,
219
- ...resolved.query || {}
199
+ ...resolved.query
220
200
  }
221
201
  };
222
202
  };
@@ -7,7 +7,21 @@ type __VLS_Props = {
7
7
  target?: string | ((row: any) => string | undefined);
8
8
  preserveQuery?: boolean;
9
9
  };
10
- declare var __VLS_21: {}, __VLS_28: {}, __VLS_30: {}, __VLS_44: `${string}-cell`, __VLS_45: any, __VLS_64: string, __VLS_65: any;
10
+ declare var __VLS_21: {}, __VLS_28: {}, __VLS_30: {}, __VLS_44: `${string}-cell`, __VLS_45: {
11
+ cell: import("@tanstack/table-core").Cell<any, unknown>;
12
+ column: import("@tanstack/table-core").Column<any, unknown>;
13
+ getValue: import("@tanstack/table-core").Getter<unknown>;
14
+ renderValue: import("@tanstack/table-core").Getter<unknown>;
15
+ row: import("@tanstack/table-core").Row<any>;
16
+ table: import("@tanstack/table-core").Table<any>;
17
+ }, __VLS_64: string, __VLS_65: {
18
+ cell: import("@tanstack/table-core").Cell<any, unknown>;
19
+ column: import("@tanstack/table-core").Column<any, unknown>;
20
+ getValue: import("@tanstack/table-core").Getter<unknown>;
21
+ renderValue: import("@tanstack/table-core").Getter<unknown>;
22
+ row: import("@tanstack/table-core").Row<any>;
23
+ table: import("@tanstack/table-core").Table<any>;
24
+ };
11
25
  type __VLS_Slots = {} & {
12
26
  [K in NonNullable<typeof __VLS_44>]?: (props: typeof __VLS_45) => any;
13
27
  } & {
@@ -1,13 +1,12 @@
1
- import { type ComponentProps } from 'vue';
2
1
  import type { TableColumn } from '@nuxt/ui';
3
- import NuxtLink from '#app/components/nuxt-link';
2
+ import type { NuxtLinkProps } from '#app';
4
3
  type __VLS_Props = {
5
4
  value: any;
6
5
  row: any;
7
6
  column: TableColumn<any> & {
8
7
  meta: {
9
8
  max: number;
10
- link?: ComponentProps<typeof NuxtLink>;
9
+ link?: NuxtLinkProps;
11
10
  };
12
11
  };
13
12
  };
@@ -24,7 +24,7 @@ const getValue = computed(() => {
24
24
  const value = props.value;
25
25
  const max = props.column?.meta?.max;
26
26
  if (max) {
27
- return StringHelper.truncate(value, max);
27
+ return StringHelper.truncate(value, max) || "-";
28
28
  }
29
29
  if (typeof value === "string") {
30
30
  return value || "-";