@ereo/forms 0.2.6 → 0.2.8

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.
Files changed (2) hide show
  1. package/README.md +233 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,233 @@
1
+ # @ereo/forms
2
+
3
+ Type-safe, signal-powered form management for React. Built on `@ereo/state` with per-field reactivity, schema validation, wizards, and accessibility out of the box.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @ereo/forms @ereo/state
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```tsx
14
+ import { useForm, useField } from '@ereo/forms';
15
+
16
+ interface LoginForm {
17
+ email: string;
18
+ password: string;
19
+ }
20
+
21
+ function LoginPage() {
22
+ const form = useForm<LoginForm>({
23
+ initialValues: { email: '', password: '' },
24
+ onSubmit: async (values) => {
25
+ await login(values);
26
+ },
27
+ });
28
+
29
+ const email = useField(form, 'email', { validate: required('Email is required') });
30
+ const password = useField(form, 'password', { validate: required('Password is required') });
31
+
32
+ return (
33
+ <form onSubmit={form.handleSubmit}>
34
+ <input {...email.inputProps} type="email" />
35
+ {email.error && <span>{email.error}</span>}
36
+
37
+ <input {...password.inputProps} type="password" />
38
+ {password.error && <span>{password.error}</span>}
39
+
40
+ <button type="submit" disabled={form.isSubmitting}>Log In</button>
41
+ </form>
42
+ );
43
+ }
44
+ ```
45
+
46
+ ## Key Features
47
+
48
+ - **Per-Field Signals** - Each field gets its own reactive signal for fine-grained updates
49
+ - **Type-Safe Paths** - `FormPath<T>` constrains all field names at compile time
50
+ - **Proxy Access** - Read/write values via `form.values.user.email`
51
+ - **Validation Engine** - Sync, async, schema, and cross-field validation with smart triggers
52
+ - **Schema Support** - Zod, Valibot, Standard Schema V1, and built-in `ereoSchema`
53
+ - **Components** - Pre-built `Field`, `TextareaField`, `SelectField`, and `FieldArray`
54
+ - **Wizard** - Multi-step forms with `createWizard`, step validation, and progress tracking
55
+ - **Server Actions** - `createFormAction` + `ActionForm` for server-side form handling
56
+ - **Accessibility** - ARIA attributes, focus management, live region announcements
57
+
58
+ ## Validation
59
+
60
+ ```typescript
61
+ import { required, email, minLength, compose, matches, async as asyncValidator } from '@ereo/forms';
62
+
63
+ const form = useForm<SignUpForm>({
64
+ initialValues: { email: '', password: '', confirmPassword: '' },
65
+ onSubmit: handleSignUp,
66
+ });
67
+
68
+ // Compose multiple validators
69
+ const emailField = useField(form, 'email', {
70
+ validate: compose(
71
+ required('Email is required'),
72
+ email('Invalid email address'),
73
+ asyncValidator(checkEmailAvailable, 'Email already taken'),
74
+ ),
75
+ });
76
+
77
+ // Cross-field validation with matches()
78
+ const confirmField = useField(form, 'confirmPassword', {
79
+ validate: matches('password', 'Passwords must match'),
80
+ });
81
+ ```
82
+
83
+ ## Schema Validation
84
+
85
+ ```typescript
86
+ import { useForm } from '@ereo/forms';
87
+ import { zodAdapter } from '@ereo/forms';
88
+ import { z } from 'zod';
89
+
90
+ const schema = z.object({
91
+ name: z.string().min(1),
92
+ age: z.number().min(18),
93
+ });
94
+
95
+ const form = useForm({
96
+ initialValues: { name: '', age: 0 },
97
+ schema: zodAdapter(schema),
98
+ onSubmit: handleSubmit,
99
+ });
100
+ ```
101
+
102
+ ## Field Arrays
103
+
104
+ ```tsx
105
+ import { useForm, useFieldArray } from '@ereo/forms';
106
+
107
+ interface TodoForm {
108
+ todos: { text: string; done: boolean }[];
109
+ }
110
+
111
+ function TodoList() {
112
+ const form = useForm<TodoForm>({
113
+ initialValues: { todos: [{ text: '', done: false }] },
114
+ onSubmit: handleSubmit,
115
+ });
116
+
117
+ const { items, append, remove, swap, move } = useFieldArray(form, 'todos');
118
+
119
+ return (
120
+ <div>
121
+ {items.map((item, i) => (
122
+ <div key={item.id}>
123
+ <input {...useField(form, `todos.${i}.text`).inputProps} />
124
+ <button onClick={() => remove(i)}>Remove</button>
125
+ </div>
126
+ ))}
127
+ <button onClick={() => append({ text: '', done: false })}>Add</button>
128
+ </div>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ## Wizard (Multi-Step Forms)
134
+
135
+ ```tsx
136
+ import { createWizard, useWizard, WizardProvider, WizardStep, WizardNavigation, WizardProgress } from '@ereo/forms';
137
+
138
+ const wizard = createWizard({
139
+ steps: [
140
+ { id: 'info', label: 'Info' },
141
+ { id: 'address', label: 'Address' },
142
+ { id: 'confirm', label: 'Confirm' },
143
+ ],
144
+ onComplete: async (data) => {
145
+ await submitRegistration(data);
146
+ },
147
+ });
148
+
149
+ function RegistrationWizard() {
150
+ return (
151
+ <WizardProvider wizard={wizard}>
152
+ <WizardProgress />
153
+ <WizardStep step="info"><InfoFields /></WizardStep>
154
+ <WizardStep step="address"><AddressFields /></WizardStep>
155
+ <WizardStep step="confirm"><ConfirmFields /></WizardStep>
156
+ <WizardNavigation />
157
+ </WizardProvider>
158
+ );
159
+ }
160
+ ```
161
+
162
+ ## Built-in Validators
163
+
164
+ | Validator | Description |
165
+ |-----------|-------------|
166
+ | `required(msg)` | Field must have a value |
167
+ | `email(msg)` | Valid email format |
168
+ | `url(msg)` | Valid URL format |
169
+ | `minLength(n, msg)` | Minimum string length |
170
+ | `maxLength(n, msg)` | Maximum string length |
171
+ | `min(n, msg)` | Minimum numeric value |
172
+ | `max(n, msg)` | Maximum numeric value |
173
+ | `pattern(regex, msg)` | Matches a regex pattern |
174
+ | `number(msg)` | Must be a valid number |
175
+ | `integer(msg)` | Must be an integer |
176
+ | `positive(msg)` | Must be positive |
177
+ | `matches(field, msg)` | Must match another field's value |
178
+ | `oneOf(values, msg)` | Must be one of the listed values |
179
+ | `fileSize(max, msg)` | File size limit |
180
+ | `fileType(types, msg)` | Allowed file MIME types |
181
+ | `compose(...fns)` | Compose multiple validators |
182
+ | `when(cond, validator)` | Conditional validation |
183
+ | `async(fn, msg)` | Async validation with debounce |
184
+ | `custom(fn)` | Custom validation function |
185
+
186
+ ## API Reference
187
+
188
+ ### Hooks
189
+ - `useForm(config)` - Create a form store (React hook)
190
+ - `useField(form, name, opts?)` - Register and subscribe to a field
191
+ - `useFieldArray(form, name)` - Manage dynamic array fields
192
+ - `useWatch(form, name)` - Observe a field value without registering
193
+ - `useFormStatus(form)` - Get form-level status (dirty, valid, submitting)
194
+
195
+ ### Core
196
+ - `createFormStore(config)` - Create a form store (non-hook)
197
+ - `FormStore` - The form store class
198
+ - `createValuesProxy(form)` - Create a proxy for `form.values.x.y` access
199
+ - `getPath(obj, path)` / `setPath(obj, path, val)` - Deep path get/set
200
+
201
+ ### Components
202
+ - `Field` - Renders an input field with label, error, and ARIA props
203
+ - `TextareaField` - Textarea variant
204
+ - `SelectField` - Select dropdown variant
205
+ - `FieldArray` - Render prop for array fields
206
+
207
+ ### Context
208
+ - `FormProvider` / `useFormContext` - React context for form store
209
+
210
+ ### Schema Adapters
211
+ - `zodAdapter(schema)` - Zod schema adapter
212
+ - `valibotAdapter(schema)` - Valibot schema adapter
213
+ - `standardSchemaAdapter(schema)` - Standard Schema V1 adapter
214
+ - `ereoSchema(definition)` - Built-in lightweight schema
215
+ - `createSchemaValidator(schema)` - Generic schema validator factory
216
+
217
+ ### Server Actions
218
+ - `createFormAction(config)` - Create a server action handler
219
+ - `ActionForm` - Form component wired to server actions
220
+ - `useFormAction(form, action)` - Hook for action-based submission
221
+ - `parseActionResult(response)` - Parse server action response
222
+
223
+ ## Documentation
224
+
225
+ For full documentation, visit [https://ereojs.dev/docs/forms](https://ereojs.dev/docs/forms)
226
+
227
+ ## Part of EreoJS
228
+
229
+ This package is part of the [EreoJS](https://github.com/ereoJS/ereoJS) monorepo - a modern full-stack framework built for Bun.
230
+
231
+ ## License
232
+
233
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ereo/forms",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "author": "Ereo Team",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "main": "./dist/index.js",
11
11
  "dependencies": {
12
- "@ereo/state": "^0.2.6"
12
+ "@ereo/state": "^0.2.8"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@happy-dom/global-registrator": "20.5.0",