@ramathibodi/nuxt-commons 0.1.42 → 0.1.44

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.42",
7
+ "version": "0.1.44",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.3",
10
10
  "unbuild": "2.0.0"
@@ -138,6 +138,7 @@ const inputTypeChoice = ref([
138
138
  { label: 'Radio Buttons', value: 'VRadio' },
139
139
  { label: 'Radio Buttons Inline', value: 'VRadioInline' },
140
140
  { label: 'Checkbox', value: 'VCheckbox' },
141
+ { label: 'Checkbox Group', value: 'FormCheckboxGroup' },
141
142
  { label: 'Switch', value: 'VSwitch' },
142
143
  { label: 'File Upload', value: 'FormFile' },
143
144
  { label: 'Signature Pad', value: 'FormSignPad' },
@@ -149,7 +150,7 @@ const inputTypeChoice = ref([
149
150
  { label: '[Advanced] Custom Code', value: 'CustomCode' },
150
151
  ]);
151
152
 
152
- const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','DocumentForm'])
153
+ const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','DocumentForm','FormCheckboxGroup'])
153
154
  const notRequireVariable = ref(['Header', 'Separator', 'CustomCode','DocumentForm'])
154
155
  const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormHidden','DocumentForm'])
155
156
  const notRequireWidth = ref(['Separator', 'FormHidden','DocumentForm'])
@@ -161,7 +162,7 @@ const notRequireAdvancedSetting = ref(['Separator','CustomCode', 'FormHidden'])
161
162
 
162
163
  const hasSpecificOption = ref(['FormHidden','FormTable'])
163
164
 
164
- const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox'])
165
+ const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox','FormCheckboxGroup'])
165
166
  const inputOptionsLabel = ref<Record<string,string>>({
166
167
  'MasterAutocomplete' : "Group Key",
167
168
  'Header' : "Class",
@@ -0,0 +1,92 @@
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 = withDefaults(defineProps<Props>(),{
17
+ inline:false
18
+ })
19
+ const emit = defineEmits(['update:modelValue'])
20
+ const values = ref([])
21
+ const valuesOther = ref()
22
+
23
+ const computedRules = computed(() => {
24
+ if (props.rules){
25
+ let rules = props.rules.map((rule : any) => rule(values.value.length ? values.value : null))
26
+ rules = without(rules,true)
27
+ return join(rules,',')
28
+ }
29
+ })
30
+ const computedOther = computed(() => {
31
+ const itemOther = filter(props.items,{value:'other'})
32
+ return head(itemOther)
33
+ })
34
+
35
+ const computeItems = computed(() => {
36
+ return reject(props.items , {value:'other'})
37
+ })
38
+
39
+ watch(values, () => {
40
+ emit('update:modelValue', [...values.value, valuesOther.value].filter(Boolean))
41
+ }, {deep: true});
42
+
43
+ watch(valuesOther, () => {
44
+ emit('update:modelValue', [...values.value, valuesOther.value].filter(Boolean))
45
+ })
46
+
47
+ watch(props.modelValue, () => {
48
+ if (!props.modelValue) {
49
+ values.value = []
50
+ valuesOther.value = ''
51
+ } else {
52
+ // Separate regular values and the "other" value if applicable
53
+ if (Array.isArray(props.modelValue)) {
54
+ valuesOther.value = props.modelValue.find(item => !props.items.some(({ value }) => value === item)) || ''
55
+ values.value = props.modelValue.filter(item => item !== valuesOther.value)
56
+ }
57
+ }
58
+ }, { deep: true, immediate: true })
59
+ </script>
60
+
61
+ <template>
62
+ <v-container fluid>
63
+ <label class="text-body-1 opacity-60">{{props.label}}</label>
64
+ <div :class="`d-flex ${inline ? 'flex-row':'flex-column'}`">
65
+ <v-checkbox v-for="item in computeItems"
66
+ :value="item.value"
67
+ v-model="values"
68
+ density="compact"
69
+ hide-details
70
+ :error = "!!computedRules"
71
+ :="$attrs"
72
+ :label="item.label">
73
+ </v-checkbox>
74
+ </div>
75
+ <v-text-field hide-details
76
+ :error = "!!computedRules"
77
+ v-if="computedOther"
78
+ v-model="valuesOther"
79
+ :="$attrs"
80
+ :label="computedOther.label">
81
+
82
+ </v-text-field>
83
+ <label class="text-error text-subtitle-2 ml-1">
84
+ {{computedRules}}
85
+ </label>
86
+ </v-container>
87
+
88
+ </template>
89
+
90
+ <style scoped>
91
+
92
+ </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>
@@ -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("");
@@ -117,5 +122,7 @@ export function buildValidationRules(validationString) {
117
122
  }
118
123
  export function processDefaultTemplate(item, insideTemplate, optionString, validationRules) {
119
124
  if (!validationRules) validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
120
- 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}>`;
121
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
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
  }