| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | <template> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   <v-card | 
					
						
							|  |  |  |     :color="color" | 
					
						
							|  |  |  |     :dark="dark" | 
					
						
							|  |  |  |     flat | 
					
						
							|  |  |  |     :width="width" | 
					
						
							|  |  |  |     class="my-2" | 
					
						
							|  |  |  |   > | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |     <v-row> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       <v-col | 
					
						
							|  |  |  |         v-for="(inputField, index) in items" | 
					
						
							|  |  |  |         :key="index" | 
					
						
							|  |  |  |         cols="12" | 
					
						
							|  |  |  |         sm="12" | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         <v-divider | 
					
						
							|  |  |  |           v-if="inputField.section" | 
					
						
							|  |  |  |           class="my-2" | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |         <v-card-title | 
					
						
							|  |  |  |           v-if="inputField.section" | 
					
						
							|  |  |  |           class="pl-0" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           {{ inputField.section }} | 
					
						
							|  |  |  |         </v-card-title> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <v-card-text | 
					
						
							|  |  |  |           v-if="inputField.sectionDetails" | 
					
						
							|  |  |  |           class="pl-0 mt-0 pt-0" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           {{ inputField.sectionDetails }} | 
					
						
							|  |  |  |         </v-card-text> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <!-- Check Box --> | 
					
						
							|  |  |  |         <v-checkbox | 
					
						
							|  |  |  |           v-if="inputField.type === fieldTypes.BOOLEAN" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           v-model="modelValue[inputField.varName]" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           :name="inputField.varName" | 
					
						
							| 
									
										
										
										
											2023-09-29 18:58:34 -05:00
										 |  |  |           :disabled="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (disabledFields && disabledFields.includes(inputField.varName))" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           :hint="inputField.hint" | 
					
						
							| 
									
										
										
										
											2025-08-14 06:24:21 -05:00
										 |  |  |           :hide-details="!inputField.hint" | 
					
						
							|  |  |  |           :persistent-hint="!!inputField.hint" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           density="comfortable" | 
					
						
							|  |  |  |           @change="emitBlur"> | 
					
						
							| 
									
										
										
										
											2024-03-11 08:28:54 -05:00
										 |  |  |           <template #label> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <span class="ml-4"> | 
					
						
							|  |  |  |               {{ inputField.label }} | 
					
						
							|  |  |  |             </span> | 
					
						
							| 
									
										
										
										
											2025-08-14 06:24:21 -05:00
										 |  |  |           </template> | 
					
						
							|  |  |  |         </v-checkbox> | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         <!-- Text Field --> | 
					
						
							|  |  |  |         <v-text-field | 
					
						
							| 
									
										
										
										
											2021-11-23 18:57:24 -09:00
										 |  |  |           v-else-if="inputField.type === fieldTypes.TEXT || inputField.type === fieldTypes.PASSWORD" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           v-model="modelValue[inputField.varName]" | 
					
						
							| 
									
										
										
										
											2023-09-29 18:58:34 -05:00
										 |  |  |           :readonly="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (readonlyFields && readonlyFields.includes(inputField.varName))" | 
					
						
							|  |  |  |           :disabled="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (disabledFields && disabledFields.includes(inputField.varName))" | 
					
						
							| 
									
										
										
										
											2021-11-23 18:57:24 -09:00
										 |  |  |           :type="inputField.type === fieldTypes.PASSWORD ? 'password' : 'text'" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           variant="solo-filled" | 
					
						
							|  |  |  |           flat | 
					
						
							| 
									
										
										
										
											2021-11-25 14:17:02 -09:00
										 |  |  |           :autofocus="index === 0" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           density="comfortable" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           :label="inputField.label" | 
					
						
							|  |  |  |           :name="inputField.varName" | 
					
						
							|  |  |  |           :hint="inputField.hint || ''" | 
					
						
							| 
									
										
										
										
											2021-11-23 18:57:24 -09:00
										 |  |  |           :rules="!(inputField.disableUpdate && updateMode) ? [...rulesByKey(inputField.rules), ...defaultRules] : []" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           lazy-validation | 
					
						
							|  |  |  |           @blur="emitBlur" | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <!-- Text Area --> | 
					
						
							|  |  |  |         <v-textarea | 
					
						
							|  |  |  |           v-else-if="inputField.type === fieldTypes.TEXT_AREA" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           v-model="modelValue[inputField.varName]" | 
					
						
							| 
									
										
										
										
											2023-09-29 18:58:34 -05:00
										 |  |  |           :readonly="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (readonlyFields && readonlyFields.includes(inputField.varName))" | 
					
						
							|  |  |  |           :disabled="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (disabledFields && disabledFields.includes(inputField.varName))" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           variant="solo-filled" | 
					
						
							|  |  |  |           flat | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           rows="3" | 
					
						
							|  |  |  |           auto-grow | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           density="comfortable" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           :label="inputField.label" | 
					
						
							|  |  |  |           :name="inputField.varName" | 
					
						
							|  |  |  |           :hint="inputField.hint || ''" | 
					
						
							|  |  |  |           :rules="[...rulesByKey(inputField.rules), ...defaultRules]" | 
					
						
							|  |  |  |           lazy-validation | 
					
						
							|  |  |  |           @blur="emitBlur" | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <!-- Option Select --> | 
					
						
							|  |  |  |         <v-select | 
					
						
							|  |  |  |           v-else-if="inputField.type === fieldTypes.SELECT" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           v-model="modelValue[inputField.varName]" | 
					
						
							| 
									
										
										
										
											2023-09-29 18:58:34 -05:00
										 |  |  |           :readonly="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (readonlyFields && readonlyFields.includes(inputField.varName))" | 
					
						
							|  |  |  |           :disabled="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (disabledFields && disabledFields.includes(inputField.varName))" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           variant="solo-filled" | 
					
						
							|  |  |  |           flat | 
					
						
							|  |  |  |           :prepend-icon="inputField.icons ? modelValue[inputField.varName] : null" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           :label="inputField.label" | 
					
						
							|  |  |  |           :name="inputField.varName" | 
					
						
							|  |  |  |           :items="inputField.options" | 
					
						
							| 
									
										
										
										
											2025-08-14 06:24:21 -05:00
										 |  |  |           item-title="text" | 
					
						
							|  |  |  |           item-value="text" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           :return-object="false" | 
					
						
							| 
									
										
										
										
											2023-02-26 13:12:16 -06:00
										 |  |  |           :hint="inputField.hint" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           density="comfortable" | 
					
						
							| 
									
										
										
										
											2023-02-26 13:12:16 -06:00
										 |  |  |           persistent-hint | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           lazy-validation | 
					
						
							|  |  |  |           @blur="emitBlur" | 
					
						
							| 
									
										
										
										
											2025-08-25 02:19:46 -05:00
										 |  |  |         /> | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         <!-- Color Picker --> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <div | 
					
						
							|  |  |  |           v-else-if="inputField.type === fieldTypes.COLOR" | 
					
						
							|  |  |  |           class="d-flex" | 
					
						
							|  |  |  |           style="width: 100%" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           <v-menu offset-y> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <template #activator="{ props: templateProps }"> | 
					
						
							|  |  |  |               <v-btn | 
					
						
							|  |  |  |                 class="my-2 ml-auto" | 
					
						
							|  |  |  |                 style="min-width: 200px" | 
					
						
							|  |  |  |                 :color="modelValue[inputField.varName]" | 
					
						
							|  |  |  |                 dark | 
					
						
							|  |  |  |                 v-bind="templateProps" | 
					
						
							|  |  |  |               > | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |                 {{ inputField.label }} | 
					
						
							|  |  |  |               </v-btn> | 
					
						
							|  |  |  |             </template> | 
					
						
							|  |  |  |             <v-color-picker | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |               v-model="modelValue[inputField.varName]" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |               value="#7417BE" | 
					
						
							|  |  |  |               hide-canvas | 
					
						
							|  |  |  |               hide-inputs | 
					
						
							|  |  |  |               show-swatches | 
					
						
							|  |  |  |               class="mx-auto" | 
					
						
							|  |  |  |               @input="emitBlur" | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           </v-menu> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <div v-else-if="inputField.type === fieldTypes.OBJECT"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           <auto-form | 
					
						
							|  |  |  |             v-model="modelValue[inputField.varName]" | 
					
						
							|  |  |  |             :color="color" | 
					
						
							|  |  |  |             :items="inputField.items" | 
					
						
							|  |  |  |             @blur="emitBlur" | 
					
						
							|  |  |  |           /> | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |         </div> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <!-- List Type --> | 
					
						
							|  |  |  |         <div v-else-if="inputField.type === fieldTypes.LIST"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           <div | 
					
						
							|  |  |  |             v-for="(item, idx) in modelValue[inputField.varName]" | 
					
						
							|  |  |  |             :key="idx" | 
					
						
							|  |  |  |           > | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |             <p> | 
					
						
							|  |  |  |               {{ inputField.label }} {{ idx + 1 }} | 
					
						
							|  |  |  |               <span> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |                 <BaseButton | 
					
						
							|  |  |  |                   class="ml-5" | 
					
						
							|  |  |  |                   x-small | 
					
						
							|  |  |  |                   delete | 
					
						
							|  |  |  |                   @click="removeByIndex(modelValue[inputField.varName], idx)" | 
					
						
							|  |  |  |                 /> | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |               </span> | 
					
						
							|  |  |  |             </p> | 
					
						
							|  |  |  |             <v-divider class="mb-5 mx-2" /> | 
					
						
							|  |  |  |             <auto-form | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |               v-model="modelValue[inputField.varName][idx]" | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |               :color="color" | 
					
						
							|  |  |  |               :items="inputField.items" | 
					
						
							|  |  |  |               @blur="emitBlur" | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |           <v-card-actions> | 
					
						
							|  |  |  |             <v-spacer /> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <BaseButton | 
					
						
							|  |  |  |               small | 
					
						
							|  |  |  |               @click="modelValue[inputField.varName].push(getTemplate(inputField.items))" | 
					
						
							|  |  |  |             > | 
					
						
							| 
									
										
										
										
											2022-08-15 23:55:51 +02:00
										 |  |  |               {{ $t("general.new") }} | 
					
						
							|  |  |  |             </BaseButton> | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |           </v-card-actions> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       </v-col> | 
					
						
							|  |  |  |     </v-row> | 
					
						
							|  |  |  |   </v-card> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | <script lang="ts" setup> | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | import { validators } from "@/composables/use-validators"; | 
					
						
							|  |  |  | import { fieldTypes } from "@/composables/forms"; | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | import type { AutoFormItems } from "~/types/auto-forms"; | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const BLUR_EVENT = "blur"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-25 09:38:21 -08:00
										 |  |  | type ValidatorKey = keyof typeof validators; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | // Use defineModel for v-model
 | 
					
						
							|  |  |  | const modelValue = defineModel<[object, Array<any>]>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const props = defineProps({ | 
					
						
							|  |  |  |   updateMode: { | 
					
						
							|  |  |  |     default: false, | 
					
						
							|  |  |  |     type: Boolean, | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  |   }, | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   items: { | 
					
						
							|  |  |  |     default: null, | 
					
						
							|  |  |  |     type: Array as () => AutoFormItems, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   width: { | 
					
						
							|  |  |  |     type: [Number, String], | 
					
						
							|  |  |  |     default: "max", | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   globalRules: { | 
					
						
							|  |  |  |     default: null, | 
					
						
							|  |  |  |     type: Array as () => string[], | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   color: { | 
					
						
							|  |  |  |     default: null, | 
					
						
							|  |  |  |     type: String, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   dark: { | 
					
						
							|  |  |  |     default: false, | 
					
						
							|  |  |  |     type: Boolean, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   disabledFields: { | 
					
						
							|  |  |  |     default: null, | 
					
						
							|  |  |  |     type: Array as () => string[], | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   readonlyFields: { | 
					
						
							|  |  |  |     default: null, | 
					
						
							|  |  |  |     type: Array as () => string[], | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | const emit = defineEmits(["blur", "update:modelValue"]); | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | function rulesByKey(keys?: ValidatorKey[] | null) { | 
					
						
							|  |  |  |   if (keys === undefined || keys === null) { | 
					
						
							|  |  |  |     return []; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   const list = [] as ((v: string) => boolean | string)[]; | 
					
						
							|  |  |  |   keys.forEach((key) => { | 
					
						
							|  |  |  |     const split = key.split(":"); | 
					
						
							|  |  |  |     const validatorKey = split[0] as ValidatorKey; | 
					
						
							|  |  |  |     if (validatorKey in validators) { | 
					
						
							|  |  |  |       if (split.length === 1) { | 
					
						
							|  |  |  |         list.push(validators[validatorKey]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         list.push(validators[validatorKey](split[1])); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   return list; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | const defaultRules = computed(() => rulesByKey(props.globalRules as ValidatorKey[])); | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | function removeByIndex(list: never[], index: number) { | 
					
						
							|  |  |  |   // Removes the item at the index
 | 
					
						
							|  |  |  |   list.splice(index, 1); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | function getTemplate(item: AutoFormItems) { | 
					
						
							|  |  |  |   const obj = {} as { [key: string]: string }; | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   item.forEach((field) => { | 
					
						
							|  |  |  |     obj[field.varName] = ""; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   return obj; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function emitBlur() { | 
					
						
							|  |  |  |   emit(BLUR_EVENT, modelValue.value); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-08-01 19:24:47 -08:00
										 |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style lang="scss" scoped></style> |