@finema/core 2.6.2 → 2.7.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 (36) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +18 -6
  3. package/dist/runtime/components/DevToolsWindow/index.vue +6 -4
  4. package/dist/runtime/components/FlexDeck/Base.vue +4 -2
  5. package/dist/runtime/components/Form/Fields.vue +28 -19
  6. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +114 -0
  7. package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue.d.ts +19 -0
  8. package/dist/runtime/components/Form/InputUploadDropzoneAuto/types.d.ts +23 -0
  9. package/dist/runtime/components/Form/InputUploadDropzoneAuto/types.js +0 -0
  10. package/dist/runtime/components/Form/types.d.ts +2 -1
  11. package/dist/runtime/components/Image.vue +3 -3
  12. package/dist/runtime/components/Table/Base.vue +1 -1
  13. package/dist/runtime/components/Table/index.vue +4 -2
  14. package/dist/runtime/composables/useConfig.d.ts +1 -0
  15. package/dist/runtime/composables/useConfig.js +3 -0
  16. package/dist/runtime/composables/useDialog.js +3 -1
  17. package/dist/runtime/composables/useForm.d.ts +1 -1
  18. package/dist/runtime/composables/useForm.js +6 -2
  19. package/dist/runtime/helpers/apiBaseHelper.js +3 -1
  20. package/dist/runtime/helpers/componentHelper.d.ts +1 -0
  21. package/dist/runtime/helpers/componentHelper.js +5 -0
  22. package/dist/runtime/theme/button.js +5 -1
  23. package/dist/runtime/theme/dialog.js +15 -5
  24. package/dist/runtime/theme/form.js +3 -1
  25. package/dist/runtime/theme/icons.js +3 -1
  26. package/dist/runtime/theme/index.d.ts +1 -0
  27. package/dist/runtime/theme/index.js +1 -0
  28. package/dist/runtime/theme/input.js +6 -2
  29. package/dist/runtime/theme/inputNumber.js +6 -2
  30. package/dist/runtime/theme/loader.js +14 -4
  31. package/dist/runtime/theme/selectMenu.js +3 -1
  32. package/dist/runtime/theme/textarea.js +5 -1
  33. package/dist/runtime/theme/uploadFileDropzone.d.ts +24 -0
  34. package/dist/runtime/theme/uploadFileDropzone.js +24 -0
  35. package/dist/runtime/utils/FileHelper.js +3 -1
  36. package/package.json +5 -3
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finema/core",
3
- "version": "2.6.2",
3
+ "version": "2.7.0",
4
4
  "configKey": "core",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
package/dist/module.mjs CHANGED
@@ -3,13 +3,17 @@ import defu from 'defu';
3
3
  import * as theme from '../dist/runtime/theme/index.js';
4
4
 
5
5
  const name = "@finema/core";
6
- const version = "2.6.2";
6
+ const version = "2.7.0";
7
7
 
8
8
  const nuxtAppOptions = {
9
9
  head: {
10
- htmlAttrs: { lang: "en" },
10
+ htmlAttrs: {
11
+ lang: "en"
12
+ },
11
13
  meta: [
12
- { charset: "utf-8" },
14
+ {
15
+ charset: "utf-8"
16
+ },
13
17
  {
14
18
  name: "viewport",
15
19
  content: "width=device-width, initial-scale=1"
@@ -68,7 +72,9 @@ const module = defineNuxtModule({
68
72
  // Default configuration options of the Nuxt module
69
73
  defaults: {},
70
74
  async setup(_options, _nuxt) {
71
- const { resolve } = createResolver(import.meta.url);
75
+ const {
76
+ resolve
77
+ } = createResolver(import.meta.url);
72
78
  const runtimeDir = resolve("./runtime");
73
79
  _nuxt.options.build.transpile.push(runtimeDir);
74
80
  _nuxt.options.alias["#core"] = runtimeDir;
@@ -82,7 +88,9 @@ const module = defineNuxtModule({
82
88
  _nuxt.options.appConfig.core || {},
83
89
  core
84
90
  );
85
- _nuxt.options.colorMode = { preference: "light" };
91
+ _nuxt.options.colorMode = {
92
+ preference: "light"
93
+ };
86
94
  _nuxt.options.appConfig.ui = {
87
95
  colors: {
88
96
  primary: "main",
@@ -109,7 +117,11 @@ const module = defineNuxtModule({
109
117
  _nuxt.options.build
110
118
  );
111
119
  _nuxt.options.vite = defu(
112
- { optimizeDeps: { include: [..._nuxt.options.vite?.optimizeDeps?.include || [], "@wdns/vue-code-block"] } },
120
+ {
121
+ optimizeDeps: {
122
+ include: [..._nuxt.options.vite?.optimizeDeps?.include || [], "@wdns/vue-code-block"]
123
+ }
124
+ },
113
125
  _nuxt.options.vite
114
126
  );
115
127
  await installModule("@nuxt/ui", {
@@ -8,7 +8,7 @@
8
8
  <!-- Draggable Title Bar -->
9
9
  <div class="flex items-center justify-between px-2 py-1 select-none">
10
10
  <p
11
- class="text-sm font-semibold cursor-move flex-grow"
11
+ class="flex-grow cursor-move text-sm font-semibold"
12
12
  @mousedown.prevent="handleDragStart"
13
13
  >
14
14
  Debug Tools
@@ -37,7 +37,7 @@
37
37
  <!-- Content Area Target for Logs -->
38
38
  <div
39
39
  id="dev-logs"
40
- class="flex flex-col flex-1 space-y-1 p-2 overflow-auto"
40
+ class="flex flex-1 flex-col space-y-1 overflow-auto p-2"
41
41
  :style="{ height: `calc(${devToolsHeight} - 40px)` }"
42
42
  />
43
43
 
@@ -83,7 +83,7 @@
83
83
 
84
84
  <!-- Toggle button for this DevToolsWindow -->
85
85
  <div
86
- class="fixed bottom-1 right-1 z-[99999]"
86
+ class="fixed right-1 bottom-1 z-[99999]"
87
87
  >
88
88
  <Button
89
89
  :icon="isShowDevTools ? 'heroicons:x-mark' : 'heroicons:information-circle'"
@@ -299,7 +299,9 @@ onMounted(() => {
299
299
  }
300
300
  });
301
301
  }
302
- }, { immediate: true });
302
+ }, {
303
+ immediate: true
304
+ });
303
305
  });
304
306
  onUnmounted(() => {
305
307
  if (isDragging.value) handleDragEnd();
@@ -40,7 +40,7 @@
40
40
  <div class="flex h-60 items-center justify-center">
41
41
  <Icon
42
42
  name="i-svg-spinners:180-ring-with-bg"
43
- class="text-primary size-8"
43
+ class="size-8 text-primary"
44
44
  />
45
45
  </div>
46
46
  </slot>
@@ -108,7 +108,9 @@ const props = defineProps({
108
108
  type: Boolean,
109
109
  default: false
110
110
  },
111
- containerClass: { type: [String, Array, Object] }
111
+ containerClass: {
112
+ type: [String, Array, Object]
113
+ }
112
114
  });
113
115
  const bottomEdgeElement = ref(null);
114
116
  const page = ref(props.pageOptions?.currentPage || 1);
@@ -1,20 +1,20 @@
1
1
  <template>
2
- <div
2
+ <div
3
3
  :class="[theme.base({
4
4
  class: [$props.class, ui?.base]
5
- })]"
6
- >
7
- <component
8
- :is="componentMap[option.type] || option.component"
9
- v-for="option in options.filter((item) => !item.isHide)"
10
- :key="option.props.name"
11
- :class="option.class"
12
- :form="form"
13
- v-bind="getFieldBinding(option)"
14
- :type="option.type === INPUT_TYPES.PASSWORD ? 'password' : void 0"
15
- v-on="option.on ?? {}"
16
- />
17
- </div>
5
+ })]"
6
+ >
7
+ <component
8
+ :is="componentMap[option.type] || option.component"
9
+ v-for="option in options.filter((item) => !item.isHide)"
10
+ :key="option.props.name"
11
+ :class="option.class"
12
+ :form="form"
13
+ v-bind="getFieldBinding(option)"
14
+ :type="option.type === INPUT_TYPES.PASSWORD ? 'password' : void 0"
15
+ v-on="option.on ?? {}"
16
+ />
17
+ </div>
18
18
  </template>
19
19
 
20
20
  <script setup>
@@ -27,6 +27,7 @@ import FormInputCheckbox from "./InputCheckbox/index.vue";
27
27
  import FormInputSelect from "./InputSelect/index.vue";
28
28
  import FormInputSelectMultiple from "./InputSelectMultiple/index.vue";
29
29
  import FormInputDateTime from "./InputDateTime/index.vue";
30
+ import FormInputUploadDropzoneAuto from "./InputUploadDropzoneAuto/index.vue";
30
31
  import { INPUT_TYPES } from "#core/components/Form/types";
31
32
  import { formTheme } from "#core/theme/form";
32
33
  import { useUiConfig } from "#core/composables/useConfig";
@@ -63,13 +64,15 @@ const componentMap = {
63
64
  [INPUT_TYPES.UPLOAD_FILE_CLASSIC_AUTO]: void 0,
64
65
  [INPUT_TYPES.UPLOAD_IMAGE_AUTO]: void 0,
65
66
  [INPUT_TYPES.UPLOAD_DROPZONE]: void 0,
66
- [INPUT_TYPES.UPLOAD_DROPZONE_AUTO]: void 0,
67
+ [INPUT_TYPES.UPLOAD_DROPZONE_AUTO]: FormInputUploadDropzoneAuto,
67
68
  [INPUT_TYPES.UPLOAD_DROPZONE_AUTO_MULTIPLE]: void 0,
68
69
  [INPUT_TYPES.UPLOAD_DROPZONE_IMAGE_AUTO_MULTIPLE]: void 0,
69
70
  [INPUT_TYPES.WYSIWYG]: void 0,
70
71
  [INPUT_TYPES.TAGS]: void 0
71
72
  };
72
- const theme = computed(() => useUiConfig(formTheme, "form")({ orientation: props.orientation }));
73
+ const theme = computed(() => useUiConfig(formTheme, "form")({
74
+ orientation: props.orientation
75
+ }));
73
76
  const getFieldBinding = (field) => {
74
77
  const {
75
78
  props: fieldProps,
@@ -77,14 +80,20 @@ const getFieldBinding = (field) => {
77
80
  } = field;
78
81
  const allProps = {
79
82
  ...fieldProps,
80
- containerUi: { ...fieldUi }
83
+ containerUi: {
84
+ ...fieldUi
85
+ }
81
86
  };
82
87
  if (props.orientation === "horizontal") {
83
88
  return {
84
89
  ...allProps,
85
90
  containerUi: {
86
- root: theme.value.wrapper({ class: [props.ui?.wrapper] }),
87
- labelWrapper: theme.value.container({ class: [props.ui?.container] })
91
+ root: theme.value.wrapper({
92
+ class: [props.ui?.wrapper]
93
+ }),
94
+ labelWrapper: theme.value.container({
95
+ class: [props.ui?.container]
96
+ })
88
97
  }
89
98
  };
90
99
  }
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <FieldWrapper v-bind="wrapperProps">
3
+ <div
4
+ ref="dropZoneRef"
5
+ :class="theme.base()"
6
+ >
7
+ <div :class="theme.wrapper()">
8
+ <div
9
+ v-if="!selectedFile && !value"
10
+ :class="[theme.placeholderWrapper()]"
11
+ >
12
+ <Icon
13
+ :name="useUiConfigStatic('uploadFileDropzone').uploadIcon"
14
+ :class="[theme.labelIcon()]"
15
+ />
16
+ <div :class="[theme.labelWrapper()]">
17
+ <p
18
+ class="text-primary bg-primary-50 cursor-pointer"
19
+ @click="fileDialog.open"
20
+ >
21
+ {{ selectFileLabel }}
22
+ </p>
23
+ <p>{{ selectFileSubLabel }}</p>
24
+ </div>
25
+ <p
26
+ v-if="placeholder"
27
+ :class="theme.placeholder()"
28
+ >
29
+ {{ placeholder }}
30
+ </p>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ </FieldWrapper>
35
+ </template>
36
+
37
+ <script setup>
38
+ import { useDropZone, useFileDialog } from "@vueuse/core";
39
+ import { computed, ref, useTemplateRef } from "vue";
40
+ import FieldWrapper from "#core/components/Form/FieldWrapper.vue";
41
+ import { useFieldHOC } from "#core/composables/useForm";
42
+ import { uploadFileDropzoneTheme } from "#core/theme/uploadFileDropzone";
43
+ import { useUiConfig, useUiConfigStatic } from "#core/composables/useConfig";
44
+ import { useFileAllocate, useFileProgress, useFileSize } from "#core/helpers/componentHelper";
45
+ const props = defineProps({
46
+ requestOptions: { type: Object, required: true },
47
+ uploadPathURL: { type: String, required: false },
48
+ selectFileLabel: { type: String, required: false, default: "\u0E04\u0E25\u0E34\u0E01\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C" },
49
+ selectFileSubLabel: { type: String, required: false, default: "\u0E2B\u0E23\u0E37\u0E2D \u0E25\u0E32\u0E01\u0E41\u0E25\u0E30\u0E27\u0E32\u0E07\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48" },
50
+ uploadingLabel: { type: String, required: false, default: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2D\u0E31\u0E1E\u0E42\u0E2B\u0E25\u0E14..." },
51
+ uploadFailedLabel: { type: String, required: false, default: "\u0E2D\u0E31\u0E1E\u0E42\u0E2B\u0E25\u0E14\u0E25\u0E49\u0E21\u0E40\u0E2B\u0E25\u0E27, \u0E01\u0E23\u0E38\u0E13\u0E32\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07" },
52
+ retryLabel: { type: String, required: false },
53
+ accept: { type: [Array, String], required: false },
54
+ bodyKey: { type: String, required: false, default: "file" },
55
+ responseURL: { type: String, required: false, default: "url" },
56
+ responsePath: { type: String, required: false, default: "path" },
57
+ maxSize: { type: Number, required: false },
58
+ form: { type: Object, required: false },
59
+ name: { type: String, required: true },
60
+ errorMessage: { type: String, required: false },
61
+ label: { type: null, required: false },
62
+ description: { type: String, required: false },
63
+ hint: { type: String, required: false },
64
+ rules: { type: null, required: false },
65
+ autoFocus: { type: Boolean, required: false },
66
+ placeholder: { type: String, required: false },
67
+ disabled: { type: Boolean, required: false },
68
+ readonly: { type: Boolean, required: false },
69
+ required: { type: Boolean, required: false },
70
+ help: { type: String, required: false },
71
+ ui: { type: null, required: false }
72
+ });
73
+ const emits = defineEmits(["change", "success", "delete"]);
74
+ const {
75
+ wrapperProps,
76
+ handleChange: onChange,
77
+ setErrors,
78
+ value
79
+ } = useFieldHOC(props);
80
+ const dropZoneRef = useTemplateRef("dropZoneRef");
81
+ const theme = computed(() => useUiConfig(uploadFileDropzoneTheme, "uploadFileDropzone")({
82
+ dragover: dropzone.isOverDropZone.value
83
+ }));
84
+ const fileDialog = useFileDialog({
85
+ accept: typeof props.accept === "string" ? props.accept : props.accept?.join(","),
86
+ // Set to accept only image files
87
+ directory: false
88
+ // Select directories instead of files if set true
89
+ });
90
+ const selectedFile = ref();
91
+ const isPreviewOpen = ref(false);
92
+ const {
93
+ onUploadProgress,
94
+ onDownloadProgress,
95
+ percent
96
+ } = useFileProgress();
97
+ const fileAllocate = useFileAllocate(selectedFile, props);
98
+ const fileAllocateFromPath = computed(() => useFileSize(value.value?.size));
99
+ fileDialog.onChange((files) => {
100
+ console.log("Selected files:", files);
101
+ });
102
+ const onDrop = (files) => {
103
+ console.log("Selected files drop:", files);
104
+ };
105
+ const dropzone = useDropZone(dropZoneRef, {
106
+ onDrop,
107
+ // specify the types of data to be received.
108
+ dataTypes: typeof props.accept === "string" ? [props.accept] : props.accept,
109
+ // control multi-file drop
110
+ multiple: false,
111
+ // whether to prevent default behavior for unhandled events
112
+ preventDefaultForUnhandled: false
113
+ });
114
+ </script>
@@ -0,0 +1,19 @@
1
+ import type { IUploadDropzoneAutoProps } from './types.js';
2
+ declare const _default: import("vue").DefineComponent<IUploadDropzoneAutoProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
3
+ success: (...args: any[]) => void;
4
+ delete: (...args: any[]) => void;
5
+ change: (...args: any[]) => void;
6
+ }, string, import("vue").PublicProps, Readonly<IUploadDropzoneAutoProps> & Readonly<{
7
+ onSuccess?: ((...args: any[]) => any) | undefined;
8
+ onDelete?: ((...args: any[]) => any) | undefined;
9
+ onChange?: ((...args: any[]) => any) | undefined;
10
+ }>, {
11
+ selectFileLabel: string;
12
+ selectFileSubLabel: string;
13
+ uploadingLabel: string;
14
+ uploadFailedLabel: string;
15
+ bodyKey: string;
16
+ responseURL: string;
17
+ responsePath: string;
18
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import type { AxiosRequestConfig } from 'axios';
2
+ import type { IFieldProps, IFormFieldBase, INPUT_TYPES } from '../types.js';
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
+ uploadingLabel?: string;
11
+ uploadFailedLabel?: string;
12
+ retryLabel?: string;
13
+ accept?: string[] | string;
14
+ bodyKey?: string;
15
+ responseURL?: string;
16
+ responsePath?: string;
17
+ maxSize?: number;
18
+ }
19
+ export type IUploadDropzoneAutoField = IFormFieldBase<INPUT_TYPES.UPLOAD_DROPZONE_AUTO, IUploadDropzoneAutoProps, {
20
+ change: (value: File | undefined) => void;
21
+ success: (res: any) => void;
22
+ delete: () => void;
23
+ }>;
@@ -1,5 +1,6 @@
1
1
  import type { Component } from '@nuxt/schema';
2
2
  import type { FormContext } from 'vee-validate';
3
+ import type { IUploadDropzoneAutoField } from './InputUploadDropzoneAuto/types.js';
3
4
  import type { ITextField } from '#core/components/Form/InputText/types';
4
5
  import type { ITextareaField } from '#core/components/Form/InputTextarea/types';
5
6
  import type { IToggleField } from '#core/components/Form/InputToggle/types';
@@ -60,7 +61,7 @@ export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O>
60
61
  props: P;
61
62
  on?: O;
62
63
  }
63
- export type IFormField = ITextField | INumberField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IDateTimeField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
64
+ export type IFormField = ITextField | INumberField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IDateTimeField | IUploadDropzoneAutoField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
64
65
  export interface IFileValue {
65
66
  url: string;
66
67
  path?: string;
@@ -3,7 +3,7 @@
3
3
  <template #loading>
4
4
  <slot name="loading">
5
5
  <div
6
- class="w-full h-full flex justify-center items-center"
6
+ class="flex h-full w-full items-center justify-center"
7
7
  >
8
8
  <Loader
9
9
  :loading="true"
@@ -15,12 +15,12 @@
15
15
  <template #error>
16
16
  <slot name="error">
17
17
  <div
18
- class="w-full h-full flex justify-center items-center"
18
+ class="flex h-full w-full items-center justify-center"
19
19
  >
20
20
  <p class="text-error-400">
21
21
  <Icon
22
22
  name="i-heroicons:exclamation-circle-solid"
23
- class="text-error-400 size-8"
23
+ class="size-8 text-error-400"
24
24
  />
25
25
  </p>
26
26
  </div>
@@ -18,7 +18,7 @@
18
18
  <div class="flex h-60 items-center justify-center">
19
19
  <Icon
20
20
  name="i-svg-spinners:180-ring-with-bg"
21
- class="text-primary size-8"
21
+ class="size-8 text-primary"
22
22
  />
23
23
  </div>
24
24
  </template>
@@ -53,7 +53,7 @@
53
53
  name="error"
54
54
  >
55
55
  <div
56
- class="text-error-400 text-2xl h-[200px] flex justify-center items-center"
56
+ class="flex h-[200px] items-center justify-center text-2xl text-error-400"
57
57
  >
58
58
  {{ StringHelper.getError(options.status.errorData) }}
59
59
  </div>
@@ -173,6 +173,8 @@ const totalCountWithComma = computed(() => {
173
173
  return StringHelper.withComma(total);
174
174
  });
175
175
  const transformValue = (column, row) => {
176
- return column.cell ? column.cell({ row }) : row.getValue(column.accessorKey);
176
+ return column.cell ? column.cell({
177
+ row
178
+ }) : row.getValue(column.accessorKey);
177
179
  };
178
180
  </script>
@@ -1,4 +1,5 @@
1
1
  import type { core as Core } from '../../core.config.js';
2
2
  export declare const useCoreConfig: () => typeof Core;
3
3
  export declare const useUiConfig: (config: object, name: string) => any;
4
+ export declare const useUiConfigStatic: (name: string) => any;
4
5
  export declare const useUiAllConfig: () => any;
@@ -9,6 +9,9 @@ export const useUiConfig = (config, name) => {
9
9
  ...appConfig.ui[name] || {}
10
10
  });
11
11
  };
12
+ export const useUiConfigStatic = (name) => {
13
+ return appConfig.ui[name].slots;
14
+ };
12
15
  export const useUiAllConfig = () => {
13
16
  return appConfig.ui;
14
17
  };
@@ -10,7 +10,9 @@ export var DialogType = /* @__PURE__ */ ((DialogType2) => {
10
10
  export const useDialog = () => {
11
11
  const overlay = useOverlay();
12
12
  const openDialog = async (payload) => {
13
- const modal = overlay.create(Dialog, { props: payload });
13
+ const modal = overlay.create(Dialog, {
14
+ props: payload
15
+ });
14
16
  const result = await modal.open();
15
17
  const res = await result.result;
16
18
  return new Promise((resolve, reject) => {
@@ -6,7 +6,7 @@ interface IFieldContext<TValue> extends FieldContext<TValue> {
6
6
  }
7
7
  export declare const useFieldHOC: <TValue = unknown>(newFormProps: IFieldProps, opts?: Partial<FieldOptions<TValue>>) => IFieldContext<TValue>;
8
8
  export declare const createFormFields: (fields: () => IFormField[]) => ComputedRef<IFormField[]>;
9
- export declare const moveToError: ({ errors }: {
9
+ export declare const moveToError: ({ errors, }: {
10
10
  errors: any;
11
11
  }) => void;
12
12
  export {};
@@ -21,11 +21,15 @@ export const useFieldHOC = (newFormProps, opts) => {
21
21
  };
22
22
  };
23
23
  export const createFormFields = (fields) => computed(fields);
24
- export const moveToError = ({ errors }) => {
24
+ export const moveToError = ({
25
+ errors
26
+ }) => {
25
27
  const firstErrorFieldName = Object.keys(errors)[0];
26
28
  const el = document.querySelector(`[name="${firstErrorFieldName}"]`);
27
29
  if (el) {
28
- el.focus({ preventScroll: true });
30
+ el.focus({
31
+ preventScroll: true
32
+ });
29
33
  const elementRect = el.getBoundingClientRect();
30
34
  const absoluteElementTop = elementRect.top + window.scrollY;
31
35
  const paddingTop = 60;
@@ -17,7 +17,9 @@ export const prepareRequestOptions = (baseOptions, requestOptions, params) => {
17
17
  ...baseOptions || {},
18
18
  ...requestOptions || {}
19
19
  };
20
- options.params = ParamHelper.getParams({ params }, options);
20
+ options.params = ParamHelper.getParams({
21
+ params
22
+ }, options);
21
23
  return options;
22
24
  };
23
25
  export const handleApiRequest = async (requestContext, mockData, callbacks) => {
@@ -4,6 +4,7 @@ export declare const checkFileType: (file: File, acceptFileType: string | string
4
4
  export declare const generateURL: (file: File) => string;
5
5
  export declare const isImage: (file: File) => boolean;
6
6
  export declare const isImageFromPath: (path?: string) => boolean;
7
+ export declare const isVideoFromPath: (path?: string) => boolean;
7
8
  export declare const isPDFFromPath: (path?: string) => boolean;
8
9
  export declare const useFileAllocate: (selectedFile: Ref<File | undefined | null>, props: {
9
10
  accept?: string | string[];
@@ -41,6 +41,11 @@ export const isImageFromPath = (path = "") => {
41
41
  const extension = path.toLowerCase().substring(path.lastIndexOf("."));
42
42
  return imageExtensions.includes(extension);
43
43
  };
44
+ export const isVideoFromPath = (path = "") => {
45
+ const imageExtensions = [".mp4"];
46
+ const extension = path.toLowerCase().substring(path.lastIndexOf("."));
47
+ return imageExtensions.includes(extension);
48
+ };
44
49
  export const isPDFFromPath = (path = "") => {
45
50
  const imageExtensions = [".pdf"];
46
51
  const extension = path.toLowerCase().substring(path.lastIndexOf("."));
@@ -1 +1,5 @@
1
- export const buttonTheme = { slots: { base: "cursor-pointer" } };
1
+ export const buttonTheme = {
2
+ slots: {
3
+ base: "cursor-pointer"
4
+ }
5
+ };
@@ -18,13 +18,23 @@ export const dialogTheme = {
18
18
  },
19
19
  variants: {
20
20
  color: {
21
- success: { icon: "text-success" },
22
- info: { icon: "text-info" },
23
- warning: { icon: "text-warning" },
24
- error: { icon: "text-error" }
21
+ success: {
22
+ icon: "text-success"
23
+ },
24
+ info: {
25
+ icon: "text-info"
26
+ },
27
+ warning: {
28
+ icon: "text-warning"
29
+ },
30
+ error: {
31
+ icon: "text-error"
32
+ }
25
33
  },
26
34
  confirm: {
27
- true: { icon: "text-info" },
35
+ true: {
36
+ icon: "text-info"
37
+ },
28
38
  false: {}
29
39
  }
30
40
  },
@@ -12,5 +12,7 @@ export const formTheme = {
12
12
  }
13
13
  }
14
14
  },
15
- defaultVariants: { orientation: "vertical" }
15
+ defaultVariants: {
16
+ orientation: "vertical"
17
+ }
16
18
  };
@@ -1 +1,3 @@
1
- export const iconsTheme = { loading: "i-svg-spinners:180-ring-with-bg" };
1
+ export const iconsTheme = {
2
+ loading: "i-svg-spinners:180-ring-with-bg"
3
+ };
@@ -9,3 +9,4 @@ export { tableTheme as table } from './table.js';
9
9
  export { formTheme as form } from './form.js';
10
10
  export { inputNumberTheme as inputNumber } from './inputNumber.js';
11
11
  export { iconsTheme as icons } from './icons.js';
12
+ export { uploadFileDropzoneTheme as uploadFileDropzone } from './uploadFileDropzone.js';
@@ -9,3 +9,4 @@ export { tableTheme as table } from "./table.js";
9
9
  export { formTheme as form } from "./form.js";
10
10
  export { inputNumberTheme as inputNumber } from "./inputNumber.js";
11
11
  export { iconsTheme as icons } from "./icons.js";
12
+ export { uploadFileDropzoneTheme as uploadFileDropzone } from "./uploadFileDropzone.js";
@@ -1,4 +1,8 @@
1
1
  export const inputTheme = {
2
- slots: { root: "w-full" },
3
- defaultVariants: { size: "lg" }
2
+ slots: {
3
+ root: "w-full"
4
+ },
5
+ defaultVariants: {
6
+ size: "lg"
7
+ }
4
8
  };
@@ -1,4 +1,8 @@
1
1
  export const inputNumberTheme = {
2
- slots: { root: "w-full" },
3
- defaultVariants: { size: "lg" }
2
+ slots: {
3
+ root: "w-full"
4
+ },
5
+ defaultVariants: {
6
+ size: "lg"
7
+ }
4
8
  };
@@ -5,11 +5,21 @@ export const loaderTheme = {
5
5
  },
6
6
  variants: {
7
7
  size: {
8
- sm: { icon: "text-2xl" },
9
- md: { icon: "text-4xl" },
10
- lg: { icon: "text-6xl" }
8
+ sm: {
9
+ icon: "text-2xl"
10
+ },
11
+ md: {
12
+ icon: "text-4xl"
13
+ },
14
+ lg: {
15
+ icon: "text-6xl"
16
+ }
11
17
  },
12
- color: { primary: { icon: "text-primary" } }
18
+ color: {
19
+ primary: {
20
+ icon: "text-primary"
21
+ }
22
+ }
13
23
  },
14
24
  defaultVariants: {
15
25
  size: "md",
@@ -14,5 +14,7 @@ export const selectMenuTheme = {
14
14
  ],
15
15
  tagsItemDeleteIcon: "ph:x"
16
16
  },
17
- defaultVariants: { size: "lg" }
17
+ defaultVariants: {
18
+ size: "lg"
19
+ }
18
20
  };
@@ -1 +1,5 @@
1
- export const textareaTheme = { slots: { root: "w-full" } };
1
+ export const textareaTheme = {
2
+ slots: {
3
+ root: "w-full"
4
+ }
5
+ };
@@ -0,0 +1,24 @@
1
+ export declare const uploadFileDropzoneTheme: {
2
+ slots: {
3
+ base: string;
4
+ wrapper: string;
5
+ disabled: string;
6
+ failed: string;
7
+ placeholderWrapper: string;
8
+ placeholder: string;
9
+ labelWrapper: string;
10
+ filePreviewIcon: string;
11
+ uploadIcon: string;
12
+ placeholderImgIcon: string;
13
+ failedImgIcon: string;
14
+ loadingIcon: string;
15
+ labelIcon: string;
16
+ };
17
+ variants: {
18
+ dragover: {
19
+ true: {
20
+ base: string;
21
+ };
22
+ };
23
+ };
24
+ };
@@ -0,0 +1,24 @@
1
+ export const uploadFileDropzoneTheme = {
2
+ slots: {
3
+ base: "relative w-full p-4 transition rounded-lg flex items-center justify-center ring-1 bg-white ring-gray-300",
4
+ wrapper: "flex flex-col items-center w-full",
5
+ disabled: "bg-gray-100 border-none grayscale cursor-not-allowed",
6
+ failed: "border-danger",
7
+ placeholderWrapper: "py-4 flex flex-col items-center justify-center",
8
+ placeholder: "text-gray-400 text-center font-light text-sm truncate",
9
+ labelWrapper: "flex items-center space-x-2 text-gray-400 text-center",
10
+ filePreviewIcon: "i-heroicons:document-text-solid",
11
+ uploadIcon: "i-ph:cloud-arrow-up",
12
+ placeholderImgIcon: "i-material-symbols:imagesmode-outline",
13
+ failedImgIcon: "i-material-symbols:imagesmode-outline",
14
+ loadingIcon: "i-svg-spinners:180-ring-with-bg",
15
+ labelIcon: "w-6 h-6 text-gray-400 text-center mb-4"
16
+ },
17
+ variants: {
18
+ dragover: {
19
+ true: {
20
+ base: "ring-primary bg-primary-50"
21
+ }
22
+ }
23
+ }
24
+ };
@@ -24,6 +24,8 @@ export class FileHelper {
24
24
  static dataURLtoFile = async (dataUrl, filename) => {
25
25
  const res = await fetch(dataUrl);
26
26
  const blob = await res.blob();
27
- return new File([blob], filename, { type: "image/png" });
27
+ return new File([blob], filename, {
28
+ type: "image/png"
29
+ });
28
30
  };
29
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finema/core",
3
- "version": "2.6.2",
3
+ "version": "2.7.0",
4
4
  "repository": "https://gitlab.finema.co/finema/ui-kit",
5
5
  "license": "MIT",
6
6
  "author": "Finema Dev Core Team",
@@ -8,6 +8,7 @@
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/types.d.mts",
11
+ "style": "./dist/runtime/styles/main.css",
11
12
  "default": "./dist/module.mjs"
12
13
  }
13
14
  },
@@ -38,7 +39,7 @@
38
39
  "dependencies": {
39
40
  "@nuxt/kit": "^3.17.4",
40
41
  "@nuxt/ui": "^3.1.3",
41
- "@pinia/nuxt": "^0.11.0",
42
+ "@pinia/nuxt": "0.7.0",
42
43
  "@tiptap/extension-image": "^2.8.0",
43
44
  "@tiptap/extension-link": "^2.8.0",
44
45
  "@tiptap/extension-text-align": "^2.8.0",
@@ -66,6 +67,7 @@
66
67
  "url-join": "^5.0.0"
67
68
  },
68
69
  "devDependencies": {
70
+ "@hyoban/eslint-plugin-tailwindcss": "^4.0.0-alpha.12",
69
71
  "@eslint/js": "^9.26.0",
70
72
  "@nuxt/devtools": "^2.4.1",
71
73
  "@nuxt/eslint-config": "^1.3.1",
@@ -89,6 +91,6 @@
89
91
  "vue-tsc": "^2.2.10"
90
92
  },
91
93
  "lint-staged": {
92
- "*": "eslint --fix ."
94
+ "*": "eslint --fix"
93
95
  }
94
96
  }