@ramathibodi/nuxt-commons 0.1.44 → 0.1.45

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.44",
7
+ "version": "0.1.45",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.3",
10
10
  "unbuild": "2.0.0"
@@ -59,7 +59,6 @@ watch(props.modelValue, () => {
59
59
  </script>
60
60
 
61
61
  <template>
62
- <v-container fluid>
63
62
  <label class="text-body-1 opacity-60">{{props.label}}</label>
64
63
  <div :class="`d-flex ${inline ? 'flex-row':'flex-column'}`">
65
64
  <v-checkbox v-for="item in computeItems"
@@ -83,7 +82,6 @@ watch(props.modelValue, () => {
83
82
  <label class="text-error text-subtitle-2 ml-1">
84
83
  {{computedRules}}
85
84
  </label>
86
- </v-container>
87
85
 
88
86
  </template>
89
87
 
@@ -6,7 +6,6 @@ import '@vuepic/vue-datepicker/dist/main.css'
6
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 {VInput} from "vuetify/components/VInput";
10
9
 
11
10
  interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
12
11
  locale?: 'TH' | 'EN'
@@ -180,50 +179,45 @@ defineExpose({
180
179
  </script>
181
180
 
182
181
  <template>
183
- <v-input v-model="displayedDate" v-bind="$attrs" ref="inputRef">
184
- <template #default="{isReadonly,isDisabled}">
185
- <v-menu
186
- v-model="isMenuOpen"
187
- :open-on-click="false"
182
+ <v-menu
183
+ v-model="isMenuOpen"
184
+ :open-on-click="false"
185
+ >
186
+ <template #activator="{ props: activatorProps }">
187
+ <v-text-field
188
+ ref="textFieldRef"
189
+ v-model="displayedDate"
190
+ :rules="computedRules"
191
+ v-bind="$attrs"
192
+ @focus="handleTextFieldFocus"
193
+ @blur="handleTextFieldBlur"
194
+ @keydown="handleTextFieldInput"
195
+ @keyup.enter="handleTextFieldEnterKey"
196
+ @click:clear="handleTextFieldClear"
197
+ @click="toggleMenuOpen('textField')"
188
198
  >
189
- <template #activator="{ props: activatorProps }">
190
- <v-text-field
191
- ref="textFieldRef"
192
- v-model="displayedDate"
193
- :rules="computedRules"
194
- v-bind="$attrs"
195
- @focus="handleTextFieldFocus"
196
- @blur="handleTextFieldBlur"
197
- @keydown="handleTextFieldInput"
198
- @keyup.enter="handleTextFieldEnterKey"
199
- @click:clear="handleTextFieldClear"
200
- @click="toggleMenuOpen('textField')"
201
- >
202
- <template #append-inner>
203
- <v-icon v-if="!isReadonly.value"
204
- v-bind="activatorProps"
205
- @click="toggleMenuOpen('icon')"
206
- >
207
- fa:fa-regular fa-calendar
208
- </v-icon>
209
- </template>
210
- </v-text-field>
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>
211
207
  </template>
212
- <Datepicker
213
- v-model="selectedDate"
214
- model-type="yyyy-MM-dd"
215
- :enable-time-picker="false"
216
- :flow="flow"
217
- :min-date="props.minDate"
218
- :max-date="props.maxDate"
219
- auto-apply
220
- inline
221
- :locale="locale"
222
- @update:model-value="updateDatePicker"
223
- />
224
- </v-menu>
208
+ </v-text-field>
225
209
  </template>
226
-
227
- </v-input>
228
-
229
- </template>
210
+ <Datepicker
211
+ v-model="selectedDate"
212
+ model-type="yyyy-MM-dd"
213
+ :enable-time-picker="false"
214
+ :flow="flow"
215
+ :min-date="props.minDate"
216
+ :max-date="props.maxDate"
217
+ auto-apply
218
+ inline
219
+ :locale="locale"
220
+ @update:model-value="updateDatePicker"
221
+ />
222
+ </v-menu>
223
+ </template>
@@ -4,7 +4,6 @@ import { union,isBoolean,isArray,isString } 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'
7
- import {VInput} from "vuetify/components/VInput";
8
7
 
9
8
  interface Props {
10
9
  modelValue?: string | null
@@ -97,7 +96,7 @@ const computedTimeRules = computed(() => union(computedRules.value, props.timeRu
97
96
 
98
97
  const datePart = ref<string | null>(null)
99
98
  const timePart = ref<string | null>(null)
100
- const pauseEmit = ref(false)
99
+ const pauseEmit = ref(true)
101
100
 
102
101
  function reset() {
103
102
  datePart.value = null
@@ -159,43 +158,38 @@ watch(() => props.modelValue, () => {
159
158
  </script>
160
159
 
161
160
  <template>
162
- <v-input v-model="datePart" v-bind="$attrs" ref="inputRef">
163
- <template #default="{isReadonly,isDisabled}">
164
- <v-container
165
- :fluid="true"
166
- class="pa-0"
167
- >
168
- <v-row :dense="dense">
169
- <v-col cols="8">
170
- <FormDate
171
- v-model="datePart"
172
- ref="dateRef"
173
- :rules="computedDateRules"
174
- :label="label"
175
- :format="format"
176
- :picker-only="pickerOnly"
177
- :readonly="isReadonly.value"
178
- :disabled="fixedDate"
179
- :min-date="minDate"
180
- :max-date="maxDate"
181
- v-bind="$attrs"
182
- />
183
- </v-col>
184
- <v-col cols="4">
185
- <FormTime
186
- v-model="timePart"
187
- ref="timeRef"
188
- :rules="computedTimeRules"
189
- :label="label"
190
- :enable-seconds="enableSeconds"
191
- :picker-only="pickerOnly"
192
- :readonly="isReadonly.value"
193
- v-bind="$attrs"
194
- />
195
- </v-col>
196
- </v-row>
197
- </v-container>
198
- </template>
199
- </v-input>
200
-
161
+ <v-container
162
+ :fluid="true"
163
+ class="pa-0"
164
+ >
165
+ <v-row :dense="dense">
166
+ <v-col cols="8">
167
+ <FormDate
168
+ v-model="datePart"
169
+ ref="dateRef"
170
+ :rules="computedDateRules"
171
+ :label="label"
172
+ :format="format"
173
+ :picker-only="pickerOnly"
174
+ :readonly="readonly"
175
+ :disabled="fixedDate"
176
+ :min-date="minDate"
177
+ :max-date="maxDate"
178
+ v-bind="$attrs"
179
+ />
180
+ </v-col>
181
+ <v-col cols="4">
182
+ <FormTime
183
+ v-model="timePart"
184
+ ref="timeRef"
185
+ :rules="computedTimeRules"
186
+ :label="label"
187
+ :enable-seconds="enableSeconds"
188
+ :picker-only="pickerOnly"
189
+ :readonly="readonly"
190
+ v-bind="$attrs"
191
+ />
192
+ </v-col>
193
+ </v-row>
194
+ </v-container>
201
195
  </template>
@@ -4,7 +4,6 @@ import { VTextField } from 'vuetify/components/VTextField'
4
4
  import Datepicker from '@vuepic/vue-datepicker'
5
5
  import '@vuepic/vue-datepicker/dist/main.css'
6
6
  import { Datetime } from '../../utils/datetime'
7
- import {VInput} from "vuetify/components/VInput";
8
7
 
9
8
  interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
10
9
  enableSeconds?: boolean
@@ -123,49 +122,45 @@ defineExpose({
123
122
  </script>
124
123
 
125
124
  <template>
126
- <v-input v-model="displayedDate" v-bind="$attrs" ref="inputRef">
127
- <template #default="{isReadonly,isDisabled}">
128
- <v-menu
129
- v-model="isMenuOpen"
130
- :close-on-content-click="false"
131
- :open-on-click="false"
125
+ <v-menu
126
+ v-model="isMenuOpen"
127
+ :close-on-content-click="false"
128
+ :open-on-click="false"
129
+ >
130
+ <template #activator="{ props }">
131
+ <v-text-field
132
+ ref="textFieldRef"
133
+ v-model="tempTime"
134
+ v-bind="$attrs"
135
+ @focus="onTextFieldFocus"
136
+ @blur="onTextFieldBlur"
137
+ @keydown="onTextFieldTyped"
138
+ @keyup.enter="onTextFieldEnterKey"
139
+ @click:clear="onTextFieldClear"
140
+ @click="toggleMenuOpen('textField')"
132
141
  >
133
- <template #activator="{ props }">
134
- <v-text-field
135
- ref="textFieldRef"
136
- v-model="tempTime"
137
- v-bind="$attrs"
138
- @focus="onTextFieldFocus"
139
- @blur="onTextFieldBlur"
140
- @keydown="onTextFieldTyped"
141
- @keyup.enter="onTextFieldEnterKey"
142
- @click:clear="onTextFieldClear"
143
- @click="toggleMenuOpen('textField')"
142
+ <template #append="{ isReadonly, isDisabled }">
143
+ <v-icon
144
+ :disabled="isReadonly.value || isDisabled.value"
145
+ v-bind="props"
146
+ @click="toggleMenuOpen('icon')"
144
147
  >
145
- <template #append-inner>
146
- <v-icon v-if="!isReadonly.value"
147
- v-bind="props"
148
- @click="toggleMenuOpen('icon')"
149
- >
150
- fa:fa-regular fa-clock
151
- </v-icon>
152
- </template>
153
- </v-text-field>
148
+ fa:fa-regular fa-clock
149
+ </v-icon>
154
150
  </template>
155
- <Datepicker
156
- v-model="time"
157
- model-type="HH:mm:ss"
158
- :enable-seconds="enableSeconds"
159
- minutes-grid-increment="1"
160
- time-picker
161
- auto-apply
162
- :close-on-auto-apply="false"
163
- inline
164
- :locale="locale"
165
- @update:model-value="setDatePicker"
166
- />
167
- </v-menu>
151
+ </v-text-field>
168
152
  </template>
169
- </v-input>
170
-
171
- </template>
153
+ <Datepicker
154
+ v-model="time"
155
+ model-type="HH:mm:ss"
156
+ :enable-seconds="enableSeconds"
157
+ minutes-grid-increment="1"
158
+ time-picker
159
+ auto-apply
160
+ :close-on-auto-apply="false"
161
+ inline
162
+ :locale="locale"
163
+ @update:model-value="setDatePicker"
164
+ />
165
+ </v-menu>
166
+ </template>
@@ -7,6 +7,7 @@ interface Props {
7
7
  horizontal?: boolean;
8
8
  size?: 'large' | 'medium';
9
9
  truncate?: boolean;
10
+ notFoundText?: string
10
11
  }
11
12
 
12
13
  const props = withDefaults(defineProps<Props>(), {
@@ -15,6 +16,7 @@ const props = withDefaults(defineProps<Props>(), {
15
16
  horizontal: false,
16
17
  size: 'large',
17
18
  truncate: false,
19
+ notFoundText : '-'
18
20
  });
19
21
 
20
22
  const valueText = ref<HTMLElement | null>(null);
@@ -27,6 +29,9 @@ const setTruncate = (event: Event) => {
27
29
  const target = event.target as HTMLElement;
28
30
  isTooltip.value = target.offsetWidth < target.scrollWidth;
29
31
  };
32
+ const valueData = computed(()=>{
33
+ return (props.value) ? props.value : props.notFoundText
34
+ })
30
35
 
31
36
  </script>
32
37
 
@@ -41,8 +46,8 @@ const setTruncate = (event: Event) => {
41
46
  <slot name="label">{{ props.label }}:</slot>
42
47
  </div>
43
48
  <div :class="`ml-1 ${calTruncate}`" ref="valueText">
44
- <slot name="value">
45
- <div v-if="!props.truncate">{{ props.value }}</div>
49
+ <slot name="value" :value="valueData">
50
+ <div v-if="!props.truncate">{{ valueData }}</div>
46
51
  <div
47
52
  v-else
48
53
  @mouseover="setTruncate"
@@ -54,10 +59,10 @@ const setTruncate = (event: Event) => {
54
59
  class="text-truncate"
55
60
  v-bind="isTooltip ? props : ''"
56
61
  >
57
- {{ value }}
62
+ {{ valueData }}
58
63
  </div>
59
64
  </template>
60
- <span>{{ value }}</span>
65
+ <span>{{ valueData }}</span>
61
66
  </v-tooltip>
62
67
  </div>
63
68
  </slot>
@@ -70,8 +75,8 @@ const setTruncate = (event: Event) => {
70
75
  </VCardSubtitle>
71
76
  <VCardText :class="`pa-0 mb-2 ${calSize}`">
72
77
  <div :class="calTruncate" ref="valueText">
73
- <slot name="value">
74
- <div v-if="!props.truncate">{{ props.value }}</div>
78
+ <slot name="value" :value="valueData">
79
+ <div v-if="!props.truncate">{{ valueData }}</div>
75
80
  <div
76
81
  v-else
77
82
  @mouseover="setTruncate"
@@ -83,10 +88,10 @@ const setTruncate = (event: Event) => {
83
88
  class="text-truncate"
84
89
  v-bind="isTooltip ? props : ''"
85
90
  >
86
- {{ value }}
91
+ {{ valueData }}
87
92
  </div>
88
93
  </template>
89
- <span>{{ value }}</span>
94
+ <span>{{ valueData }}</span>
90
95
  </v-tooltip>
91
96
  </div>
92
97
  </slot>
@@ -43,6 +43,17 @@ watch(selectedItem, (newValue) => {
43
43
  emit('update:modelValue', newValue.itemCode)
44
44
  })
45
45
 
46
+ watch(
47
+ () => props.modelValue,
48
+ (newVal) => {
49
+ if (newVal && items.value.length > 0) {
50
+ const found = items.value.find(item => item.itemCode === newVal)
51
+ if (found) selectedItem.value = found
52
+ }
53
+ },
54
+ { immediate: true }
55
+ )
56
+
46
57
  const itemTitleField = computed(() => {
47
58
  if (props.lang == 'TH') return 'itemValue'
48
59
  else return 'itemValueAlternative'
@@ -9,6 +9,7 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof VSelect['$props']>
9
9
  modelValue?: string
10
10
  groupKey: string
11
11
  fields?: string[]
12
+ lang?: 'TH' | 'EN'
12
13
  }
13
14
  const props = withDefaults(defineProps<Props>(), {
14
15
  lang: 'TH',
@@ -38,9 +39,20 @@ watch(() => props.groupKey, () => {
38
39
  }, { immediate: true })
39
40
 
40
41
  watch(selectedItem, (newValue) => {
41
- emit('update:modelValue', newValue)
42
+ emit('update:modelValue', newValue.itemCode)
42
43
  })
43
44
 
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
+
44
56
  const itemTitleField = computed(() => {
45
57
  if (props.lang == 'TH') return 'itemValue'
46
58
  else return 'itemValueAlternative'
@@ -1,9 +1,10 @@
1
1
  <script lang="ts" setup>
2
+ import {computed} from "vue";
3
+
2
4
  interface Props {
3
5
  groupKey?: string | null
4
6
  itemCode?: string | null
5
7
  locale?: string
6
-
7
8
  notFoundText?: string
8
9
  placeholder?: string
9
10
  }
@@ -1,7 +1,7 @@
1
1
  import { processTemplateFormTable } from "./templateFormTable.js";
2
2
  import { processTemplateFormHidden } from "./templateFormHidden.js";
3
3
  import { some, includes } from "lodash-es";
4
- export const validationRulesRegex = /^(require(?:\([^)]*\))?|requireIf(?:\([^)]*\))?|requireTrue(?:\([^)]*\))?|requireTrueIf(?:\([^)]*\))?|numeric(?:\([^)]*\))?|range(?:\([^)]*\))?|integer(?:\([^)]*\))?|unique(?:\([^)]*\))?|length(?:\([^)]*\))?|lengthGreater(?:\([^)]*\))?|lengthLess(?:\([^)]*\))?|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex(?:\([^)]*\))?)(,(require(?:\([^)]*\))?|requireIf(?:\([^)]*\))?|requireTrue(?:\([^)]*\))?|requireTrueIf(?:\([^)]*\))?|numeric(?:\([^)]*\))?|range(?:\([^)]*\))?|integer(?:\([^)]*\))?|unique(?:\([^)]*\))?|length(?:\([^)]*\))?|lengthGreater(?:\([^)]*\))?|lengthLess(?:\([^)]*\))?|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex(?:\([^)]*\))?))*$/;
4
+ export const validationRulesRegex = /^(require(?:\([^)]*\))?|requireIf\([^)]*\)|requireTrue(?:\([^)]*\))?|requireTrueIf\([^)]*\)|numeric(?:\([^)]*\))?|range\([^)]*\)|integer(?:\([^)]*\))?|unique\([^)]*\)|length(?:\([^)]*\))?|lengthGreater\([^)]*\)|lengthLess\([^)]*\)|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex\([^)]*\)|idcard(?:\([^)]*\))?|DateFuture(?:\([^)]*\))?|DatetimeFuture(?:\([^)]*\))?|DateHappen(?:\([^)]*\))?|DatetimeHappen(?:\([^)]*\))?|DateAfter\([^)]*\)|DateBefore\([^)]*\)|DateEqual\([^)]*\))(,(require(?:\([^)]*\))?|requireIf\([^)]*\)|requireTrue(?:\([^)]*\))?|requireTrueIf\([^)]*\)|numeric(?:\([^)]*\))?|range\([^)]*\)|integer(?:\([^)]*\))?|unique\([^)]*\)|length(?:\([^)]*\))?|lengthGreater\([^)]*\)|lengthLess\([^)]*\)|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex\([^)]*\)|idcard(?:\([^)]*\))?|DateFuture(?:\([^)]*\))?|DatetimeFuture(?:\([^)]*\))?|DateHappen(?:\([^)]*\))?|DatetimeHappen(?:\([^)]*\))?|DateAfter\([^)]*\)|DateBefore\([^)]*\)|DateEqual\([^)]*\)))*$/;
5
5
  export function useDocumentTemplate(items, parentTemplates) {
6
6
  if (!items) return "";
7
7
  if (typeof items === "string") {
@@ -52,7 +52,7 @@ function templateItemToString(item, parentTemplates) {
52
52
  templateString = item.inputCustomCode || "";
53
53
  break;
54
54
  case "VRadio":
55
- templateString = `<v-radio-group v-model="data.${item.variableName || ""}"${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #label>${item.inputLabel}</template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
55
+ templateString = `${item.inputLabel ? `<p class="opacity-60">${item.inputLabel}</p>` : ""} <v-radio-group v-model="data.${item.variableName || ""}"${validationRules ? " " + validationRules.trim() : ""}>${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
56
56
  break;
57
57
  case "VRadioInline":
58
58
  templateString = `<v-radio-group v-model="data.${item.variableName || ""}" inline ${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #prepend><span class="opacity-60">${item.inputLabel}</span></template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
@@ -20,7 +20,7 @@ export function routeToMenuItem(route) {
20
20
  };
21
21
  if (route.children) {
22
22
  const menuItems = new Array();
23
- for (const children of route.children) {
23
+ for (const children of route.children.sort((a, b) => (a.path?.toString() ?? "").localeCompare(b.path?.toString() ?? ""))) {
24
24
  const childMenuItem = routeToMenuItem(children);
25
25
  if (childMenuItem) menuItems.push(childMenuItem);
26
26
  menuItem.menuItems = menuItems;
@@ -31,7 +31,7 @@ export function routeToMenuItem(route) {
31
31
  }
32
32
  export function createMenu() {
33
33
  const menuAll = ref([]);
34
- const routes = useRouter().getRoutes();
34
+ const routes = useRouter().getRoutes().sort((a, b) => (a.path?.toString() ?? "").localeCompare(b.path?.toString() ?? ""));
35
35
  for (const route of routes) {
36
36
  const paths = route.path.split("/");
37
37
  if (paths.length == 2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -115,5 +115,5 @@
115
115
  "vitest": "^1.6.0",
116
116
  "vue-tsc": "2.0.29"
117
117
  },
118
- "packageManager": "pnpm@9.15.5+sha512.845196026aab1cc3f098a0474b64dfbab2afe7a1b4e91dd86895d8e4aa32a7a6d03049e2d0ad770bbe4de023a7122fb68c1a1d6e0d033c7076085f9d5d4800d4"
118
+ "packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531"
119
119
  }