@finema/core 2.23.0 → 2.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 (33) hide show
  1. package/README.md +79 -79
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +1 -1
  4. package/dist/runtime/components/Dialog/index.vue +6 -2
  5. package/dist/runtime/components/Form/FieldWrapper.vue +13 -13
  6. package/dist/runtime/components/Form/Fields.vue +13 -13
  7. package/dist/runtime/components/Form/InputCheckbox/index.vue +18 -18
  8. package/dist/runtime/components/Form/InputNumber/index.vue +20 -20
  9. package/dist/runtime/components/Form/InputSelectMultiple/index.vue +43 -43
  10. package/dist/runtime/components/Form/InputText/index.vue +74 -74
  11. package/dist/runtime/components/Form/InputTextarea/index.vue +18 -18
  12. package/dist/runtime/components/Form/InputToggle/index.vue +17 -17
  13. package/dist/runtime/components/Form/InputUploadDropzone/index.vue +30 -30
  14. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +1 -8
  15. package/dist/runtime/components/Form/fileState/EmptyState.vue +21 -21
  16. package/dist/runtime/components/Form/fileState/FailedState.vue +33 -33
  17. package/dist/runtime/components/Form/fileState/LoadingState.vue +24 -24
  18. package/dist/runtime/components/Form/fileState/PreviewModal.vue +23 -23
  19. package/dist/runtime/components/Form/fileState/SuccessState.vue +9 -3
  20. package/dist/runtime/components/Form/fileState/useUploadState.js +12 -13
  21. package/dist/runtime/components/Form/index.vue +5 -5
  22. package/dist/runtime/components/Image.vue +28 -28
  23. package/dist/runtime/components/Log/index.vue +17 -17
  24. package/dist/runtime/components/Table/ColumnDate.vue +1 -1
  25. package/dist/runtime/components/Table/ColumnDateTime.vue +1 -1
  26. package/dist/runtime/components/Table/ColumnImage.vue +4 -4
  27. package/dist/runtime/components/Table/ColumnText.vue +1 -1
  28. package/dist/runtime/composables/useDialog.d.ts +4 -1
  29. package/dist/runtime/composables/useDialog.js +16 -5
  30. package/dist/runtime/server/tsconfig.json +3 -3
  31. package/dist/runtime/theme/dialog.d.ts +6 -0
  32. package/dist/runtime/theme/dialog.js +7 -1
  33. package/package.json +2 -2
@@ -1,21 +1,21 @@
1
1
  <template>
2
- <FieldWrapper
3
- v-bind="wrapperProps"
4
- label=""
5
- description=""
6
- >
7
- <Switch
8
- :model-value="value"
9
- :disabled="wrapperProps.disabled"
10
- :name="name"
11
- :ui="ui"
12
- :label="label"
13
- :description="description"
14
- :loading="loading"
15
- :loading-icon="loadingIcon"
16
- @update:modelValue="onChange"
17
- />
18
- </FieldWrapper>
2
+ <FieldWrapper
3
+ v-bind="wrapperProps"
4
+ label=""
5
+ description=""
6
+ >
7
+ <Switch
8
+ :model-value="value"
9
+ :disabled="wrapperProps.disabled"
10
+ :name="name"
11
+ :ui="ui"
12
+ :label="label"
13
+ :description="description"
14
+ :loading="loading"
15
+ :loading-icon="loadingIcon"
16
+ @update:modelValue="onChange"
17
+ />
18
+ </FieldWrapper>
19
19
  </template>
20
20
 
21
21
  <script setup>
@@ -1,34 +1,34 @@
1
1
  <template>
2
- <FieldWrapper v-bind="wrapperProps">
3
- <div
4
- ref="dropzoneRef"
5
- :class="theme.base()"
6
- >
7
- <div :class="theme.wrapper()">
8
- <!-- Empty State -->
9
- <EmptyState
10
- v-if="uploadState.isEmpty.value"
11
- :theme="theme"
12
- :select-file-label="selectFileLabel"
13
- :select-file-sub-label="selectFileSubLabel"
14
- :placeholder="placeholder"
15
- @open-file="uploadState.handleOpenFile"
16
- />
17
-
18
- <!-- Success State -->
19
- <SuccessState
20
- v-if="uploadState.isSuccess.value"
21
- :theme="theme"
22
- :value="value"
23
- :disabled="wrapperProps.disabled"
24
- :readonly="wrapperProps.readonly"
25
- @preview="uploadState.handlePreview"
26
- @download="handleDownloadFile"
27
- @delete="uploadState.handleDeleteFile"
28
- />
29
- </div>
30
- </div>
31
- </FieldWrapper>
2
+ <FieldWrapper v-bind="wrapperProps">
3
+ <div
4
+ ref="dropzoneRef"
5
+ :class="theme.base()"
6
+ >
7
+ <div :class="theme.wrapper()">
8
+ <!-- Empty State -->
9
+ <EmptyState
10
+ v-if="uploadState.isEmpty.value"
11
+ :theme="theme"
12
+ :select-file-label="selectFileLabel"
13
+ :select-file-sub-label="selectFileSubLabel"
14
+ :placeholder="placeholder"
15
+ @open-file="uploadState.handleOpenFile"
16
+ />
17
+
18
+ <!-- Success State -->
19
+ <SuccessState
20
+ v-if="uploadState.isSuccess.value"
21
+ :theme="theme"
22
+ :value="value"
23
+ :disabled="wrapperProps.disabled"
24
+ :readonly="wrapperProps.readonly"
25
+ @preview="uploadState.handlePreview"
26
+ @download="handleDownloadFile"
27
+ @delete="uploadState.handleDeleteFile"
28
+ />
29
+ </div>
30
+ </div>
31
+ </FieldWrapper>
32
32
  </template>
33
33
 
34
34
  <script setup>
@@ -57,7 +57,7 @@ import SuccessState from "../fileState/SuccessState.vue";
57
57
  import LoadingState from "../fileState/LoadingState.vue";
58
58
  import FailedState from "../fileState/FailedState.vue";
59
59
  import { useUploadState } from "../fileState/useUploadState";
60
- import { computed, useTemplateRef, useWatchChange } from "#imports";
60
+ import { computed, useTemplateRef } from "#imports";
61
61
  import FieldWrapper from "#core/components/Form/FieldWrapper.vue";
62
62
  import { useFieldHOC } from "#core/composables/useForm";
63
63
  import { uploadFileDropzoneTheme } from "#core/theme/uploadFileDropzone";
@@ -114,13 +114,6 @@ const uploadState = useUploadState(
114
114
  wrapperProps,
115
115
  dropzoneRef
116
116
  );
117
- useWatchChange(() => value.value, (newValue) => {
118
- if (typeof newValue === "object" && newValue !== null) {
119
- onChange(newValue);
120
- } else {
121
- onChange(void 0);
122
- }
123
- });
124
117
  const theme = computed(
125
118
  () => useUiConfig(uploadFileDropzoneTheme, "uploadFileDropzone")({
126
119
  dragover: uploadState.dropzone.isOverDropZone.value && uploadState.isEmpty.value,
@@ -1,25 +1,25 @@
1
1
  <template>
2
- <div :class="theme.placeholderWrapper()">
3
- <Icon
4
- :name="icons.uploadIcon"
5
- :class="theme.labelIcon()"
6
- />
7
- <div :class="theme.labelWrapper()">
8
- <p
9
- class="text-primary cursor-pointer font-bold"
10
- @click="$emit('openFile')"
11
- >
12
- {{ selectFileLabel }}
13
- </p>
14
- <p>{{ selectFileSubLabel }}</p>
15
- </div>
16
- <p
17
- v-if="placeholder"
18
- :class="theme.placeholder()"
19
- >
20
- {{ placeholder }}
21
- </p>
22
- </div>
2
+ <div :class="theme.placeholderWrapper()">
3
+ <Icon
4
+ :name="icons.uploadIcon"
5
+ :class="theme.labelIcon()"
6
+ />
7
+ <div :class="theme.labelWrapper()">
8
+ <p
9
+ class="text-primary cursor-pointer font-bold"
10
+ @click="$emit('openFile')"
11
+ >
12
+ {{ selectFileLabel }}
13
+ </p>
14
+ <p>{{ selectFileSubLabel }}</p>
15
+ </div>
16
+ <p
17
+ v-if="placeholder"
18
+ :class="theme.placeholder()"
19
+ >
20
+ {{ placeholder }}
21
+ </p>
22
+ </div>
23
23
  </template>
24
24
 
25
25
  <script setup>
@@ -1,37 +1,37 @@
1
1
  <template>
2
- <div :class="theme.onFailedWrapper()">
3
- <div :class="theme.onFailedFailedImgWrapper()">
4
- <Icon
5
- :name="getFileIcon(selectedFile)"
6
- :class="theme.onFailedFailedIconClass()"
7
- />
8
- </div>
9
- <div :class="theme.onFailedTextWrapper()">
10
- <div class="truncate">
11
- <h1 class="truncate font-bold">
12
- {{ selectedFile.name }}
13
- </h1>
14
- <p class="text-error truncate font-light">
15
- {{ uploadFailedLabel }}
16
- </p>
17
- <Button
18
- variant="link"
19
- :icon="icons.actionRetryIcon"
20
- :class="theme.actionRetryBtnClass()"
21
- color="primary"
22
- @click="$emit('retry')"
23
- >
24
- {{ retryLabel }}
25
- </Button>
26
- </div>
27
- <Icon
28
- :name="icons.actionDeleteIcon"
29
- :class="theme.actionDeleteIconClass()"
30
- title="ลบไฟล์"
31
- @click="$emit('delete')"
32
- />
33
- </div>
34
- </div>
2
+ <div :class="theme.onFailedWrapper()">
3
+ <div :class="theme.onFailedFailedImgWrapper()">
4
+ <Icon
5
+ :name="getFileIcon(selectedFile)"
6
+ :class="theme.onFailedFailedIconClass()"
7
+ />
8
+ </div>
9
+ <div :class="theme.onFailedTextWrapper()">
10
+ <div class="truncate">
11
+ <h1 class="truncate font-bold">
12
+ {{ selectedFile.name }}
13
+ </h1>
14
+ <p class="text-error truncate font-light">
15
+ {{ uploadFailedLabel }}
16
+ </p>
17
+ <Button
18
+ variant="link"
19
+ :icon="icons.actionRetryIcon"
20
+ :class="theme.actionRetryBtnClass()"
21
+ color="primary"
22
+ @click="$emit('retry')"
23
+ >
24
+ {{ retryLabel }}
25
+ </Button>
26
+ </div>
27
+ <Icon
28
+ :name="icons.actionDeleteIcon"
29
+ :class="theme.actionDeleteIconClass()"
30
+ title="ลบไฟล์"
31
+ @click="$emit('delete')"
32
+ />
33
+ </div>
34
+ </div>
35
35
  </template>
36
36
 
37
37
  <script setup>
@@ -1,28 +1,28 @@
1
1
  <template>
2
- <div :class="theme.onLoadingWrapper()">
3
- <div :class="theme.onLoadingPlaceholderWrapper()">
4
- <Icon
5
- :name="getFileIcon(selectedFile)"
6
- :class="theme.onLoadingPlaceholderIconClass()"
7
- />
8
- </div>
9
- <div :class="theme.onLoadingTextWrapper()">
10
- <div class="truncate">
11
- <h1 class="truncate font-bold">
12
- {{ selectedFile.name }}
13
- </h1>
14
- <p class="truncate font-light text-gray-400">
15
- {{ getFileSize(selectedFile) }} - {{ percent }}% {{ uploadingLabel }}
16
- </p>
17
- </div>
18
- <div>
19
- <Icon
20
- :name="icons.loadingIcon"
21
- :class="theme.onLoadingLoadingIconClass()"
22
- />
23
- </div>
24
- </div>
25
- </div>
2
+ <div :class="theme.onLoadingWrapper()">
3
+ <div :class="theme.onLoadingPlaceholderWrapper()">
4
+ <Icon
5
+ :name="getFileIcon(selectedFile)"
6
+ :class="theme.onLoadingPlaceholderIconClass()"
7
+ />
8
+ </div>
9
+ <div :class="theme.onLoadingTextWrapper()">
10
+ <div class="truncate">
11
+ <h1 class="truncate font-bold">
12
+ {{ selectedFile.name }}
13
+ </h1>
14
+ <p class="truncate font-light text-gray-400">
15
+ {{ getFileSize(selectedFile) }} - {{ percent }}% {{ uploadingLabel }}
16
+ </p>
17
+ </div>
18
+ <div>
19
+ <Icon
20
+ :name="icons.loadingIcon"
21
+ :class="theme.onLoadingLoadingIconClass()"
22
+ />
23
+ </div>
24
+ </div>
25
+ </div>
26
26
  </template>
27
27
 
28
28
  <script setup>
@@ -1,29 +1,29 @@
1
1
  <template>
2
- <Modal
3
- :close="{ onClick: () => emits('close', false) }"
4
- :dismissible="false"
5
- :title="value?.name"
2
+ <Modal
3
+ :close="{ onClick: () => emits('close', false) }"
4
+ :dismissible="false"
5
+ :title="value?.name"
6
6
  :ui="{
7
7
  content: 'max-w-3xl'
8
- }"
9
- >
10
- <template #body>
11
- <div class="flex justify-center">
12
- <img
13
- v-if="value && isImageFromPath(value.path)"
14
- :src="value.url"
15
- alt="img-preview"
16
- class="max-h-96 max-w-full rounded-lg"
17
- />
18
- <video
19
- v-else-if="value && isVideoFromPath(value.path)"
20
- :src="value.url"
21
- controls
22
- class="max-h-96 max-w-full"
23
- />
24
- </div>
25
- </template>
26
- </Modal>
8
+ }"
9
+ >
10
+ <template #body>
11
+ <div class="flex justify-center">
12
+ <img
13
+ v-if="value && isImageFromPath(value.path)"
14
+ :src="value.url"
15
+ alt="img-preview"
16
+ class="max-h-96 max-w-full rounded-lg"
17
+ />
18
+ <video
19
+ v-else-if="value && isVideoFromPath(value.path)"
20
+ :src="value.url"
21
+ controls
22
+ class="max-h-96 max-w-full"
23
+ />
24
+ </div>
25
+ </template>
26
+ </Modal>
27
27
  </template>
28
28
 
29
29
  <script setup>
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <div :class="theme.onPreviewWrapper()">
3
- <div v-if="isImageFromPath(value.path)" :class="theme.onPreviewImgWrapper()">
3
+ <div
4
+ v-if="isImageFromPath(value.path)"
5
+ :class="theme.onPreviewImgWrapper()"
6
+ >
4
7
  <div
5
8
  class="size-full overflow-hidden"
6
9
  >
@@ -11,8 +14,11 @@
11
14
  />
12
15
  </div>
13
16
  </div>
14
- <div v-else :class="theme.onPreviewFileWrapper()">
15
- <div >
17
+ <div
18
+ v-else
19
+ :class="theme.onPreviewFileWrapper()"
20
+ >
21
+ <div>
16
22
  <Icon
17
23
  :name="icons.filePreviewIcon"
18
24
  :class="theme.onPreviewFileClass()"
@@ -1,12 +1,11 @@
1
1
  import { useDropZone, useFileDialog } from "@vueuse/core";
2
+ import { useWatchTrue } from "./../../../../../dist/runtime/composables/useWatch";
2
3
  import PreviewModal from "./PreviewModal.vue";
3
- import { computed, ref, useOverlay, watch } from "#imports";
4
+ import { computed, ref, useOverlay } from "#imports";
4
5
  import { useUploadLoader } from "#core/composables/useUpload";
5
6
  import { useFileAllocate, useFileProgress } from "#core/helpers/componentHelper";
6
7
  import { StringHelper } from "#core/utils/StringHelper";
7
8
  import { _get } from "#core/utils/lodash";
8
- const overlay = useOverlay();
9
- const previewModal = overlay.create(PreviewModal);
10
9
  export var UploadState = /* @__PURE__ */ ((UploadState2) => {
11
10
  UploadState2["EMPTY"] = "empty";
12
11
  UploadState2["UPLOADING"] = "uploading";
@@ -15,6 +14,8 @@ export var UploadState = /* @__PURE__ */ ((UploadState2) => {
15
14
  return UploadState2;
16
15
  })(UploadState || {});
17
16
  export const useUploadState = (props, emits, onChange, setErrors, value, acceptedFileTypes, wrapperProps, dropzoneRef) => {
17
+ const overlay = useOverlay();
18
+ const previewModal = overlay.create(PreviewModal);
18
19
  const selectedFile = ref();
19
20
  const fileAllocate = useFileAllocate(selectedFile, props);
20
21
  const {
@@ -73,7 +74,7 @@ export const useUploadState = (props, emits, onChange, setErrors, value, accepte
73
74
  selectedFile.value = file;
74
75
  emits("change", file);
75
76
  const formData = new FormData();
76
- formData.append(props.bodyKey || "file", file);
77
+ formData.append(props.bodyKey, file);
77
78
  upload.run({
78
79
  data: formData
79
80
  });
@@ -132,7 +133,7 @@ export const useUploadState = (props, emits, onChange, setErrors, value, accepte
132
133
  const handleRetryUpload = () => {
133
134
  if (selectedFile.value) {
134
135
  const formData = new FormData();
135
- formData.append(props.bodyKey || "file", selectedFile.value);
136
+ formData.append(props.bodyKey, selectedFile.value);
136
137
  upload.run(formData);
137
138
  }
138
139
  };
@@ -141,10 +142,10 @@ export const useUploadState = (props, emits, onChange, setErrors, value, accepte
141
142
  value: value.value
142
143
  });
143
144
  };
144
- watch(
145
+ useWatchTrue(
145
146
  () => upload.status.value.isSuccess,
146
- (isSuccess2) => {
147
- if (isSuccess2 && upload.data.value) {
147
+ () => {
148
+ if (upload.data.value) {
148
149
  const fileValue = {
149
150
  url: _get(upload.data.value, props.responseURL),
150
151
  path: _get(upload.data.value, props.responsePath),
@@ -156,12 +157,10 @@ export const useUploadState = (props, emits, onChange, setErrors, value, accepte
156
157
  }
157
158
  }
158
159
  );
159
- watch(
160
+ useWatchTrue(
160
161
  () => upload.status.value.isError,
161
- (isError2) => {
162
- if (isError2) {
163
- setErrors("\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14: " + StringHelper.getError(upload.status.value.errorData));
164
- }
162
+ () => {
163
+ setErrors("\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14: " + StringHelper.getError(upload.status.value.errorData));
165
164
  }
166
165
  );
167
166
  return {
@@ -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>
@@ -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>
@@ -2,7 +2,8 @@ export declare const enum DialogType {
2
2
  ERROR = "error",
3
3
  INFO = "info",
4
4
  SUCCESS = "success",
5
- WARNING = "warning"
5
+ WARNING = "warning",
6
+ LOADING = "loading"
6
7
  }
7
8
  export interface IDialogMetaItem {
8
9
  title: string;
@@ -21,5 +22,7 @@ export interface IDialog {
21
22
  success: (payload: IDialogMetaItem) => Promise<boolean>;
22
23
  warning: (payload: IDialogMetaItem) => Promise<boolean>;
23
24
  confirm: (payload: IDialogMetaItem) => Promise<boolean>;
25
+ loading: (payload: Partial<IDialogMetaItem>) => Promise<boolean>;
26
+ close: () => Promise<void>;
24
27
  }
25
28
  export declare const useDialog: () => IDialog;
@@ -5,15 +5,14 @@ export var DialogType = /* @__PURE__ */ ((DialogType2) => {
5
5
  DialogType2["INFO"] = "info";
6
6
  DialogType2["SUCCESS"] = "success";
7
7
  DialogType2["WARNING"] = "warning";
8
+ DialogType2["LOADING"] = "loading";
8
9
  return DialogType2;
9
10
  })(DialogType || {});
10
11
  export const useDialog = () => {
11
12
  const overlay = useOverlay();
13
+ const modal = overlay.create(Dialog);
12
14
  const openDialog = async (payload) => {
13
- const modal = overlay.create(Dialog, {
14
- props: payload
15
- });
16
- const result = await modal.open();
15
+ const result = await modal.open(payload);
17
16
  const res = await result.result;
18
17
  return new Promise((resolve, reject) => {
19
18
  if (res) {
@@ -54,11 +53,23 @@ export const useDialog = () => {
54
53
  isConfirm: true
55
54
  });
56
55
  };
56
+ const loading = async (payload = {}) => {
57
+ return openDialog({
58
+ ...payload,
59
+ title: payload.title || "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E42\u0E2B\u0E25\u0E14...",
60
+ type: "loading" /* LOADING */
61
+ });
62
+ };
63
+ const close = async () => {
64
+ return modal.close();
65
+ };
57
66
  return {
58
67
  error,
59
68
  success,
60
69
  info,
61
70
  warning,
62
- confirm
71
+ confirm,
72
+ loading,
73
+ close
63
74
  };
64
75
  };