@overgaming/valiform 0.2.0 → 0.2.2
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/README.md +268 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Valiform
|
|
2
|
+
|
|
3
|
+
Lightweight, headless form validation library for Vue 3. Framework-agnostic validation rules, composable field state, and full localization support — with zero UI assumptions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @overgaming/valiform
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
### Vue
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createApp } from 'vue';
|
|
17
|
+
import { FormsPlugin } from '@overgaming/valiform';
|
|
18
|
+
import { es } from '@overgaming/valiform/locales';
|
|
19
|
+
|
|
20
|
+
const app = createApp(App);
|
|
21
|
+
|
|
22
|
+
app.use(FormsPlugin, {
|
|
23
|
+
locale: 'es',
|
|
24
|
+
locales: { es }
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Nuxt
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// nuxt.config.ts
|
|
32
|
+
export default defineNuxtConfig({
|
|
33
|
+
modules: ['@overgaming/valiform/nuxt'],
|
|
34
|
+
valiform: {
|
|
35
|
+
locale: 'es',
|
|
36
|
+
locales: { es }
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The Nuxt module auto-imports `<Form>`, `<Field>`, `useLocale`, `useFormContext` and `useFieldContext`.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### With custom components (recommended)
|
|
48
|
+
|
|
49
|
+
Build a custom input component using `useFieldContext` and `defineModel`:
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<!-- MyInput.vue -->
|
|
53
|
+
<template>
|
|
54
|
+
<input
|
|
55
|
+
class="my-input"
|
|
56
|
+
:class="{ 'my-input--error': error }"
|
|
57
|
+
v-model.trim="inputValue"
|
|
58
|
+
v-bind="inputProps"
|
|
59
|
+
:type
|
|
60
|
+
/>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<script setup lang="ts">
|
|
64
|
+
import { useFieldContext } from '@overgaming/valiform';
|
|
65
|
+
|
|
66
|
+
defineProps({
|
|
67
|
+
type: { type: String, default: 'text' }
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const model = defineModel({ type: String, default: '' });
|
|
71
|
+
const { inputValue, inputProps, error } = useFieldContext({ inputValue: model });
|
|
72
|
+
</script>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Then use it inside a `<Field>`:
|
|
76
|
+
|
|
77
|
+
```vue
|
|
78
|
+
<template>
|
|
79
|
+
<Form v-model="formData" @submit="handleSubmit" v-slot="{ isValid }">
|
|
80
|
+
<Field
|
|
81
|
+
name="name"
|
|
82
|
+
validation="required|min:3"
|
|
83
|
+
v-slot="{ labelProps, errorProps, error, isTouched }"
|
|
84
|
+
>
|
|
85
|
+
<label v-bind="labelProps">Name</label>
|
|
86
|
+
<MyInput />
|
|
87
|
+
<span v-if="error && isTouched" v-bind="errorProps">{{ error }}</span>
|
|
88
|
+
</Field>
|
|
89
|
+
|
|
90
|
+
<button type="submit" :disabled="!isValid">Submit</button>
|
|
91
|
+
</Form>
|
|
92
|
+
</template>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Components
|
|
98
|
+
|
|
99
|
+
### `<Form>`
|
|
100
|
+
|
|
101
|
+
Wraps your form and manages the global form state.
|
|
102
|
+
|
|
103
|
+
| Prop | Type | Description |
|
|
104
|
+
| ------------ | ------------------------- | -------------------------------- |
|
|
105
|
+
| `modelValue` | `Record<string, unknown>` | Form values (use with `v-model`) |
|
|
106
|
+
|
|
107
|
+
| Event | Payload | Description |
|
|
108
|
+
| -------- | -------------------------------- | ---------------------------- |
|
|
109
|
+
| `submit` | `(values, { setErrors, reset })` | Emitted on valid form submit |
|
|
110
|
+
|
|
111
|
+
| Slot prop | Type | Description |
|
|
112
|
+
| ---------- | ------------ | ----------------------------------- |
|
|
113
|
+
| `isValid` | `boolean` | Whether all fields are valid |
|
|
114
|
+
| `errors` | `string[]` | Array of all form-level errors |
|
|
115
|
+
| `reset` | `() => void` | Resets all fields to initial values |
|
|
116
|
+
| `validate` | `() => void` | Triggers validation on all fields |
|
|
117
|
+
|
|
118
|
+
### `<Field>`
|
|
119
|
+
|
|
120
|
+
Manages a single field's state and validation.
|
|
121
|
+
|
|
122
|
+
| Prop | Type | Description |
|
|
123
|
+
| -------------------- | ------------------------- | --------------------------------------- |
|
|
124
|
+
| `name` | `string` | Field name (used as key in form values) |
|
|
125
|
+
| `modelValue` | `unknown` | Field value when used outside `<Form>` |
|
|
126
|
+
| `validation` | `string \| Function` | Validation rules |
|
|
127
|
+
| `validationMessages` | `Record<string, unknown>` | Custom error messages for this field |
|
|
128
|
+
| `error` | `string \| string[]` | External error (e.g. from API) |
|
|
129
|
+
| `id` | `string` | Override the auto-generated input id |
|
|
130
|
+
|
|
131
|
+
| Slot prop | Type | Description |
|
|
132
|
+
| ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
133
|
+
| `inputProps` | `object` | Props for custom Vue components (`modelValue`, `onUpdate:modelValue`, `onBlur`, `id`, `name`, aria attrs) |
|
|
134
|
+
| `inputValue` | `unknown` | Current field value (writable) |
|
|
135
|
+
| `labelProps` | `{ for: string }` | Props for `<label>` |
|
|
136
|
+
| `errorProps` | `{ id, role, aria-live }` | Props for the error element |
|
|
137
|
+
| `helpProps` | `{ id: string }` | Props for a help text element |
|
|
138
|
+
| `error` | `string \| null` | First error message |
|
|
139
|
+
| `errors` | `string[]` | All error messages |
|
|
140
|
+
| `isValid` | `boolean` | Whether the field is valid |
|
|
141
|
+
| `isTouched` | `boolean` | Whether the field has been blurred |
|
|
142
|
+
| `isDirty` | `boolean` | Whether the value has changed |
|
|
143
|
+
| `validate` | `() => void` | Triggers validation manually |
|
|
144
|
+
| `reset` | `() => void` | Resets to initial value |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Validation rules
|
|
149
|
+
|
|
150
|
+
Rules are specified as a pipe-separated string: `"required|min:3|max:100"`.
|
|
151
|
+
|
|
152
|
+
| Rule | Arguments | Description |
|
|
153
|
+
| ------------------- | -------------------- | ------------------------------------------ |
|
|
154
|
+
| `required` | — | Value must not be empty |
|
|
155
|
+
| `min` | `min` | Minimum string length |
|
|
156
|
+
| `max` | `max` | Maximum string length |
|
|
157
|
+
| `email` | — | Valid email address |
|
|
158
|
+
| `url` | — | Valid URL |
|
|
159
|
+
| `number` | — | Must be a number |
|
|
160
|
+
| `alpha` | — | Letters only |
|
|
161
|
+
| `alphanumeric` | — | Letters and numbers only |
|
|
162
|
+
| `alphaSpaces` | — | Letters and spaces only |
|
|
163
|
+
| `lowercase` | — | Lowercase only |
|
|
164
|
+
| `uppercase` | — | Uppercase only |
|
|
165
|
+
| `between` | `min,max` | Number between two values |
|
|
166
|
+
| `length` | `exact` or `min,max` | String length |
|
|
167
|
+
| `matches` | `value1,value2,...` | Must match one of the values |
|
|
168
|
+
| `is` | `value` | Strict equality |
|
|
169
|
+
| `not` | `value` | Must not equal value |
|
|
170
|
+
| `accepted` | — | Must be truthy (checkboxes) |
|
|
171
|
+
| `confirm` | `fieldName` | Must match another field's value |
|
|
172
|
+
| `startsWith` | `prefix` | Must start with prefix |
|
|
173
|
+
| `endsWith` | `suffix` | Must end with suffix |
|
|
174
|
+
| `containsAlpha` | — | Must contain at least one letter |
|
|
175
|
+
| `containsNumeric` | — | Must contain at least one number |
|
|
176
|
+
| `containsUppercase` | — | Must contain at least one uppercase letter |
|
|
177
|
+
| `containsLowercase` | — | Must contain at least one lowercase letter |
|
|
178
|
+
| `containsSymbol` | — | Must contain at least one symbol |
|
|
179
|
+
| `dateFormat` | `format` | Valid date format |
|
|
180
|
+
| `dateAfter` | `date` | Date must be after |
|
|
181
|
+
| `dateBefore` | `date` | Date must be before |
|
|
182
|
+
| `dateBetween` | `start,end` | Date between two dates |
|
|
183
|
+
|
|
184
|
+
### Custom rules
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
app.use(FormsPlugin, {
|
|
188
|
+
rules: {
|
|
189
|
+
myRule: (value, { args, messages }) => {
|
|
190
|
+
if (value !== args[0]) return messages.myRule ?? 'Invalid value';
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Localization
|
|
200
|
+
|
|
201
|
+
Built-in locales: `en` (default), `es`.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { en, es } from '@overgaming/valiform';
|
|
205
|
+
|
|
206
|
+
app.use(FormsPlugin, {
|
|
207
|
+
locale: 'es',
|
|
208
|
+
locales: { en, es }
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Switch locale at runtime
|
|
213
|
+
|
|
214
|
+
```vue
|
|
215
|
+
<script setup>
|
|
216
|
+
import { useLocale } from '@overgaming/valiform';
|
|
217
|
+
|
|
218
|
+
const { locale, setLocale } = useLocale();
|
|
219
|
+
</script>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Custom locale
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
app.use(FormsPlugin, {
|
|
226
|
+
locales: {
|
|
227
|
+
en: {
|
|
228
|
+
required: 'This field is required',
|
|
229
|
+
email: 'Enter a valid email',
|
|
230
|
+
min: ({ args }) => `Minimum ${args[0]} characters`
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Composables
|
|
239
|
+
|
|
240
|
+
### `useFormContext()`
|
|
241
|
+
|
|
242
|
+
Access the parent `<Form>` state from any descendant component.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
const { values, isValid, errors, reset, validate, setErrors } = useFormContext();
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### `useFieldContext(options?)`
|
|
249
|
+
|
|
250
|
+
Access the parent `<Field>` state from any descendant component. Optionally pass `{ inputValue }` to sync a local ref (e.g. from `defineModel`) bidirectionally with the field value.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
// Basic usage
|
|
254
|
+
const { inputValue, inputProps, error, isValid, isTouched, isDirty } = useFieldContext();
|
|
255
|
+
|
|
256
|
+
// With defineModel sync
|
|
257
|
+
const model = defineModel({ type: String, default: '' });
|
|
258
|
+
const { inputValue, inputProps, error } = useFieldContext({ inputValue: model });
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### `useLocale()`
|
|
262
|
+
|
|
263
|
+
Access and change the active locale.
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
const { locale, setLocale } = useLocale();
|
|
267
|
+
setLocale('es');
|
|
268
|
+
```
|