@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 +1 -1
- package/dist/runtime/components/document/TemplateBuilder.vue +38 -7
- package/dist/runtime/components/form/CheckboxGroup.vue +90 -0
- package/dist/runtime/components/form/Date.vue +44 -37
- package/dist/runtime/components/form/DateTime.vue +40 -34
- package/dist/runtime/components/form/Hidden.vue +2 -2
- package/dist/runtime/components/form/Time.vue +42 -36
- package/dist/runtime/composables/document/template.js +13 -5
- package/package.json +2 -2
package/dist/module.json
CHANGED
|
@@ -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="
|
|
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-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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 #
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
<
|
|
168
|
-
v-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
v-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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 #
|
|
143
|
-
<v-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
118
|
+
"packageManager": "pnpm@9.15.5+sha512.845196026aab1cc3f098a0474b64dfbab2afe7a1b4e91dd86895d8e4aa32a7a6d03049e2d0ad770bbe4de023a7122fb68c1a1d6e0d033c7076085f9d5d4800d4"
|
|
119
119
|
}
|