ptitlutins/app/components/molecules/Form.vue
2025-09-15 23:03:42 +02:00

113 lines
No EOL
2.2 KiB
Vue

<template>
<form @submit.prevent="handleSubmit" class="form-container">
<div v-for="(field, index) in fields" :key="index" class="form-field">
<Input
:id="field.id"
:label="field.label"
:type="field.type"
v-model="formData[field.id]"
:error="errors[field.id]"
@blur="validateField(field.id)"
v-bind="field.attrs"
/>
</div>
<slot name="submit">
<button v-if="showSubmit" type="submit" class="submit-button">Submit</button>
</slot>
</form>
</template>
<script setup>
const props = defineProps({
fields: {
type: Array,
required: true,
validator: (value) => {
return value.every(field => field.id && field.label)
}
},
showSubmit: {
type: Boolean,
default: true
},
validationRules: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['submit'])
const formData = reactive({})
const errors = reactive({})
props.fields.forEach(field => {
formData[field.id] = field.defaultValue || ''
errors[field.id] = ''
})
const validateField = (fieldId) => {
const rules = props.validationRules[fieldId]
if (!rules) return
const value = formData[fieldId]
errors[fieldId] = ''
if (rules.required && !value) {
errors[fieldId] = 'This field is required'
return
}
if (rules.minLength && value.length < rules.minLength) {
errors[fieldId] = `Minimum ${rules.minLength} characters required`
return
}
if (rules.pattern && !new RegExp(rules.pattern).test(value)) {
errors[fieldId] = rules.patternMessage || 'Invalid format'
}
}
const validateAllFields = () => {
let isValid = true
props.fields.forEach(field => {
validateField(field.id)
if (errors[field.id]) isValid = false
})
return isValid
}
const handleSubmit = () => {
if (validateAllFields()) {
emit('submit', formData)
}
}
</script>
<style scoped>
.form-container {
display: flex;
flex-direction: column;
gap: 1rem;
}
.form-field {
margin-bottom: 1rem;
}
.submit-button {
padding: 0.75rem 1.5rem;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
align-self: flex-start;
}
.submit-button:hover {
background-color: #3aa876;
}
</style>