@finema/core 1.3.23 → 1.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.d.mts CHANGED
@@ -10,10 +10,10 @@ declare namespace config {
10
10
  export { config_core as core };
11
11
  }
12
12
 
13
- type Strategy = 'merge' | 'override'
14
-
15
- type DeepPartial<T> = Partial<{
16
- [P in keyof T]: DeepPartial<T[P]> | Record<string, string>
13
+ type Strategy = 'merge' | 'override'
14
+
15
+ type DeepPartial<T> = Partial<{
16
+ [P in keyof T]: DeepPartial<T[P]> | Record<string, string>
17
17
  }>
18
18
 
19
19
  interface ModuleOptions {
package/dist/module.d.ts CHANGED
@@ -10,10 +10,10 @@ declare namespace config {
10
10
  export { config_core as core };
11
11
  }
12
12
 
13
- type Strategy = 'merge' | 'override'
14
-
15
- type DeepPartial<T> = Partial<{
16
- [P in keyof T]: DeepPartial<T[P]> | Record<string, string>
13
+ type Strategy = 'merge' | 'override'
14
+
15
+ type DeepPartial<T> = Partial<{
16
+ [P in keyof T]: DeepPartial<T[P]> | Record<string, string>
17
17
  }>
18
18
 
19
19
  interface ModuleOptions {
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finema/core",
3
- "version": "1.3.23",
3
+ "version": "1.3.24",
4
4
  "configKey": "core",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.7.4"
package/dist/module.mjs CHANGED
@@ -2,7 +2,7 @@ import { defineNuxtModule, createResolver, installModule, addPlugin, addComponen
2
2
  import { merge } from 'lodash-es';
3
3
 
4
4
  const name = "@finema/core";
5
- const version = "1.3.23";
5
+ const version = "1.3.24";
6
6
 
7
7
  const colors = {
8
8
  black: "#20243E",
@@ -68,9 +68,86 @@ const colors = {
68
68
  };
69
69
 
70
70
  const ui = {
71
+ strategy: "override",
71
72
  safelistColors: ["secondary"],
72
73
  icons: {
73
74
  dynamic: true
75
+ },
76
+ pagination: {
77
+ wrapper: "flex items-center -space-x-px space-x-1",
78
+ default: {
79
+ activeButton: {
80
+ color: "primary",
81
+ class: "rounded-md px-3"
82
+ },
83
+ inactiveButton: {
84
+ color: "primary",
85
+ variant: "ghost",
86
+ class: "rounded-md px-3 text-gray-500 hover:bg-primary-500 hover:text-white"
87
+ },
88
+ firstButton: {
89
+ color: "primary",
90
+ variant: "ghost",
91
+ class: "rtl:[&_span:first-child]:rotate-180 rounded-md px-2 text-gray-500 hover:bg-primary-500 hover:text-white"
92
+ },
93
+ lastButton: {
94
+ color: "primary",
95
+ variant: "ghost",
96
+ class: "rtl:[&_span:last-child]:rotate-180 rounded-md px-2 text-gray-500 hover:bg-primary-500 hover:text-white"
97
+ },
98
+ prevButton: {
99
+ color: "primary",
100
+ variant: "ghost",
101
+ class: "rtl:[&_span:first-child]:rotate-180 rounded-md px-2 text-gray-500 hover:bg-primary-500 hover:text-white"
102
+ },
103
+ nextButton: {
104
+ color: "primary",
105
+ variant: "ghost",
106
+ class: "rtl:[&_span:last-child]:rotate-180 rounded-md px-2 text-gray-500 hover:bg-primary-500 hover:text-white"
107
+ }
108
+ }
109
+ },
110
+ table: {
111
+ wrapper: "relative overflow-x-auto bg-white rounded-lg",
112
+ base: "min-w-full table-fixed",
113
+ divide: "divide-y divide-y-2 divide-gray-300 dark:divide-gray-700",
114
+ thead: "",
115
+ tbody: "divide-y divide-gray-200 dark:divide-gray-800",
116
+ tr: {
117
+ base: "even:bg-gray-50",
118
+ selected: "bg-gray-50 dark:bg-gray-800/50",
119
+ active: "hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer"
120
+ },
121
+ th: {
122
+ base: "text-left rtl:text-right",
123
+ padding: "px-3 py-3.5",
124
+ color: "text-gray-700 dark:text-white",
125
+ font: "font-normal",
126
+ size: "text-sm"
127
+ },
128
+ td: {
129
+ base: "whitespace-nowrap",
130
+ padding: "px-3 py-4",
131
+ color: "text-gray-500 dark:text-gray-400",
132
+ font: "",
133
+ size: "text-sm"
134
+ },
135
+ default: {
136
+ sortButton: {
137
+ icon: "i-heroicons-arrows-up-down-20-solid",
138
+ trailing: true,
139
+ square: true,
140
+ color: "gray",
141
+ variant: "ghost",
142
+ class: "-m-1.5 text-gray-700 font-normal"
143
+ },
144
+ loadingState: {
145
+ label: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E42\u0E2B\u0E25\u0E14..."
146
+ },
147
+ emptyState: {
148
+ label: "\u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25"
149
+ }
150
+ }
74
151
  }
75
152
  };
76
153
 
@@ -94,7 +171,7 @@ const module = defineNuxtModule({
94
171
  nuxt.options.alias["#core"] = runtimeDir;
95
172
  nuxt.options.css.push(resolve(runtimeDir, "ui.css"));
96
173
  nuxt.options.appConfig.app = {
97
- strategy: "merge"
174
+ strategy: "override"
98
175
  };
99
176
  nuxt.hook("tailwindcss:config", (tailwindConfig) => {
100
177
  tailwindConfig.content = {
@@ -102,7 +179,8 @@ const module = defineNuxtModule({
102
179
  files: [
103
180
  ...tailwindConfig.content.files,
104
181
  resolve(runtimeDir, "components/**/*.{vue,mjs,ts}"),
105
- resolve(runtimeDir, "*.{mjs,js,ts}")
182
+ resolve(runtimeDir, "*.{mjs,js,ts}"),
183
+ resolve("./ui.ts")
106
184
  ]
107
185
  };
108
186
  tailwindConfig.theme.extend.colors = {
@@ -110,8 +188,8 @@ const module = defineNuxtModule({
110
188
  ...colors
111
189
  };
112
190
  });
113
- nuxt.options.appConfig.ui = _merge(ui, nuxt.options.appConfig.ui);
114
191
  await installModule("@nuxt/ui");
192
+ nuxt.options.appConfig.ui = _merge(ui, nuxt.options.appConfig.ui);
115
193
  await installModule("@pinia/nuxt");
116
194
  await installModule("@vee-validate/nuxt", {
117
195
  // disable or enable auto imports
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <UBadge
3
+ v-bind="attrs"
4
+ :class="$props.class"
5
+ :label="label"
6
+ :size="size"
7
+ :color="color"
8
+ :variant="variant"
9
+ :ui="ui"
10
+ >
11
+ <slot />
12
+ </UBadge>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { useUiConfig, type PropType, useUI, toRef } from '#imports'
17
+ import { type BadgeSize, type BadgeColor, type BadgeVariant } from '#ui/types'
18
+ import { badge } from '#core/ui.config'
19
+ import type { Strategy } from '#core/types/utils'
20
+
21
+ const config = useUiConfig<typeof badge>(badge, 'badge')
22
+
23
+ const props = defineProps({
24
+ size: {
25
+ type: String as PropType<BadgeSize>,
26
+ default: () => badge.default.size,
27
+ validator(value: string) {
28
+ return Object.keys(badge.size).includes(value)
29
+ },
30
+ },
31
+ color: {
32
+ type: String as PropType<BadgeColor>,
33
+ default: () => badge.default.color,
34
+ },
35
+ variant: {
36
+ type: String as PropType<BadgeVariant>,
37
+ default: () => badge.default.variant,
38
+ },
39
+ label: {
40
+ type: [String, Number],
41
+ default: null,
42
+ },
43
+ class: {
44
+ type: [String, Object, Array] as PropType<any>,
45
+ default: () => '',
46
+ },
47
+ ui: {
48
+ type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
49
+ default: () => ({}),
50
+ },
51
+ })
52
+
53
+ const { ui, attrs } = useUI('badge', toRef(props, 'ui'), config, toRef(props, 'class'))
54
+ </script>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <UBreadcrumb v-bind="attrs" :class="$props.class" :links="links" :divider="divider" :ui="ui">
3
+ <template #default="{ link, isActive, index }">
4
+ <slot name="default" :link="link" :is-active="isActive" :index="index" />
5
+ </template>
6
+
7
+ <template #icon="{ link, index, isActive }">
8
+ <slot name="icon" :link="link" :is-active="isActive" :index="index" />
9
+ </template>
10
+
11
+ <template #divider>
12
+ <slot name="divider" />
13
+ </template>
14
+ </UBreadcrumb>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { useUiConfig, type PropType, useUI, toRef } from '#imports'
19
+ import { type BreadcrumbLink } from '#ui/types'
20
+ import type { Strategy } from '#core/types/utils'
21
+ import { breadcrumb } from '#core/ui.config'
22
+
23
+ const config = useUiConfig<typeof breadcrumb>(breadcrumb, 'breadcrumb')
24
+
25
+ const props = defineProps({
26
+ links: {
27
+ type: Array as PropType<BreadcrumbLink[]>,
28
+ default: () => [],
29
+ },
30
+ divider: {
31
+ type: String,
32
+ default: () => breadcrumb.default.divider,
33
+ },
34
+ class: {
35
+ type: [String, Object, Array] as PropType<any>,
36
+ default: () => '',
37
+ },
38
+ ui: {
39
+ type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
40
+ default: () => ({}),
41
+ },
42
+ })
43
+
44
+ const { ui, attrs } = useUI('breadcrumb', toRef(props, 'ui'), config, toRef(props, 'class'))
45
+ </script>
@@ -1,31 +1,47 @@
1
1
  <template>
2
- <div>
3
- <UButtonGroup v-bind="$attrs">
4
- <Button label="Button" />
5
- <Button color="blue" size="xs">
6
- <svg
7
- xmlns="http://www.w3.org/2000/svg"
8
- fill="none"
9
- viewBox="0 0 24 24"
10
- stroke-width="1.5"
11
- stroke="currentColor"
12
- class="h-3 w-3"
13
- >
14
- <path
15
- stroke-linecap="round"
16
- stroke-linejoin="round"
17
- d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3"
18
- />
19
- </svg>
20
- </Button>
21
- </UButtonGroup>
22
- </div>
2
+ <UButtonGroup
3
+ v-bind="attrs"
4
+ :class="$props.class"
5
+ :size="size"
6
+ :orientation="orientation"
7
+ :ui="ui"
8
+ >
9
+ <slot />
10
+ </UButtonGroup>
23
11
  </template>
24
12
 
25
13
  <script lang="ts" setup>
26
- defineOptions({
27
- inheritAttrs: true,
14
+ import { type PropType, useUiConfig, useUI, toRef } from '#imports'
15
+ import { button, buttonGroup } from '#core/ui.config'
16
+ import { type ButtonSize } from '#ui/types/button'
17
+ import { type Strategy } from '#core/types/utils'
18
+
19
+ const config = useUiConfig<typeof buttonGroup>(buttonGroup, 'buttonGroup')
20
+
21
+ const props = defineProps({
22
+ size: {
23
+ type: String as PropType<ButtonSize>,
24
+ default: () => button.default.size,
25
+ validator(value: string) {
26
+ return Object.keys(button.size).includes(value)
27
+ },
28
+ },
29
+ orientation: {
30
+ type: String as PropType<'horizontal' | 'vertical'>,
31
+ default: 'horizontal',
32
+ validator(value: string) {
33
+ return ['horizontal', 'vertical'].includes(value)
34
+ },
35
+ },
36
+ class: {
37
+ type: [String, Object, Array] as PropType<any>,
38
+ default: undefined,
39
+ },
40
+ ui: {
41
+ type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
42
+ default: undefined,
43
+ },
28
44
  })
29
- </script>
30
45
 
31
- <style></style>
46
+ const { ui, attrs } = useUI('buttonGroup', toRef(props, 'ui'), config, toRef(props, 'class'))
47
+ </script>
@@ -1,36 +1,58 @@
1
1
  <template>
2
- <UButton v-bind="$props">
3
- <template #leading>
4
- <slot name="leading" />
5
- </template>
6
- <slot />
2
+ <UButton
3
+ v-bind="attrs"
4
+ :class="$props.class"
5
+ :label="label"
6
+ :type="type"
7
+ :block="block"
8
+ :loading="loading"
9
+ :disabled="disabled"
10
+ :padded="padded"
11
+ :size="size"
12
+ :color="color"
13
+ :variant="variant"
14
+ :icon="icon"
15
+ :loading-icon="loadingIcon"
16
+ :leading-icon="leadingIcon"
17
+ :trailing-icon="trailingIcon"
18
+ :trailing="trailing"
19
+ :leading="leading"
20
+ :square="square"
21
+ :truncate="truncate"
22
+ :ui="ui"
23
+ >
24
+ <template #leading><slot name="leading" /></template>
7
25
 
8
- <template #trailing>
9
- <slot name="trailing" />
10
- </template>
26
+ <slot />
27
+ <template #trailing><slot name="trailing" /></template>
11
28
  </UButton>
12
29
  </template>
30
+
13
31
  <script lang="ts" setup>
14
- import { UButton } from '#components'
15
- import { type PropType } from 'vue'
32
+ import { useUiConfig, toRef, type PropType, useUI } from '#imports'
33
+ import { button } from '#core/ui.config'
34
+ import { type ButtonSize, type ButtonColor, type ButtonVariant } from '#ui/types/button'
35
+ import { type Strategy } from '#core/types/utils'
36
+
37
+ const config = useUiConfig<typeof button>(button, 'button')
16
38
 
17
39
  defineOptions({
18
40
  inheritAttrs: true,
19
41
  })
20
42
 
21
- defineProps({
22
- type: {
43
+ const props = defineProps({
44
+ label: {
23
45
  type: String,
46
+ default: '',
47
+ },
48
+ type: {
49
+ type: String as PropType<'button' | 'submit' | 'reset'>,
24
50
  default: 'button',
25
51
  },
26
52
  block: {
27
53
  type: Boolean,
28
54
  default: false,
29
55
  },
30
- label: {
31
- type: String,
32
- default: null,
33
- },
34
56
  loading: {
35
57
  type: Boolean,
36
58
  default: false,
@@ -44,24 +66,28 @@ defineProps({
44
66
  default: true,
45
67
  },
46
68
  size: {
47
- type: String,
48
- validator(value: unknown): boolean {
49
- return ['2xs', 'xs', 'sm', 'md', 'lg', 'xl'].includes(value as string)
69
+ type: String as PropType<ButtonSize>,
70
+ default: () => button.default.size,
71
+ validator(value: string) {
72
+ return Object.keys(button.size).includes(value)
50
73
  },
51
74
  },
52
75
  color: {
53
- type: String,
76
+ type: String as PropType<ButtonColor>,
77
+ default: () => button.default.color,
54
78
  },
55
79
  variant: {
80
+ type: String as PropType<ButtonVariant>,
81
+ default: () => button.default.variant,
82
+ },
83
+ loadingIcon: {
56
84
  type: String,
85
+ default: () => button.default.loadingIcon,
57
86
  },
58
87
  icon: {
59
88
  type: String,
60
89
  default: null,
61
90
  },
62
- loadingIcon: {
63
- type: String,
64
- },
65
91
  leadingIcon: {
66
92
  type: String,
67
93
  default: null,
@@ -87,10 +113,14 @@ defineProps({
87
113
  default: false,
88
114
  },
89
115
  class: {
90
- type: [String, Object, Array] as PropType<any>,
116
+ type: [String, Array, Object] as PropType<any>,
117
+ default: undefined,
91
118
  },
92
119
  ui: {
93
- type: Object,
120
+ type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>,
121
+ default: undefined,
94
122
  },
95
123
  })
124
+
125
+ const { ui, attrs } = useUI('button', toRef(props, 'ui'), config, toRef(props, 'class'))
96
126
  </script>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <UCard v-bind="attrs" :class="$props.class" :as="as" :ui="ui">
3
+ <template #header>
4
+ <slot name="header" />
5
+ </template>
6
+
7
+ <slot />
8
+
9
+ <template #footer>
10
+ <slot name="footer" />
11
+ </template>
12
+ </UCard>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { useUiConfig, type PropType, useUI, toRef } from '#imports'
17
+ import type { Strategy } from '#core/types/utils'
18
+ import { card } from '#core/ui.config'
19
+
20
+ const config = useUiConfig<typeof card>(card, 'card')
21
+
22
+ const props = defineProps({
23
+ as: {
24
+ type: String,
25
+ default: 'div',
26
+ },
27
+ class: {
28
+ type: [String, Object, Array] as PropType<any>,
29
+ default: () => '',
30
+ },
31
+ ui: {
32
+ type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
33
+ default: () => ({}),
34
+ },
35
+ })
36
+
37
+ const { ui, attrs } = useUI('card', toRef(props, 'ui'), config, toRef(props, 'class'))
38
+ </script>
@@ -2,6 +2,7 @@
2
2
  <UDropdown
3
3
  v-if="renderOnMounted"
4
4
  v-bind="attrs"
5
+ :class="$props.class"
5
6
  :items="items"
6
7
  :mode="mode"
7
8
  :open-delay="openDelay"
@@ -1,5 +1,11 @@
1
1
  <template>
2
- <UFormGroup :label="label" :name="name" :error="errorMessage" :required="!!isRequired">
2
+ <UFormGroup
3
+ :label="label"
4
+ :name="name"
5
+ :help="help"
6
+ :error="errorMessage"
7
+ :required="!!isRequired"
8
+ >
3
9
  <slot />
4
10
  </UFormGroup>
5
11
  </template>
@@ -1,5 +1,5 @@
1
1
  import { type Component } from '@nuxt/schema';
2
- import { type FormContext, type RuleExpression } from 'vee-validate';
2
+ import { type FormContext } from 'vee-validate';
3
3
  import { type ITextField } from '#core/components/Form/InputText/types';
4
4
  import { type IStaticField } from '#core/components/Form/InputStatic/types';
5
5
  import { type ICheckboxField } from '#core/components/Form/InputCheckbox/types';
@@ -21,19 +21,11 @@ export declare const enum INPUT_TYPES {
21
21
  DATE_TIME = "DATE_TIME",
22
22
  DATE = "DATE"
23
23
  }
24
- export interface IOption {
25
- label: string;
26
- value: any;
27
- }
28
- export interface IRadioOption {
29
- label: string | any;
30
- value: any;
31
- }
32
24
  export interface IFieldProps {
33
25
  form?: FormContext;
34
26
  name: string;
35
27
  label?: string | any;
36
- rules?: RuleExpression<any> | any;
28
+ rules?: any;
37
29
  autoFocus?: boolean;
38
30
  class?: any;
39
31
  classInner?: any;
@@ -48,12 +40,12 @@ export interface IFieldProps {
48
40
  transform?: (value: any, oldValue: any, e: InputEvent) => any;
49
41
  getInstance?: (el: HTMLElement) => void;
50
42
  }
51
- export interface IFormFieldBase<I extends INPUT_TYPES, P extends object = never, O extends object = never> {
52
- type: I | INPUT_TYPES;
43
+ export interface IFormFieldBase<I extends INPUT_TYPES, P, O> {
44
+ type: I;
53
45
  component?: Component;
54
46
  class?: any;
55
47
  isHide?: boolean;
56
- props: IFieldProps & P;
48
+ props: P;
57
49
  on?: O;
58
50
  }
59
51
  export type IFormField = ITextField | IStaticField | ICheckboxField | IRadioField | ISelectField | IToggleField | ITextareaField | IDateTimeField;
@@ -1,11 +1,23 @@
1
- <template>
2
- <UIcon :name="name" />
3
- </template>
4
- <script lang="ts" setup>
5
- defineProps({
6
- name: {
7
- type: String,
8
- required: true,
9
- },
10
- })
11
- </script>
1
+ <template>
2
+ <UIcon :name="name" :dynamic="dynamicValue" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import { computed, useUiConfig } from '#imports'
7
+ import { icon } from '#core/ui.config'
8
+
9
+ const props = defineProps({
10
+ name: {
11
+ type: String,
12
+ required: true,
13
+ },
14
+ dynamic: {
15
+ type: Boolean,
16
+ default: false,
17
+ },
18
+ })
19
+
20
+ const config = useUiConfig<typeof icon>(icon, 'icon')
21
+
22
+ const dynamicValue = computed(() => props.dynamic || config.dynamic)
23
+ </script>
@@ -2,6 +2,7 @@
2
2
  <UModal
3
3
  v-bind="attrs"
4
4
  :model-value="modelValue"
5
+ :class="$props.class"
5
6
  :overlay="overlay"
6
7
  :transition="transition"
7
8
  :prevent-close="preventClose"
@@ -2,6 +2,7 @@
2
2
  <USlideover
3
3
  v-bind="attrs"
4
4
  :model-value="modelValue"
5
+ :class="$props.class"
5
6
  :prevent-close="preventClose"
6
7
  :overlay="overlay"
7
8
  :transition="transition"
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <div>
3
3
  <div
4
- v-if="!options.isHideToolbar"
5
- class="flex border-b border-gray-200 px-3 py-3.5 dark:border-gray-700"
4
+ v-if="options.isEnabledSearch"
5
+ class="flex border-b border-gray-200 py-3.5 dark:border-gray-700"
6
6
  >
7
7
  <UInput v-model="q" placeholder="Search..." />
8
8
  </div>
@@ -14,7 +14,7 @@
14
14
  >
15
15
  <template #empty-state>
16
16
  <div class="flex flex-col items-center justify-center gap-3 py-6">
17
- <span class="text-sm italic">No one here!</span>
17
+ <span class="text-sm italic">ไม่พบข้อมูล!</span>
18
18
  </div>
19
19
  </template>
20
20
  <template
@@ -42,7 +42,10 @@
42
42
  <slot :name="slot" v-bind="scope" />
43
43
  </template>
44
44
  </UTable>
45
- <div class="mt-4 flex justify-end">
45
+ <div class="mt-4 flex justify-between">
46
+ <p class="text-xs text-gray-500">
47
+ ผลลัพธ์ {{ pageBetween }} ของ {{ totalCountWithComma }} รายการ
48
+ </p>
46
49
  <UPagination
47
50
  v-model="page"
48
51
  :page-count="options.pageOptions.totalPage"
@@ -52,9 +55,9 @@
52
55
  </div>
53
56
  </template>
54
57
  <script lang="ts" setup>
55
- import { type PropType } from 'vue'
58
+ import { computed, type PropType } from 'vue'
56
59
  import { COLUMN_TYPES, type ITableOptions } from '#core/components/Table/types'
57
- import { _debounce, ref, watch } from '#imports'
60
+ import { _debounce, ref, StringHelper, watch } from '#imports'
58
61
  import ColumnNumber from '#core/components/Table/ColumnNumber.vue'
59
62
  import ColumnImage from '#core/components/Table/ColumnImage.vue'
60
63
 
@@ -65,6 +68,10 @@ const emits = defineEmits<{
65
68
 
66
69
  const props = defineProps({
67
70
  options: { type: Object as PropType<ITableOptions>, required: true },
71
+ class: {
72
+ type: [String, Array, Object] as PropType<any>,
73
+ default: undefined,
74
+ },
68
75
  })
69
76
 
70
77
  const q = ref(props.options?.pageOptions.search ?? '')
@@ -81,4 +88,23 @@ watch(
81
88
  watch(page, () => {
82
89
  emits('pageChange', page.value)
83
90
  })
91
+
92
+ const pageBetween = computed((): string => {
93
+ const length = props.options?.rawData?.length
94
+
95
+ if (length === 0) {
96
+ return '0'
97
+ }
98
+
99
+ const start = (props.options.pageOptions.currentPage - 1) * props.options.pageOptions.limit + 1
100
+ const end = start + length - 1
101
+
102
+ return `${start} - ${end}`
103
+ })
104
+
105
+ const totalCountWithComma = computed((): string => {
106
+ return !props.options.pageOptions.totalCount
107
+ ? '0'
108
+ : StringHelper.withComma(props.options.pageOptions.totalCount)
109
+ })
84
110
  </script>
@@ -36,6 +36,7 @@ export interface ITableOptions<T = object> {
36
36
  pageOptions: IPageOptions;
37
37
  columns: IColumn[];
38
38
  isHideToolbar?: boolean;
39
+ isEnabledSearch?: boolean;
39
40
  isShowCheckbox?: boolean;
40
41
  deleteStatus?: IStatus;
41
42
  onRowClick?: (index: number, columns: Array<{
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <UTabs
3
+ v-bind="attrs"
4
+ :model-value="modelValue"
5
+ :class="$props.class"
6
+ :items="items"
7
+ :orientation="orientation"
8
+ :default-index="defaultIndex"
9
+ :ui="ui"
10
+ @change="change"
11
+ >
12
+ <template #default="{ item, index, selected }">
13
+ <slot name="default" :item="item" :index="index" :selected="selected" />
14
+ </template>
15
+
16
+ <template #item="{ item, index, selected }">
17
+ <slot name="item" :item="item" :index="index" :selected="selected" />
18
+ </template>
19
+ </UTabs>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { useUiConfig, type PropType, useUI, toRef } from '#imports'
24
+ import { type TabItem } from '#ui/types'
25
+ import type { Strategy } from '#core/types/utils'
26
+ import { tabs } from '#core/ui.config'
27
+
28
+ const config = useUiConfig<typeof tabs>(tabs, 'tabs')
29
+
30
+ const props = defineProps({
31
+ modelValue: {
32
+ type: Number,
33
+ default: undefined,
34
+ },
35
+ items: {
36
+ type: Array as PropType<TabItem[]>,
37
+ default: () => [],
38
+ },
39
+ orientation: {
40
+ type: String as PropType<'horizontal' | 'vertical'>,
41
+ default: 'horizontal',
42
+ validator: (value: string) => ['horizontal', 'vertical'].includes(value),
43
+ },
44
+ defaultIndex: {
45
+ type: Number,
46
+ default: 0,
47
+ },
48
+ class: {
49
+ type: [String, Object, Array] as PropType<any>,
50
+ default: () => '',
51
+ },
52
+ ui: {
53
+ type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
54
+ default: () => ({}),
55
+ },
56
+ })
57
+
58
+ const emits = defineEmits(['update:modelValue', 'change'])
59
+
60
+ const change = (index: number) => {
61
+ emits('change', index)
62
+ }
63
+
64
+ const { ui, attrs } = useUI('tabs', toRef(props, 'ui'), config, toRef(props, 'class'))
65
+ </script>
@@ -11,6 +11,7 @@ export interface IFieldWrapperProps {
11
11
  isHideLabel?: boolean;
12
12
  customErrorMessage?: string | DefineComponent;
13
13
  name: string;
14
+ help?: string;
14
15
  }
15
16
  interface IFieldContext<TValue> extends FieldContext<TValue> {
16
17
  isRequired: boolean;
@@ -36,7 +36,8 @@ export const useFieldHOC = (newFormProps, opts) => {
36
36
  isRequired: newFormProps.isRequired,
37
37
  isHideLabel: newFormProps.isHideLabel,
38
38
  customErrorMessage: newFormProps.customErrorMessage,
39
- name: newFormProps.name
39
+ name: newFormProps.name,
40
+ help: newFormProps.help
40
41
  }))
41
42
  };
42
43
  };
@@ -1 +1 @@
1
- export type UIComponentList = 'modal' | 'slideover' | 'dropdown';
1
+ export type UIComponentList = 'modal' | 'slideover' | 'dropdown' | 'icon' | 'button' | 'buttonGroup' | 'tabs' | 'card' | 'breadcrumb' | 'badge';
@@ -1,9 +1,29 @@
1
- export type Strategy = 'merge' | 'override'
2
-
3
- export type NestedKeyOf<ObjectType extends object> = {
4
- [Key in keyof ObjectType]: ObjectType[Key] extends object ? NestedKeyOf<ObjectType[Key]> : Key
5
- }[keyof ObjectType]
6
-
7
- export type DeepPartial<T> = Partial<{
8
- [P in keyof T]: DeepPartial<T[P]> | Record<string, string>
9
- }>
1
+ export type Strategy = 'merge' | 'override'
2
+
3
+ export type NestedKeyOf<ObjectType extends object> = {
4
+ [Key in keyof ObjectType]: ObjectType[Key] extends object ? NestedKeyOf<ObjectType[Key]> : Key
5
+ }[keyof ObjectType]
6
+
7
+ export type DeepPartial<T> = Partial<{
8
+ [P in keyof T]: DeepPartial<T[P]> | Record<string, string>
9
+ }>
10
+
11
+ type DeepKey<T, Keys extends string[]> = Keys extends [infer First, ...infer Rest]
12
+ ? First extends keyof T
13
+ ? Rest extends string[]
14
+ ? DeepKey<T[First], Rest>
15
+ : never
16
+ : never
17
+ : T
18
+
19
+ export type ExtractDeepKey<T, Path extends string[]> = DeepKey<T, Path> extends infer Result
20
+ ? Result extends Record<string, any>
21
+ ? keyof Result
22
+ : never
23
+ : never
24
+
25
+ export type ExtractDeepObject<T, Path extends string[]> = DeepKey<T, Path> extends infer Result
26
+ ? Result extends Record<string, any>
27
+ ? Result
28
+ : never
29
+ : never
@@ -1,2 +1,11 @@
1
+ export declare const icon: {
2
+ dynamic: boolean;
3
+ };
4
+ export declare const card: any;
5
+ export declare const breadcrumb: any;
6
+ export declare const buttonGroup: any;
7
+ export declare const button: any;
1
8
  export declare const modal: any;
2
9
  export declare const slideover: any;
10
+ export declare const tabs: any;
11
+ export declare const badge: any;
@@ -1,4 +1,39 @@
1
- import { modal as inheritModal, slideover as inheritSlideover } from "#ui/ui.config";
1
+ import {
2
+ modal as inheritModal,
3
+ slideover as inheritSlideover,
4
+ button as inheritButton,
5
+ buttonGroup as inheritButtonGroup,
6
+ tabs as inheritTabs,
7
+ card as inheritCard,
8
+ breadcrumb as inheritBreadcrumb,
9
+ badge as inheritBadge
10
+ } from "#ui/ui.config";
11
+ export const icon = {
12
+ dynamic: false
13
+ };
14
+ export const card = { ...inheritCard };
15
+ export const breadcrumb = {
16
+ ...inheritBreadcrumb,
17
+ default: {
18
+ divider: "i-heroicons-chevron-right-20-solid rtl:i-heroicons-chevron-left-20-solid"
19
+ }
20
+ };
21
+ export const buttonGroup = {
22
+ ...inheritButtonGroup,
23
+ default: {
24
+ size: "md",
25
+ orientation: "horizontal"
26
+ }
27
+ };
28
+ export const button = {
29
+ ...inheritButton,
30
+ default: {
31
+ size: "md",
32
+ variant: "solid",
33
+ color: "primary",
34
+ loadingIcon: "i-heroicons-arrow-path-20-solid"
35
+ }
36
+ };
2
37
  export const modal = {
3
38
  ...inheritModal,
4
39
  header: "px-4 py-2 border-b",
@@ -42,3 +77,14 @@ export const slideover = {
42
77
  size: "md"
43
78
  }
44
79
  };
80
+ export const tabs = {
81
+ ...inheritTabs
82
+ };
83
+ export const badge = {
84
+ ...inheritBadge,
85
+ default: {
86
+ size: "sm",
87
+ variant: "solid",
88
+ color: "primary"
89
+ }
90
+ };
@@ -15,4 +15,5 @@ export declare class ObjectHelper {
15
15
  static createStatus(): IStatus;
16
16
  static isInvalidParams(errorData: any): boolean;
17
17
  static isEmpty: (object: any) => boolean;
18
+ static stringArrayToObject: (array: string[]) => Record<string, string>;
18
19
  }
@@ -105,4 +105,10 @@ export class ObjectHelper {
105
105
  static isEmpty = (object) => {
106
106
  return _isEmpty(object);
107
107
  };
108
+ static stringArrayToObject = (array) => {
109
+ return array.reduce((obj, item) => {
110
+ obj[item] = item;
111
+ return obj;
112
+ }, {});
113
+ };
108
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finema/core",
3
- "version": "1.3.23",
3
+ "version": "1.3.24",
4
4
  "repository": "https://gitlab.finema.co/finema/ui-kit",
5
5
  "license": "MIT",
6
6
  "author": "Finema Development Team",
@@ -69,6 +69,7 @@
69
69
  "nuxt": "^3.7.4",
70
70
  "prettier": "^3.0.3",
71
71
  "release-it": "^16.2.1",
72
+ "sass": "^1.69.5",
72
73
  "stylelint": "^15.10.3",
73
74
  "stylelint-config-prettier-scss": "^1.0.0",
74
75
  "stylelint-config-standard-scss": "^11.0.0",