vue-yup-wrapper-reactive
Version:
Vue 3 composable plugin that integrates Yup validation with Vue reactive system for easy and type-safe form validation
283 lines (227 loc) • 7.65 kB
Markdown
# Vue Yup Wrapper Reactive
Plugin Vue 3 composable yang mengintegrasikan validasi Yup dengan sistem reaktif Vue untuk manajemen form yang mudah dan type-safe.
## Fitur
- ✅ **Vue 3 Composition API** - Menggunakan composable pattern
- ✅ **TypeScript Support** - Full type safety
- ✅ **Yup Integration** - Validasi schema yang powerful
- ✅ **Reactive State** - State management otomatis dengan Vue reactivity
- ✅ **Custom Field Labels** - Pemetaan label field untuk internationalization
- ✅ **Error Handling** - Penanganan error yang komprehensif
- ✅ **Reset Functionality** - Reset form ke nilai awal
## Instalasi
```bash
npm install vue-yup-wrapper-reactive
# atau
yarn add vue-yup-wrapper-reactive
# atau
pnpm add vue-yup-wrapper-reactive
```
## Penggunaan Dasar
```typescript
import { useYupForm, YUP } from 'vue-yup-wrapper-reactive'
// Definisikan konfigurasi form
const formConfig = {
name: ['', YUP.string().required('Name is required')],
email: ['', YUP.string().email('Invalid email').required('Email is required')],
age: [0, YUP.number().min(18, 'Must be at least 18 years old').required('Age is required')],
} as const
// Gunakan dalam component Vue
export default {
setup() {
const { form, errors, validate, reset } = useYupForm(formConfig)
const handleSubmit = async () => {
const isValid = await validate()
if (isValid) {
console.log('Form data:', form)
// Proses form data
} else {
console.log('Validation errors:', errors.value)
}
}
return {
form,
errors,
validate,
reset,
handleSubmit
}
}
}
```
## Penggunaan dengan Custom Labels
```typescript
const formConfig = {
name: ['', YUP.string().required('Name is required'), 'Nama Lengkap'],
email: ['', YUP.string().email('Invalid email').required('Email is required'), 'Alamat Email'],
age: [0, YUP.number().min(18, 'Must be at least 18 years old').required('Age is required'), 'Umur'],
} as const
const { form, errors, validate, reset, getFieldLabel, fieldLabels } = useYupForm(formConfig)
// Akses label field
console.log(getFieldLabel('name')) // 'Nama Lengkap'
console.log(fieldLabels.email) // 'Alamat Email'
```
## Template Vue
```vue
<template>
<form @submit.prevent="handleSubmit">
<div>
<label>{{ getFieldLabel('name') }}:</label>
<input v-model="form.name" type="text" />
<span v-if="errors.name" class="error">{{ errors.name }}</span>
</div>
<div>
<label>{{ getFieldLabel('email') }}:</label>
<input v-model="form.email" type="email" />
<span v-if="errors.email" class="error">{{ errors.email }}</span>
</div>
<div>
<label>{{ getFieldLabel('age') }}:</label>
<input v-model.number="form.age" type="number" />
<span v-if="errors.age" class="error">{{ errors.age }}</span>
</div>
<button type="submit">Submit</button>
<button type="button" @click="reset">Reset</button>
</form>
</template>
```
## API Reference
### `useYupForm(config)`
#### Parameters
- `config`: Object dengan format `{ fieldName: [defaultValue, yupSchema, optionalLabel] }`
#### Returns
- `form`: Reactive object berisi nilai form
- `errors`: Ref object berisi error messages
- `validate()`: Function untuk validasi form (returns Promise<boolean>)
- `reset()`: Function untuk reset form ke nilai awal
- `getFieldLabel(fieldKey)`: Function untuk mendapatkan label field
- `fieldLabels`: Object mapping semua field labels
### Exported Utilities
- `YUP`: Yup library instance
- `YUP_OBJECT`: Yup.object() shorthand
- `version`: Plugin version
- `pluginInfo`: Plugin information
## Contoh Lengkap
```vue
<script setup lang="ts">
import { useYupForm, YUP } from 'vue-yup-wrapper-reactive'
const formConfig = {
firstName: ['', YUP.string().required('First name is required'), 'Nama Depan'],
lastName: ['', YUP.string().required('Last name is required'), 'Nama Belakang'],
email: ['', YUP.string().email('Invalid email').required('Email is required'), 'Email'],
password: ['', YUP.string().min(6, 'Password must be at least 6 characters').required('Password is required'), 'Password'],
confirmPassword: ['', YUP.string().oneOf([YUP.ref('password')], 'Passwords must match').required('Confirm password is required'), 'Konfirmasi Password'],
age: [0, YUP.number().min(18, 'Must be at least 18 years old').required('Age is required'), 'Umur'],
terms: [false, YUP.boolean().oneOf([true], 'You must accept terms and conditions'), 'Syarat & Ketentuan']
} as const
const { form, errors, validate, reset, getFieldLabel } = useYupForm(formConfig)
const handleSubmit = async () => {
const isValid = await validate()
if (isValid) {
alert('Form submitted successfully!')
console.log('Form data:', form)
}
}
</script>
<template>
<div class="form-container">
<h2>Registration Form</h2>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<label>{{ getFieldLabel('firstName') }}:</label>
<input v-model="form.firstName" type="text" />
<span v-if="errors.firstName" class="error">{{ errors.firstName }}</span>
</div>
<div class="form-group">
<label>{{ getFieldLabel('lastName') }}:</label>
<input v-model="form.lastName" type="text" />
<span v-if="errors.lastName" class="error">{{ errors.lastName }}</span>
</div>
<div class="form-group">
<label>{{ getFieldLabel('email') }}:</label>
<input v-model="form.email" type="email" />
<span v-if="errors.email" class="error">{{ errors.email }}</span>
</div>
<div class="form-group">
<label>{{ getFieldLabel('password') }}:</label>
<input v-model="form.password" type="password" />
<span v-if="errors.password" class="error">{{ errors.password }}</span>
</div>
<div class="form-group">
<label>{{ getFieldLabel('confirmPassword') }}:</label>
<input v-model="form.confirmPassword" type="password" />
<span v-if="errors.confirmPassword" class="error">{{ errors.confirmPassword }}</span>
</div>
<div class="form-group">
<label>{{ getFieldLabel('age') }}:</label>
<input v-model.number="form.age" type="number" />
<span v-if="errors.age" class="error">{{ errors.age }}</span>
</div>
<div class="form-group">
<label>
<input v-model="form.terms" type="checkbox" />
{{ getFieldLabel('terms') }}
</label>
<span v-if="errors.terms" class="error">{{ errors.terms }}</span>
</div>
<div class="form-actions">
<button type="submit">Submit</button>
<button type="button" @click="reset">Reset</button>
</div>
</form>
</div>
</template>
<style scoped>
.form-container {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.error {
color: red;
font-size: 14px;
margin-top: 5px;
display: block;
}
.form-actions {
display: flex;
gap: 10px;
margin-top: 20px;
}
button {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button[type="submit"] {
background-color: #007bff;
color: white;
}
button[type="button"] {
background-color: #6c757d;
color: white;
}
</style>
```
## Requirements
- Vue 3.x
- Yup 1.x
- TypeScript (recommended)
## License
MIT
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.