@ramathibodi/nuxt-commons 0.1.58 → 0.1.60

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.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.1.58",
7
+ "version": "0.1.60",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -102,7 +102,8 @@ const assignNestedValue = (obj: any, keys: string[], value: any) => {
102
102
  const parseIfJson = (value: any) => {
103
103
  if (typeof value === 'string') {
104
104
  try {
105
- return JSON.parse(value)
105
+ let parsedValue = JSON.parse(value)
106
+ return (parsedValue==value) ? value : parsedValue
106
107
  } catch {
107
108
  // If parsing fails, return the original value
108
109
  return value
@@ -1,37 +1,30 @@
1
1
  <script lang="ts" setup>
2
- import Datepicker from '@vuepic/vue-datepicker'
3
2
  import '@vuepic/vue-datepicker/dist/main.css'
4
3
  import {computed, nextTick, onMounted, ref, watch, watchEffect} from 'vue'
5
- import {type dateFormat, Datetime} from '../../utils/datetime'
4
+ import {VTextField} from "vuetify/components/VTextField";
5
+ import {isArray, isString} from "lodash-es";
6
+ import {useRules} from "../../composables/utils/validation";
6
7
 
7
8
  interface IDobPrecision {
8
9
  yearMonthDay: string
9
10
  yearMonth: string
10
11
  year: string
11
12
  }
13
+
12
14
  interface Props {
13
- readonly?: boolean
14
- locale?: 'TH' | 'EN'
15
- format?: dateFormat | string
16
- modelValue?: string | null
17
- holiday?: object[] | undefined
18
- minDate?: Date | string
19
- maxDate?: Date | string
20
- pickerOnly?: boolean
21
15
  flow?: ('month' | 'year' | 'calendar' | 'time' | 'minutes' | 'hours' | 'seconds')[]
22
16
  dobPrecisionText?: IDobPrecision
17
+ rules?: typeof VTextField['rules']
23
18
  }
24
19
 
25
20
  const props = withDefaults(defineProps<Props>(), {
26
- readonly: false,
27
- locale: 'TH',
28
- format: 'shortDate',
29
- pickerOnly: false,
30
21
  flow: () => ['year', 'month', 'calendar'],
31
22
  })
32
23
 
33
24
  const emit = defineEmits(['update:modelValue'])
34
25
 
26
+ const modelValue = defineModel<string>()
27
+
35
28
  const dobPrecisionText = computed(() => {
36
29
  if (props.dobPrecisionText) return props.dobPrecisionText
37
30
  else return {
@@ -61,161 +54,47 @@ const changeDobPrecision = () => {
61
54
  }
62
55
  }
63
56
 
64
- const selectedDate = ref<string | null>(null)
65
- const displayedDate = ref<string | null>(null)
66
-
67
- const isMenuOpen = ref(false)
68
- const isTextFieldFocused = ref(false)
69
- const hasTextFieldInput = ref(false)
70
-
71
- function handleTextFieldFocus(event: Event) {
72
- isTextFieldFocused.value = true
73
- nextTick(() => {
74
- (event.target as HTMLInputElement).select()
75
- })
76
- }
77
-
78
- function handleTextFieldInput() {
79
- if (!hasTextFieldInput.value) {
80
- hasTextFieldInput.value = true
81
- isMenuOpen.value = false
82
- }
83
- }
84
-
85
- function handleTextFieldBlur() {
86
- if (hasTextFieldInput.value) {
87
- updateDate(displayedDate.value)
88
- hasTextFieldInput.value = false
89
- }
90
- isTextFieldFocused.value = false
91
- }
92
-
93
- function handleTextFieldEnterKey() {
94
- handleTextFieldBlur()
95
- }
96
-
97
- function updateDatePicker(dateString: string | null) {
98
- isMenuOpen.value = false
99
- updateDate(dateString)
100
- }
101
-
102
- function updateDate(dateString: string | null) {
103
- const dateTime = Datetime().fromString(dateString, undefined, props.locale)
104
- if (!dateTime.luxonDateTime.isValid) {
105
- displayedDate.value = null
106
- selectedDate.value = null
107
- }
108
- else {
109
- if (dobPrecisionSelected.value=="yearMonth") {
110
- dateTime.luxonDateTime = dateTime.luxonDateTime.startOf('month')
111
- }
112
- if (dobPrecisionSelected.value=="year") {
113
- dateTime.luxonDateTime = dateTime.luxonDateTime.startOf('year')
114
- }
115
- selectedDate.value = dateTime.toFormat('yyyy-MM-dd', 'EN')
116
- displayedDate.value = selectedDate.value
57
+ const computedRules = computed(() => {
58
+ if (props.rules && isArray(props.rules)) {
59
+ return props.rules.includes("DateHappen") ? props.rules : props.rules.concat("DateHappen")
60
+ } else {
61
+ return ['DateHappen']
117
62
  }
63
+ })
118
64
 
119
- if (!isTextFieldFocused.value) displayedDate.value = formatDate(displayedDate.value)
120
- }
121
-
122
- function formatDate(dateString: string | null) {
123
- if (!dateString) return null
124
-
125
- let displayFormat = props.format
65
+ const dobFormat = computed(() => {
66
+ let displayFormat : string|undefined = undefined
126
67
  if (dobPrecisionSelected.value=="yearMonth") {
127
68
  displayFormat = "MMM yyyy"
128
69
  }
129
70
  if (dobPrecisionSelected.value=="year") {
130
71
  displayFormat = "yyyy"
131
72
  }
132
-
133
- const dateTime = Datetime().fromString(dateString, undefined, props.locale)
134
- return dateTime.toFormat(displayFormat, props.locale)
135
- }
136
-
137
- function handleTextFieldClear() {
138
- resetDatePicker()
139
- }
140
-
141
- function resetDatePicker() {
142
- selectedDate.value = null
143
- displayedDate.value = null
144
- }
145
-
146
- watchEffect(() => {
147
- if (!isTextFieldFocused.value && selectedDate.value) {
148
- displayedDate.value = formatDate(selectedDate.value)
149
- }
150
- else {
151
- displayedDate.value = selectedDate.value
152
- }
153
- })
154
-
155
- watch(selectedDate, (newValue) => {
156
- emit('update:modelValue', newValue)
157
- })
158
-
159
- watch(() => props.modelValue, () => {
160
- updateDate(props.modelValue || null)
161
- }, { immediate: true })
162
-
163
- watch(dobPrecisionSelected,()=>{
164
- updateDate(selectedDate.value)
73
+ return displayFormat
165
74
  })
166
-
167
- function toggleMenuOpen(trigger: string) {
168
- if ((trigger === 'textField' && props.pickerOnly) || (trigger === 'icon' && !props.pickerOnly)) {
169
- isMenuOpen.value = true
170
- }
171
- }
172
75
  </script>
173
76
 
174
77
  <template>
175
- <v-menu
176
- v-model="isMenuOpen"
177
- :open-on-click="false"
78
+ <FormDate
79
+ v-model="modelValue"
80
+ :flow="props.flow"
81
+ :format="dobFormat"
82
+ :rules="computedRules"
178
83
  >
179
- <template #activator="{ props: activatorProps }">
180
- <v-text-field
181
- ref="textField"
182
- v-model="displayedDate"
183
- :readonly="readonly"
184
- v-bind="$attrs"
185
- @focus="handleTextFieldFocus"
186
- @blur="handleTextFieldBlur"
187
- @keydown="handleTextFieldInput"
188
- @keyup.enter="handleTextFieldEnterKey"
189
- @click:clear="handleTextFieldClear"
190
- @click="toggleMenuOpen('textField')"
84
+ <template #append="{ isReadonly, isDisabled, activatorProps, toggleMenuOpen}">
85
+ <span
86
+ style="cursor: pointer;"
87
+ class="font-weight-medium"
88
+ @click="(isReadonly.value || isDisabled.value) ? undefined : changeDobPrecision()"
89
+ >{{ dobPrecisionDisplay }}</span>
90
+ &nbsp;
91
+ <v-icon
92
+ :disabled="isReadonly.value || isDisabled.value"
93
+ v-bind="activatorProps"
94
+ @click="toggleMenuOpen('icon')"
191
95
  >
192
- <template #append-inner>
193
- <span
194
- style="cursor: pointer;"
195
- class="font-weight-medium"
196
- @click="changeDobPrecision"
197
- >{{ dobPrecisionDisplay }}</span>
198
- &nbsp;
199
- <v-icon
200
- v-bind="activatorProps"
201
- @click="toggleMenuOpen('icon')"
202
- >
203
- fa:fa-regular fa-calendar
204
- </v-icon>
205
- </template>
206
- </v-text-field>
96
+ fa:fa-regular fa-calendar
97
+ </v-icon>
207
98
  </template>
208
- <Datepicker
209
- v-model="selectedDate"
210
- model-type="yyyy-MM-dd"
211
- :enable-time-picker="false"
212
- :flow="flow"
213
- :min-date="props.minDate"
214
- :max-date="props.maxDate"
215
- auto-apply
216
- inline
217
- :locale="locale"
218
- @update:model-value="updateDatePicker"
219
- />
220
- </v-menu>
99
+ </FormDate>
221
100
  </template>
@@ -3,9 +3,10 @@ import { ref, watch, watchEffect, nextTick, defineExpose, computed} from 'vue'
3
3
  import { VTextField } from 'vuetify/components/VTextField'
4
4
  import Datepicker from '@vuepic/vue-datepicker'
5
5
  import '@vuepic/vue-datepicker/dist/main.css'
6
- import {isArray, isString} from "lodash-es";
6
+ import { isArray, isString } from "lodash-es";
7
7
  import { type dateFormat, Datetime } from '../../utils/datetime'
8
8
  import { useRules } from "../../composables/utils/validation";
9
+ import { th } from 'date-fns/locale';
9
10
 
10
11
  interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
11
12
  locale?: 'TH' | 'EN'
@@ -17,6 +18,8 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props
17
18
  pickerOnly?: boolean
18
19
  flow?: ('month' | 'year' | 'calendar' | 'time' | 'minutes' | 'hours' | 'seconds')[]
19
20
  rules?: typeof VTextField['rules']
21
+
22
+ defaultDate?: boolean | string
20
23
  }
21
24
 
22
25
  const props = withDefaults(defineProps<Props>(), {
@@ -24,6 +27,8 @@ const props = withDefaults(defineProps<Props>(), {
24
27
  format: 'shortDate',
25
28
  pickerOnly: false,
26
29
  flow: () => [],
30
+
31
+ defaultDate: false,
27
32
  })
28
33
 
29
34
  const emit = defineEmits(['update:modelValue'])
@@ -155,8 +160,29 @@ watch(selectedDate, (newValue) => {
155
160
  emit('update:modelValue', newValue)
156
161
  })
157
162
 
158
- watch(() => props.modelValue, () => {
159
- updateDate(props.modelValue || null)
163
+ watch(() => props.modelValue, (newValue,oldValue) => {
164
+ if (!oldValue && !newValue && props.defaultDate) {
165
+ if (!oldValue && !newValue && props.defaultDate) {
166
+ let defaultDate: string | null = null;
167
+
168
+ if (props.defaultDate === true) {
169
+ defaultDate = Datetime().now().toFormat('yyyy-MM-dd', 'EN');
170
+ } else if (typeof props.defaultDate === 'string' &&/^[+-]?\d+$/.test(props.defaultDate.trim())) {
171
+ defaultDate = Datetime().now().luxonDateTime
172
+ .plus({ days: Number(props.defaultDate) })
173
+ .toFormat('yyyy-MM-dd');
174
+ } else {
175
+ const dateTime = Datetime().fromString(props.defaultDate)
176
+ if (dateTime.luxonDateTime.isValid) defaultDate = dateTime.toFormat('yyyy-MM-dd')
177
+ }
178
+
179
+ updateDate(defaultDate);
180
+ } else {
181
+ updateDate(newValue ?? null);
182
+ }
183
+ } else {
184
+ updateDate(props.modelValue || null)
185
+ }
160
186
  }, { immediate: true })
161
187
 
162
188
  function toggleMenuOpen(trigger: string) {
@@ -196,14 +222,16 @@ defineExpose({
196
222
  @click:clear="handleTextFieldClear"
197
223
  @click="toggleMenuOpen('textField')"
198
224
  >
199
- <template #append="{ isReadonly, isDisabled }">
200
- <v-icon
201
- :disabled="isReadonly.value || isDisabled.value"
202
- v-bind="activatorProps"
203
- @click="toggleMenuOpen('icon')"
204
- >
205
- fa:fa-regular fa-calendar
206
- </v-icon>
225
+ <template #append="appendProps">
226
+ <slot name="append" v-bind="appendProps" :toggleMenuOpen="toggleMenuOpen" :activatorProps="activatorProps">
227
+ <v-icon
228
+ :disabled="appendProps.isReadonly?.value || appendProps.isDisabled?.value"
229
+ v-bind="activatorProps"
230
+ @click="toggleMenuOpen('icon')"
231
+ >
232
+ fa:fa-regular fa-calendar
233
+ </v-icon>
234
+ </slot>
207
235
  </template>
208
236
  </v-text-field>
209
237
  </template>
@@ -217,7 +245,15 @@ defineExpose({
217
245
  auto-apply
218
246
  inline
219
247
  :locale="locale"
248
+ :format-locale="(locale=='TH') ? th : undefined"
220
249
  @update:model-value="updateDatePicker"
221
- />
250
+ >
251
+ <template #year="{value}" v-if="locale=='TH'">
252
+ {{value+543}}
253
+ </template>
254
+ <template #year-overlay-value="{value}" v-if="locale=='TH'">
255
+ {{value+543}}
256
+ </template>
257
+ </Datepicker>
222
258
  </v-menu>
223
259
  </template>
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
- import { ref, computed, watch, watchEffect, nextTick } from 'vue'
3
- import { union,isBoolean,isArray,isString } from 'lodash-es'
2
+ import {ref, computed, watch, watchEffect, nextTick, useAttrs} from 'vue'
3
+ import {union, isBoolean, isArray, isString, omit} from 'lodash-es'
4
4
  import { VTextField } from 'vuetify/components/VTextField'
5
5
  import { type dateFormat, Datetime } from '../../utils/datetime'
6
6
  import { useRules } from '../../composables/utils/validation'
@@ -39,6 +39,11 @@ const props = withDefaults(defineProps<Props>(), {
39
39
 
40
40
  const emit = defineEmits(['update:modelValue'])
41
41
 
42
+ const attrs = useAttrs()
43
+ const plainAttrs = computed(() => {
44
+ return omit(attrs, ['modelValue', 'onUpdate:modelValue','defaultDate','defaultDateTime','fixedDate'])
45
+ })
46
+
42
47
  const dateRef = ref<VTextField>()
43
48
  const timeRef = ref<VTextField>()
44
49
 
@@ -109,8 +114,16 @@ function reset() {
109
114
  }
110
115
  } else {
111
116
  if (props.defaultDate) {
112
- const dateTime = (isBoolean(props.defaultDate)) ? Datetime().now() : Datetime().fromString(props.defaultDate)
113
- if (dateTime.luxonDateTime.isValid) datePart.value = dateTime.toFormat('yyyy-MM-dd')
117
+ if (props.defaultDate === true) {
118
+ datePart.value = Datetime().now().toFormat('yyyy-MM-dd', 'EN');
119
+ } else if (typeof props.defaultDate === 'string' &&/^[+-]?\d+$/.test(props.defaultDate.trim())) {
120
+ datePart.value = Datetime().now().luxonDateTime
121
+ .plus({ days: Number(props.defaultDate) })
122
+ .toFormat('yyyy-MM-dd');
123
+ } else {
124
+ const dateTime = Datetime().fromString(props.defaultDate)
125
+ if (dateTime.luxonDateTime.isValid) datePart.value = dateTime.toFormat('yyyy-MM-dd')
126
+ }
114
127
  }
115
128
  }
116
129
  }
@@ -175,7 +188,7 @@ watch(() => props.modelValue, () => {
175
188
  :disabled="fixedDate"
176
189
  :min-date="minDate"
177
190
  :max-date="maxDate"
178
- v-bind="$attrs"
191
+ v-bind="plainAttrs"
179
192
  />
180
193
  </v-col>
181
194
  <v-col cols="4">
@@ -187,7 +200,7 @@ watch(() => props.modelValue, () => {
187
200
  :enable-seconds="enableSeconds"
188
201
  :picker-only="pickerOnly"
189
202
  :readonly="readonly"
190
- v-bind="$attrs"
203
+ v-bind="plainAttrs"
191
204
  />
192
205
  </v-col>
193
206
  </v-row>
@@ -4,7 +4,6 @@ import {cloneDeep, isEqual} from 'lodash-es'
4
4
  import type {FormDialogCallback} from '../../types/formDialog'
5
5
 
6
6
  interface Props {
7
- maxWidth?: number | string
8
7
  fullscreen?: boolean
9
8
  title?: string
10
9
  initialData?: object
@@ -104,7 +103,6 @@ watch(() => isShowing.value, (newValue) => {
104
103
  <v-dialog
105
104
  v-model="isShowing"
106
105
  :fullscreen="fullscreen"
107
- :max-width="maxWidth"
108
106
  persistent
109
107
  scrollable
110
108
  >
@@ -15,6 +15,10 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof VDataTable['$props
15
15
  noDataText?: string
16
16
  modelValue?: Record<string, any>[]
17
17
  modelKey?: string
18
+ dialogWidth?: string | number
19
+ dialogMaxWidth?: string | number
20
+ dialogHeight?: string | number
21
+ dialogMaxHeight?: string | number
18
22
  dialogFullscreen?: boolean
19
23
  initialData?: Record<string, any>
20
24
  toolbarColor?: string
@@ -327,6 +331,10 @@ defineExpose({
327
331
  @update="updateItem"
328
332
  @afterLeave="emit('close:dialog')"
329
333
  :saveAndStay="saveAndStay"
334
+ :width="dialogWidth"
335
+ :height="dialogHeight"
336
+ :max-width="dialogMaxWidth"
337
+ :max-height="dialogMaxHeight"
330
338
  v-if="!props.inputPadOnly"
331
339
  >
332
340
  <template #default="slotData">
@@ -1,96 +1,54 @@
1
- <script setup lang="ts">
2
- import {VSelect} from 'vuetify/components/VSelect'
3
- import {concat} from 'lodash-es'
4
- import {computed, ref, watch} from 'vue'
5
- import {useGraphQl} from '../../composables/graphql'
6
- import {useAlert} from '../../composables/alert'
1
+ <script lang="ts" setup>
2
+ import { VCombobox } from 'vuetify/components/VCombobox'
3
+ import { withDefaults } from 'vue'
4
+ import { useLookupListMaster, type StaticMasterLikeProps } from '../../composables/lookupListMaster'
7
5
 
8
- interface Props extends /* @vue-ignore */ InstanceType<typeof VSelect['$props']> {
9
- modelValue?: string
10
- groupKey: string
11
- fields?: string[]
12
- lang?: 'TH' | 'EN'
13
- }
14
- const props = withDefaults(defineProps<Props>(), {
15
- lang: 'TH',
16
- })
17
-
18
- const emit = defineEmits(['update:modelValue'])
19
- const items = ref<Array<any>>([])
20
- const alert = useAlert()
21
- const selectedItem = ref<any>()
22
- function query() {
23
- const variables: Record<string, any> = { groupKey: { value: props.groupKey, required: true } }
24
- let fields: any[] = ['itemCode', 'itemValue', 'itemValueAlternative']
25
- if (props.fields) fields = concat(fields, props.fields)
26
-
27
- useGraphQl().queryPromise('masterItemByGroupKey', fields, variables).then((result: any) => {
28
- items.value = result
29
- }).catch((error) => {
30
- alert?.addAlert({
31
- message: `${error.message}`,
32
- alertType: 'error',
33
- })
34
- })
35
- }
36
-
37
- watch(() => props.groupKey, () => {
38
- query()
39
- }, { immediate: true })
40
-
41
- watch(selectedItem, (newValue) => {
42
- emit('update:modelValue', newValue.itemCode)
43
- })
6
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VCombobox['$props']> {}
44
7
 
45
- watch(
46
- () => props.modelValue,
47
- (newVal) => {
48
- if (newVal && items.value.length > 0) {
49
- const found = items.value.find(item => item.itemCode === newVal)
50
- if (found) selectedItem.value = found
51
- }
52
- },
53
- { immediate: true }
54
- )
55
-
56
- const itemTitleField = computed(() => {
57
- if (props.lang == 'TH') return 'itemValue'
58
- else return 'itemValueAlternative'
8
+ const props = withDefaults(defineProps<Props & StaticMasterLikeProps>(), {
9
+ sortBy: 'itemValue',
10
+ showCode: false,
11
+ lang: 'TH',
12
+ noDataText: 'ไม่พบข้อมูล',
13
+ waitForFilter: false,
14
+ cache: false,
59
15
  })
60
16
 
61
- query()
17
+ const {
18
+ computedModelName,
19
+ computedModelBy,
20
+ computedFields,
21
+ itemTitleField,
22
+ computedNoDataText,
23
+ computedSortBy,
24
+ formatItemTitle,
25
+ } = useLookupListMaster(props)
62
26
  </script>
63
27
 
64
28
  <template>
65
- <v-select
66
- v-model="selectedItem"
67
- :item-title="itemTitleField"
68
- :items="items"
69
- item-value="itemCode"
29
+ <model-combobox
30
+ :model-name="computedModelName"
31
+ :model-by="computedModelBy"
32
+ :fields="computedFields"
33
+ :sort-by="computedSortBy"
34
+ :item-title="itemTitleField"
35
+ item-value="itemCode"
36
+ :no-data-text="computedNoDataText"
37
+ :show-code="props.showCode"
38
+ :cache="props.cache"
70
39
  >
71
- <template
72
- v-for="(_, name, index) in ($slots as {})"
73
- :key="index"
74
- #[name]="slotData"
75
- >
76
- <slot
77
- :name="name"
78
- v-bind="((slotData || {}) as object)"
79
- :operation="operation"
80
- />
40
+ <!-- pass-through slots -->
41
+ <!-- @ts-ignore -->
42
+ <template v-for="(_, name, index) in ($slots as {})" :key="index" #[name]="slotData">
43
+ <slot :name="name" v-bind="((slotData || {}) as object)" :operation="computedModelName" />
81
44
  </template>
82
- <template
83
- v-if="!$slots.item"
84
- #item="{ props, item }"
85
- >
86
- <v-list-item
87
- v-bind="props"
88
- :title="item.raw.itemValue"
89
- />
90
- </template>
91
- </v-select>
92
- </template>
93
45
 
94
- <style scoped>
46
+ <template v-if="!$slots.item" #item="{ props: itemProps, item }">
47
+ <v-list-item v-bind="itemProps" :title="formatItemTitle(item)" />
48
+ </template>
95
49
 
96
- </style>
50
+ <template v-if="!$slots.selection && props.showCode" #selection="{ item }">
51
+ {{ formatItemTitle(item) }}
52
+ </template>
53
+ </model-combobox>
54
+ </template>
@@ -0,0 +1,62 @@
1
+ <script lang="ts" setup>
2
+ import { VCombobox } from 'vuetify/components/VCombobox'
3
+ import { defineModel, withDefaults } from 'vue'
4
+ import { useLookupList, type StaticLookupProps } from '../../composables/lookupList'
5
+
6
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VCombobox['$props']> {}
7
+
8
+ const props = withDefaults(defineProps<Props & StaticLookupProps>(), {
9
+ fuzzy: false,
10
+ showCode: false,
11
+ cache: false,
12
+ })
13
+
14
+ const emit = defineEmits<{
15
+ (e: 'update:selectedObject', object: any | any[]): void
16
+ }>()
17
+
18
+ const selectedItems = defineModel<any>()
19
+
20
+ const {
21
+ computedItems,
22
+ computedFilterKeys,
23
+ computedPlaceholder,
24
+ computedNoDataText,
25
+ isLoading,
26
+ isErrorLoading,
27
+ } = useLookupList(props, emit, selectedItems)
28
+ </script>
29
+
30
+ <template>
31
+ <v-combobox
32
+ v-model="selectedItems"
33
+ v-bind="$attrs"
34
+ :items="computedItems"
35
+ :filter-keys="computedFilterKeys"
36
+ :item-title="props.itemTitle"
37
+ :item-value="props.itemValue"
38
+ :loading="isLoading"
39
+ :placeholder="computedPlaceholder"
40
+ :no-data-text="computedNoDataText"
41
+ :multiple="props.multiple"
42
+ :return-object="false"
43
+ >
44
+ <!-- passthrough slots -->
45
+ <!-- @ts-ignore -->
46
+ <template v-for="(_, name, index) in ($slots as {})" :key="index" #[name]="slotData">
47
+ <slot :name="name" v-bind="((slotData || {}) as object)" />
48
+ </template>
49
+
50
+ <template v-if="!$slots.item" #item="{ props: itemProps, item }">
51
+ <v-list-item v-bind="itemProps" :title="(props.showCode ? item.value + '-' : '') + item.title" />
52
+ </template>
53
+
54
+ <template v-if="!$slots.selection && props.showCode" #selection="{ item }">
55
+ {{ item.value + '-' + item.title }}
56
+ </template>
57
+
58
+ <template v-if="isErrorLoading" #append>
59
+ <v-icon color="error">mdi mdi-alert</v-icon>
60
+ </template>
61
+ </v-combobox>
62
+ </template>
@@ -16,6 +16,10 @@ defineOptions({
16
16
  interface Props extends /* @vue-ignore */ InstanceType<typeof VDataTable['$props']> {
17
17
  title: string
18
18
  noDataText?: string
19
+ dialogWidth?: string | number
20
+ dialogMaxWidth?: string | number
21
+ dialogHeight?: string | number
22
+ dialogMaxHeight?: string | number
19
23
  dialogFullscreen?: boolean
20
24
  initialData?: Record<string, any>
21
25
  toolbarColor?: string
@@ -302,6 +306,10 @@ defineExpose({ reload,operation })
302
306
  @afterLeave="emit('close:dialog')"
303
307
  :saveAndStay="saveAndStay"
304
308
  :readonly="isDialogReadonly"
309
+ :width="dialogWidth"
310
+ :height="dialogHeight"
311
+ :max-width="dialogMaxWidth"
312
+ :max-height="dialogMaxHeight"
305
313
  >
306
314
  <template #default="slotData">
307
315
  <slot
@@ -1,5 +1,5 @@
1
1
  import { type Ref } from 'vue';
2
- export interface LookupProps {
2
+ export interface StaticLookupProps {
3
3
  fuzzy?: boolean;
4
4
  sortBy?: string | string[];
5
5
  showCode?: boolean;
@@ -9,16 +9,18 @@ export interface LookupProps {
9
9
  itemValue: string;
10
10
  fields?: Array<string | object>;
11
11
  cache?: boolean | number;
12
+ filterKeys?: string | string[];
13
+ noDataText?: string;
14
+ placeholder?: string;
15
+ multiple?: boolean;
16
+ }
17
+ export interface LookupProps extends StaticLookupProps {
12
18
  serverSearch?: boolean;
13
19
  serverSearchKey?: string;
14
20
  searchSearchSort?: boolean;
15
21
  serverSearchDebounce?: number;
16
22
  serverSearchText?: string;
17
23
  serverSearchLoadingText?: string;
18
- filterKeys?: string | string[];
19
- noDataText?: string;
20
- placeholder?: string;
21
- multiple?: boolean;
22
24
  modelSelectedItem?: string;
23
25
  modelSelectedItemBy?: Record<string, any>;
24
26
  modelSelectedItemKey?: string;
@@ -128,7 +128,7 @@ export function useLookupList(props, emit, selectedItems) {
128
128
  }
129
129
  emit("update:selectedObject", props.multiple ? selectedItemsObject.value : selectedItemsObject.value[0]);
130
130
  }
131
- watch(
131
+ watchDebounced(
132
132
  () => [
133
133
  props.modelName,
134
134
  props.serverSearch,
@@ -138,7 +138,7 @@ export function useLookupList(props, emit, selectedItems) {
138
138
  queryFields.value
139
139
  ],
140
140
  () => loadItems(),
141
- { immediate: true, deep: true }
141
+ { immediate: true, deep: true, debounce: 30, maxWait: 200 }
142
142
  );
143
143
  watchDebounced(
144
144
  searchData,
@@ -1,6 +1,6 @@
1
1
  export type Lang = 'TH' | 'EN';
2
2
  export type MasterSortBy = 'itemCode' | 'itemValue';
3
- export interface MasterLikeProps {
3
+ export interface StaticMasterLikeProps {
4
4
  sortBy?: MasterSortBy;
5
5
  showCode?: boolean;
6
6
  groupKey: string;
@@ -11,9 +11,11 @@ export interface MasterLikeProps {
11
11
  filterText?: string;
12
12
  waitForFilter?: boolean;
13
13
  waitForFilterText?: string;
14
- meilisearch?: boolean;
15
14
  cache?: boolean | number;
16
15
  }
16
+ export interface MasterLikeProps extends StaticMasterLikeProps {
17
+ meilisearch?: boolean;
18
+ }
17
19
  export declare function useLookupListMaster(props: MasterLikeProps): {
18
20
  computedModelName: import("vue").ComputedRef<string>;
19
21
  computedModelBy: import("vue").ComputedRef<Record<string, any>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",