@ramathibodi/nuxt-commons 0.1.41 → 0.1.43

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.41",
7
+ "version": "0.1.43",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.3",
10
10
  "unbuild": "2.0.0"
@@ -3,6 +3,7 @@ import {computed, ref, watch} from 'vue'
3
3
  import * as prettier from 'prettier'
4
4
  import prettierPluginHtml from 'prettier/plugins/html'
5
5
  import {useDocumentTemplate, validationRulesRegex,optionStringToChoiceObject} from '../../composables/document/template'
6
+ import {cloneDeep} from "lodash-es";
6
7
 
7
8
  interface Props {
8
9
  title?: string
@@ -13,10 +14,11 @@ const props = withDefaults(defineProps<Props>(), {
13
14
  })
14
15
 
15
16
  const emit = defineEmits(['update:modelValue'])
16
- const modelValue = defineModel<string>()
17
+ const modelValue = defineModel<string|Record<string, any>[]>()
17
18
 
19
+ const advanceModeCode = ref<string>()
18
20
  const isAdvanceMode = computed(() => {
19
- return modelValue.value && !isValidJsonArrayOfObjects(modelValue.value)
21
+ return modelValue.value && ((typeof modelValue.value === "string") && !isValidJsonArrayOfObjects(modelValue.value))
20
22
  })
21
23
 
22
24
  const templateItems = ref<Record<string, any>[]>([])
@@ -70,6 +72,11 @@ const formTableHeaders = ref([
70
72
  title: 'Width',
71
73
  key: 'width',
72
74
  },
75
+ {
76
+ title: 'Action',
77
+ key: 'action',
78
+ width: '120px',
79
+ },
73
80
  ])
74
81
 
75
82
  const choiceHeaders = ref([
@@ -81,6 +88,11 @@ const choiceHeaders = ref([
81
88
  title: 'Value',
82
89
  key: 'value',
83
90
  },
91
+ {
92
+ title: 'Action',
93
+ key: 'action',
94
+ width: '120px',
95
+ },
84
96
  ])
85
97
 
86
98
 
@@ -99,9 +111,15 @@ watch(templateItems, (newValue) => {
99
111
  }, { deep: true })
100
112
 
101
113
  watch(modelValue, (newValue) => {
102
- if (isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue as string)
114
+ if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue as string)
115
+ else if (typeof newValue === "string") advanceModeCode.value = newValue
116
+ else if (newValue) templateItems.value = cloneDeep(newValue)
103
117
  }, { deep: true, immediate: true })
104
118
 
119
+ watch(advanceModeCode, (newValue)=>{
120
+ if (isAdvanceMode.value) modelValue.value = newValue
121
+ })
122
+
105
123
  async function convertToAdvanceMode() {
106
124
  if (!isAdvanceMode.value) {
107
125
  modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll('>', '>\n'), { parser: 'html', plugins: [prettierPluginHtml] })
@@ -120,6 +138,7 @@ const inputTypeChoice = ref([
120
138
  { label: 'Radio Buttons', value: 'VRadio' },
121
139
  { label: 'Radio Buttons Inline', value: 'VRadioInline' },
122
140
  { label: 'Checkbox', value: 'VCheckbox' },
141
+ { label: 'Checkbox Group', value: 'FormCheckboxGroup' },
123
142
  { label: 'Switch', value: 'VSwitch' },
124
143
  { label: 'File Upload', value: 'FormFile' },
125
144
  { label: 'Signature Pad', value: 'FormSignPad' },
@@ -131,7 +150,7 @@ const inputTypeChoice = ref([
131
150
  { label: '[Advanced] Custom Code', value: 'CustomCode' },
132
151
  ]);
133
152
 
134
- const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','DocumentForm'])
153
+ const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','DocumentForm','FormCheckboxGroup'])
135
154
  const notRequireVariable = ref(['Header', 'Separator', 'CustomCode','DocumentForm'])
136
155
  const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormHidden','DocumentForm'])
137
156
  const notRequireWidth = ref(['Separator', 'FormHidden','DocumentForm'])
@@ -143,7 +162,7 @@ const notRequireAdvancedSetting = ref(['Separator','CustomCode', 'FormHidden'])
143
162
 
144
163
  const hasSpecificOption = ref(['FormHidden','FormTable'])
145
164
 
146
- const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox'])
165
+ const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox','FormCheckboxGroup'])
147
166
  const inputOptionsLabel = ref<Record<string,string>>({
148
167
  'MasterAutocomplete' : "Group Key",
149
168
  'Header' : "Class",
@@ -197,7 +216,7 @@ const ruleOptions = (inputType: string) => (value: any) => {
197
216
  :rules="[rules.require()]"
198
217
  type="number"
199
218
  />
200
- <form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="()=>undefined"></form-hidden>
219
+ <form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="(_result: any,model: any,newValue: any,oldValue: any)=>{return (newValue && oldValue) ? undefined : model}"></form-hidden>
201
220
  </v-col>
202
221
  <v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
203
222
  <v-text-field
@@ -367,10 +386,22 @@ const ruleOptions = (inputType: string) => (value: any) => {
367
386
  <template v-if="props.item.inputAttributes">
368
387
  <b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
369
388
  </template>
389
+ <template v-if="props.item.columnAttributes">
390
+ <b>Column Attributes :</b> {{ props.item.columnAttributes }}<br>
391
+ </template>
392
+ <template v-if="props.item.conditionalDisplay">
393
+ <b>Conditional Display :</b> {{ props.item.conditionalDisplay }}<br>
394
+ </template>
395
+ <template v-if="props.item.computedValue">
396
+ <b>Computed Value :</b> {{ props.item.computedValue }}<br>
397
+ </template>
398
+ <template v-if="props.item.retrievedValue">
399
+ <b>Retrieved Value :</b> {{ props.item.retrievedValue }}<br>
400
+ </template>
370
401
  </template>
371
402
  </FormTable>
372
403
  <FormCodeEditor
373
404
  v-else
374
- v-model="modelValue"
405
+ v-model="advanceModeCode"
375
406
  />
376
407
  </template>
@@ -0,0 +1,90 @@
1
+ <script setup lang="ts">
2
+ import { ref, watch, computed} from 'vue'
3
+ import { VCheckbox } from 'vuetify/components/VCheckbox'
4
+ import { join,without,filter,head,reject } from 'lodash-es'
5
+ interface Items {
6
+ label : string
7
+ value : any
8
+ }
9
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VCheckbox['$props']>{
10
+ items : Items[]
11
+ label? : string
12
+ modelValue : []
13
+ inline? : boolean
14
+ rules?: typeof import('vuetify/components')['VCheckbox']['rules']
15
+ }
16
+ const props =defineProps<Props>()
17
+ const emit = defineEmits(['update:modelValue'])
18
+ const values = ref([])
19
+ const valuesOther = ref()
20
+
21
+ const computedRules = computed(() => {
22
+ if (props.rules){
23
+ let rules = props.rules.map((rule : any) => rule(values.value.length ? values.value : null))
24
+ rules = without(rules,true)
25
+ return join(rules,',')
26
+ }
27
+ })
28
+ const computedOther = computed(() => {
29
+ const itemOther = filter(props.items,{value:'other'})
30
+ return head(itemOther)
31
+ })
32
+
33
+ const computeItems = computed(() => {
34
+ return reject(props.items , {value:'other'})
35
+ })
36
+
37
+ watch(values, () => {
38
+ emit('update:modelValue', [...values.value, valuesOther.value].filter(Boolean))
39
+ }, {deep: true});
40
+
41
+ watch(valuesOther, () => {
42
+ emit('update:modelValue', [...values.value, valuesOther.value].filter(Boolean))
43
+ })
44
+
45
+ watch(props.modelValue, () => {
46
+ if (!props.modelValue) {
47
+ values.value = []
48
+ valuesOther.value = ''
49
+ } else {
50
+ // Separate regular values and the "other" value if applicable
51
+ if (Array.isArray(props.modelValue)) {
52
+ valuesOther.value = props.modelValue.find(item => !props.items.some(({ value }) => value === item)) || ''
53
+ values.value = props.modelValue.filter(item => item !== valuesOther.value)
54
+ }
55
+ }
56
+ }, { deep: true, immediate: true })
57
+ </script>
58
+
59
+ <template>
60
+ <v-container fluid>
61
+ <label class="text-body-1 opacity-60">{{props.label}}</label>
62
+ <div :class="`d-flex ${inline ? 'flex-row':'flex-column'}`">
63
+ <v-checkbox v-for="item in computeItems"
64
+ :value="item.value"
65
+ v-model="values"
66
+ density="compact"
67
+ hide-details
68
+ :error = "!!computedRules"
69
+ :="$attrs"
70
+ :label="item.label">
71
+ </v-checkbox>
72
+ </div>
73
+ <v-text-field hide-details
74
+ :error = "!!computedRules"
75
+ v-if="computedOther"
76
+ v-model="valuesOther"
77
+ :="$attrs"
78
+ :label="computedOther.label">
79
+
80
+ </v-text-field>
81
+ <label class="text-error text-subtitle-2 ml-1">
82
+ {{computedRules}}
83
+ </label>
84
+ </v-container>
85
+
86
+ </template>
87
+
88
+ <style scoped>
89
+
90
+ </style>
@@ -6,6 +6,7 @@ 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";
9
10
 
10
11
  interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
11
12
  locale?: 'TH' | 'EN'
@@ -179,44 +180,50 @@ defineExpose({
179
180
  </script>
180
181
 
181
182
  <template>
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')"
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"
198
188
  >
199
- <template #append-inner>
200
- <v-icon
201
- v-bind="activatorProps"
202
- @click="toggleMenuOpen('icon')"
203
- >
204
- fa:fa-regular fa-calendar
205
- </v-icon>
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>
206
211
  </template>
207
- </v-text-field>
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
225
  </template>
209
- <Datepicker
210
- v-model="selectedDate"
211
- model-type="yyyy-MM-dd"
212
- :enable-time-picker="false"
213
- :flow="flow"
214
- :min-date="props.minDate"
215
- :max-date="props.maxDate"
216
- auto-apply
217
- inline
218
- :locale="locale"
219
- @update:model-value="updateDatePicker"
220
- />
221
- </v-menu>
226
+
227
+ </v-input>
228
+
222
229
  </template>
@@ -4,6 +4,7 @@ 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";
7
8
 
8
9
  interface Props {
9
10
  modelValue?: string | null
@@ -158,38 +159,43 @@ watch(() => props.modelValue, () => {
158
159
  </script>
159
160
 
160
161
  <template>
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>
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
+
195
201
  </template>
@@ -11,10 +11,10 @@ interface Props {
11
11
  const props = defineProps<Props>()
12
12
  const emit = defineEmits(['update:modelValue'])
13
13
 
14
- watch(() => props.itemValue, (newValue) => {
14
+ watch(() => props.itemValue, (newValue,oldValue) => {
15
15
  const resultValue = cloneDeep(newValue)
16
16
  if (props.hook) {
17
- Promise.resolve(props.hook(resultValue, props.modelValue)).then((result) => {
17
+ Promise.resolve(props.hook(resultValue, props.modelValue,newValue,oldValue)).then((result) => {
18
18
  emit('update:modelValue', result)
19
19
  }).catch(e => void e)
20
20
  }
@@ -4,6 +4,7 @@ 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";
7
8
 
8
9
  interface Props extends /* @vue-ignore */ InstanceType<typeof VTextField['$props']> {
9
10
  enableSeconds?: boolean
@@ -122,44 +123,49 @@ defineExpose({
122
123
  </script>
123
124
 
124
125
  <template>
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')"
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"
141
132
  >
142
- <template #append-inner>
143
- <v-icon
144
- v-bind="props"
145
- @click="toggleMenuOpen('icon')"
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')"
146
144
  >
147
- fa:fa-regular fa-clock
148
- </v-icon>
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>
149
154
  </template>
150
- </v-text-field>
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
168
  </template>
152
- <Datepicker
153
- v-model="time"
154
- model-type="HH:mm:ss"
155
- :enable-seconds="enableSeconds"
156
- minutes-grid-increment="1"
157
- time-picker
158
- auto-apply
159
- :close-on-auto-apply="false"
160
- inline
161
- :locale="locale"
162
- @update:model-value="setDatePicker"
163
- />
164
- </v-menu>
169
+ </v-input>
170
+
165
171
  </template>
@@ -1,5 +1,6 @@
1
1
  import { processTemplateFormTable } from "./templateFormTable.js";
2
2
  import { processTemplateFormHidden } from "./templateFormHidden.js";
3
+ import { some, includes } from "lodash-es";
3
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
5
  export function useDocumentTemplate(items, parentTemplates) {
5
6
  if (!items) return "";
@@ -26,6 +27,10 @@ function templateItemToString(item, parentTemplates) {
26
27
  const choice = optionStringToChoiceObject(item.inputOptions);
27
28
  optionString = `item-value="value" item-title="label" :items='${escapeObjectForInlineBinding(choice)}' `;
28
29
  }
30
+ if (["FormCheckboxGroup"].includes(item.inputType)) {
31
+ const choice = optionStringToChoiceObject(item.inputOptions);
32
+ optionString = ` :items='${escapeObjectForInlineBinding(choice)}'`;
33
+ }
29
34
  if (["VRadio", "VRadioInline"].includes(item.inputType)) {
30
35
  const choice = optionStringToChoiceObject(item.inputOptions);
31
36
  optionString = choice.map((choiceItem) => `<v-radio label="${choiceItem.label || ""}" value="${choiceItem.value || ""}" ${item.inputAttributes ? " " + item.inputAttributes : ""}></v-radio>`).join("");
@@ -41,15 +46,16 @@ function templateItemToString(item, parentTemplates) {
41
46
  item.inputAttributes = `${item.inputAttributes?.trim() || ""} dense`.trim();
42
47
  }
43
48
  let templateString;
49
+ const validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
44
50
  switch (item.inputType) {
45
51
  case "CustomCode":
46
52
  templateString = item.inputCustomCode || "";
47
53
  break;
48
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>`;
56
+ break;
49
57
  case "VRadioInline":
50
- const inlineAttr = item.inputType === "VRadioInline" ? " inline" : "";
51
- const validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
52
- templateString = `<v-radio-group v-model="data.${item.variableName || ""}"${inlineAttr}${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #prepend>${item.inputLabel}</template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
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>`;
53
59
  break;
54
60
  case "Separator":
55
61
  templateString = "</v-row><v-row dense>";
@@ -65,7 +71,7 @@ function templateItemToString(item, parentTemplates) {
65
71
  break;
66
72
  case "DocumentForm":
67
73
  const parentTemplatesString = typeof parentTemplates === "string" ? parentTemplates : parentTemplates.join("|");
68
- templateString = `<document-form v-model="data" templateCode="${item.inputOptions || ""}" parent-templates="${parentTemplatesString}"></document-form>`;
74
+ templateString = `<document-form :model-value="data" templateCode="${item.inputOptions || ""}" parent-templates="${parentTemplatesString}"></document-form>`;
69
75
  break;
70
76
  default:
71
77
  templateString = processDefaultTemplate(item, void 0, optionString);
@@ -116,5 +122,7 @@ export function buildValidationRules(validationString) {
116
122
  }
117
123
  export function processDefaultTemplate(item, insideTemplate, optionString, validationRules) {
118
124
  if (!validationRules) validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
119
- return `<${item.inputType} v-model="data.${item.variableName || ""}" label="${item.inputLabel || item.variableName || ""}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}>${insideTemplate || ""}</${item.inputType}>`;
125
+ const hasVariant = some([item.inputAttributes], (str) => includes(str, "variant"));
126
+ const defaultAttributes = `${!hasVariant ? `variant="underlined"` : ""} :active=isReadonly`;
127
+ return `<${item.inputType} ${defaultAttributes} v-model="data.${item.variableName || ""}" label="${item.inputLabel || item.variableName || ""}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}>${insideTemplate || ""}</${item.inputType}>`;
120
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
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.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
118
+ "packageManager": "pnpm@9.15.5+sha512.845196026aab1cc3f098a0474b64dfbab2afe7a1b4e91dd86895d8e4aa32a7a6d03049e2d0ad770bbe4de023a7122fb68c1a1d6e0d033c7076085f9d5d4800d4"
119
119
  }