@coherent.js/forms 1.0.0-beta.3 → 1.0.0-beta.6

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 ADDED
@@ -0,0 +1,304 @@
1
+ # @coherent.js/forms
2
+
3
+ Comprehensive forms handling and validation utilities for Coherent.js applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @coherent.js/forms
9
+ # or
10
+ pnpm add @coherent.js/forms
11
+ # or
12
+ yarn add @coherent.js/forms
13
+ ```
14
+
15
+ ## Overview
16
+
17
+ The `@coherent.js/forms` package provides powerful form handling capabilities including:
18
+
19
+ - Form state management
20
+ - Validation with built-in validators
21
+ - Error handling and display
22
+ - Form serialization and submission
23
+ - Integration with Coherent.js components
24
+
25
+ ## Quick Start
26
+
27
+ ```javascript
28
+ import { createForm } from '@coherent.js/forms';
29
+ import { validators } from '@coherent.js/state';
30
+
31
+ const contactForm = createForm({
32
+ fields: {
33
+ email: {
34
+ value: '',
35
+ validators: [validators.email('Please enter a valid email')]
36
+ },
37
+ message: {
38
+ value: '',
39
+ validators: [validators.minLength(10, 'Message must be at least 10 characters')]
40
+ }
41
+ }
42
+ });
43
+
44
+ function ContactForm() {
45
+ const handleSubmit = async (event) => {
46
+ event.preventDefault();
47
+
48
+ if (contactForm.validate()) {
49
+ // Form is valid, submit data
50
+ await submitFormData(contactForm.values);
51
+ contactForm.reset();
52
+ }
53
+ };
54
+
55
+ return {
56
+ form: {
57
+ onsubmit: handleSubmit,
58
+ children: [
59
+ {
60
+ input: {
61
+ type: 'email',
62
+ value: contactForm.fields.email.value,
63
+ oninput: (e) => contactForm.setField('email', e.target.value),
64
+ className: contactForm.fields.email.error ? 'error' : ''
65
+ }
66
+ },
67
+ {
68
+ span: {
69
+ text: contactForm.fields.email.error || '',
70
+ className: 'error-message'
71
+ }
72
+ },
73
+ {
74
+ textarea: {
75
+ value: contactForm.fields.message.value,
76
+ oninput: (e) => contactForm.setField('message', e.target.value),
77
+ className: contactForm.fields.message.error ? 'error' : ''
78
+ }
79
+ },
80
+ {
81
+ span: {
82
+ text: contactForm.fields.message.error || '',
83
+ className: 'error-message'
84
+ }
85
+ },
86
+ {
87
+ button: {
88
+ type: 'submit',
89
+ text: 'Send Message',
90
+ disabled: contactForm.isSubmitting
91
+ }
92
+ }
93
+ ]
94
+ }
95
+ };
96
+ }
97
+ ```
98
+
99
+ ## Features
100
+
101
+ ### Form State Management
102
+
103
+ Automatically manage form state including values, errors, and submission status:
104
+
105
+ ```javascript
106
+ const form = createForm({
107
+ fields: {
108
+ username: { value: '' },
109
+ password: { value: '' }
110
+ }
111
+ });
112
+
113
+ // Access form values
114
+ console.log(form.values); // { username: '', password: '' }
115
+
116
+ // Update field values
117
+ form.setField('username', 'john_doe');
118
+
119
+ // Check form validity
120
+ console.log(form.isValid); // true/false
121
+
122
+ // Check submission status
123
+ console.log(form.isSubmitting); // true/false
124
+ ```
125
+
126
+ ### Validation
127
+
128
+ Built-in validators with custom validation support:
129
+
130
+ ```javascript
131
+ import { validators } from '@coherent.js/state';
132
+
133
+ const form = createForm({
134
+ fields: {
135
+ email: {
136
+ value: '',
137
+ validators: [
138
+ validators.required('Email is required'),
139
+ validators.email('Please enter a valid email')
140
+ ]
141
+ },
142
+ age: {
143
+ value: '',
144
+ validators: [
145
+ validators.required('Age is required'),
146
+ validators.min(18, 'Must be at least 18 years old')
147
+ ]
148
+ }
149
+ }
150
+ });
151
+
152
+ // Custom validator
153
+ const customValidator = (value) => {
154
+ if (value && value.length < 5) {
155
+ return 'Value must be at least 5 characters';
156
+ }
157
+ return null; // null means valid
158
+ };
159
+
160
+ const formWithCustomValidation = createForm({
161
+ fields: {
162
+ customField: {
163
+ value: '',
164
+ validators: [customValidator]
165
+ }
166
+ }
167
+ });
168
+ ```
169
+
170
+ ### Async Validation
171
+
172
+ Support for asynchronous validation (e.g., checking if username is available):
173
+
174
+ ```javascript
175
+ const asyncValidator = async (value) => {
176
+ if (!value) return null;
177
+
178
+ const response = await fetch(`/api/check-username/${value}`);
179
+ const exists = await response.json();
180
+
181
+ return exists ? 'Username is already taken' : null;
182
+ };
183
+
184
+ const signupForm = createForm({
185
+ fields: {
186
+ username: {
187
+ value: '',
188
+ validators: [asyncValidator]
189
+ }
190
+ }
191
+ });
192
+ ```
193
+
194
+ ## API Reference
195
+
196
+ ### createForm(options)
197
+
198
+ Create a new form instance.
199
+
200
+ **Parameters:**
201
+ - `options.fields` - Object defining form fields and their initial state
202
+ - `options.onSubmit` - Optional function to handle form submission
203
+
204
+ **Returns:** Form instance with methods and properties
205
+
206
+ ### Form Instance Properties
207
+
208
+ - `values` - Current form values
209
+ - `fields` - Field state objects with value, error, touched, etc.
210
+ - `isValid` - Boolean indicating if form is valid
211
+ - `isSubmitting` - Boolean indicating if form is being submitted
212
+ - `errors` - Object containing field errors
213
+
214
+ ### Form Instance Methods
215
+
216
+ - `setField(name, value)` - Update a field's value
217
+ - `validate()` - Validate all fields, returns boolean
218
+ - `reset()` - Reset form to initial state
219
+ - `submit()` - Trigger form submission
220
+
221
+ ## Integration with @coherent.js/state
222
+
223
+ The forms package integrates seamlessly with the reactive state system:
224
+
225
+ ```javascript
226
+ import { createForm } from '@coherent.js/forms';
227
+ import { observable } from '@coherent.js/state';
228
+
229
+ // Create reactive form
230
+ const form = createForm({
231
+ fields: {
232
+ search: { value: '' }
233
+ }
234
+ });
235
+
236
+ // Create observable for search results
237
+ const searchResults = observable([]);
238
+
239
+ // Update search results when form changes
240
+ form.fields.search.watch((newValue) => {
241
+ if (newValue.length > 2) {
242
+ performSearch(newValue).then(results => {
243
+ searchResults.value = results;
244
+ });
245
+ }
246
+ });
247
+ ```
248
+
249
+ ## Examples
250
+
251
+ ### Login Form
252
+
253
+ ```javascript
254
+ import { createForm } from '@coherent.js/forms';
255
+ import { validators } from '@coherent.js/state';
256
+
257
+ const loginForm = createForm({
258
+ fields: {
259
+ email: {
260
+ value: '',
261
+ validators: [
262
+ validators.required('Email is required'),
263
+ validators.email('Please enter a valid email')
264
+ ]
265
+ },
266
+ password: {
267
+ value: '',
268
+ validators: [
269
+ validators.required('Password is required'),
270
+ validators.minLength(8, 'Password must be at least 8 characters')
271
+ ]
272
+ }
273
+ },
274
+ async onSubmit(values) {
275
+ try {
276
+ const response = await fetch('/api/login', {
277
+ method: 'POST',
278
+ headers: { 'Content-Type': 'application/json' },
279
+ body: JSON.stringify(values)
280
+ });
281
+
282
+ if (response.ok) {
283
+ // Handle successful login
284
+ window.location.href = '/dashboard';
285
+ } else {
286
+ // Handle login error
287
+ throw new Error('Invalid credentials');
288
+ }
289
+ } catch (error) {
290
+ loginForm.setError('login', error.message);
291
+ }
292
+ }
293
+ });
294
+ ```
295
+
296
+ ## Related Packages
297
+
298
+ - [@coherent.js/state](../state/README.md) - Reactive state management
299
+ - [@coherent.js/core](../core/README.md) - Core framework
300
+ - [@coherent.js/client](../client/README.md) - Client-side utilities
301
+
302
+ ## License
303
+
304
+ MIT
package/dist/index.js CHANGED
@@ -1664,7 +1664,7 @@ var enhancedForm = createForm();
1664
1664
 
1665
1665
  // src/advanced-validation.js
1666
1666
  import { ReactiveState, observable, computed } from "@coherent.js/state/src/reactive-state.js";
1667
- import { globalErrorHandler } from "@coherent.js/core/src/utils/_error-handler.js";
1667
+ import { globalErrorHandler } from "@coherent.js/core/src/utils/error-handler.js";
1668
1668
  var validationRules = {
1669
1669
  required: (value, params = true) => {
1670
1670
  if (!params) return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherent.js/forms",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "SSR + Hydration form system for Coherent.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,8 +22,8 @@
22
22
  "author": "Coherent.js Team",
23
23
  "license": "MIT",
24
24
  "peerDependencies": {
25
- "@coherent.js/core": "1.0.0-beta.3",
26
- "@coherent.js/state": "1.0.0-beta.3"
25
+ "@coherent.js/core": "1.0.0-beta.6",
26
+ "@coherent.js/state": "1.0.0-beta.6"
27
27
  },
28
28
  "repository": {
29
29
  "type": "git",
@@ -38,6 +38,7 @@
38
38
  "README.md",
39
39
  "types/"
40
40
  ],
41
+ "sideEffects": false,
41
42
  "scripts": {
42
43
  "build": "node build.mjs",
43
44
  "clean": "rm -rf dist"
package/types/index.d.ts CHANGED
@@ -3,132 +3,455 @@
3
3
  * @module @coherent.js/forms
4
4
  */
5
5
 
6
- // ===== Form Builder Types =====
6
+ import type { CoherentNode, CoherentElement, StrictCoherentElement } from '@coherent.js/core';
7
7
 
8
- export interface FormField {
9
- type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'date' | 'time' | 'datetime-local' | 'checkbox' | 'radio' | 'select' | 'textarea';
8
+ // ============================================================================
9
+ // Form Field Types
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Available form field input types
14
+ */
15
+ export type FormFieldType =
16
+ | 'text'
17
+ | 'email'
18
+ | 'password'
19
+ | 'number'
20
+ | 'tel'
21
+ | 'url'
22
+ | 'date'
23
+ | 'time'
24
+ | 'datetime-local'
25
+ | 'checkbox'
26
+ | 'radio'
27
+ | 'select'
28
+ | 'textarea'
29
+ | 'file'
30
+ | 'hidden'
31
+ | 'color'
32
+ | 'range'
33
+ | 'search'
34
+ | 'month'
35
+ | 'week';
36
+
37
+ /**
38
+ * Option for select and radio fields
39
+ */
40
+ export interface SelectOption {
41
+ value: string | number;
42
+ label: string;
43
+ disabled?: boolean;
44
+ }
45
+
46
+ /**
47
+ * Typed form field definition with generic value type
48
+ * @template T - The type of the field value
49
+ */
50
+ export interface FormField<T = unknown> {
51
+ /** Field input type */
52
+ type: FormFieldType;
53
+ /** Field name (used as form data key) */
10
54
  name: string;
55
+ /** Human-readable label */
11
56
  label?: string;
57
+ /** Placeholder text */
12
58
  placeholder?: string;
59
+ /** Whether field is required */
13
60
  required?: boolean;
14
- value?: any;
15
- options?: Array<{ value: string; label: string }>;
61
+ /** Whether field is disabled */
62
+ disabled?: boolean;
63
+ /** Whether field is readonly */
64
+ readonly?: boolean;
65
+ /** Default/initial value */
66
+ defaultValue?: T;
67
+ /** Current value */
68
+ value?: T;
69
+ /** Options for select/radio fields */
70
+ options?: SelectOption[];
71
+ /** Validation rules */
16
72
  validators?: Validator[];
17
- attributes?: Record<string, any>;
73
+ /** Field-specific validation configuration */
74
+ validation?: FieldValidation<T>;
75
+ /** Additional HTML attributes */
76
+ attributes?: Record<string, unknown>;
77
+ /** Transform function to convert raw input to typed value */
78
+ transform?: (value: unknown) => T;
18
79
  }
19
80
 
81
+ /**
82
+ * Field validation configuration with typed value
83
+ * @template T - The type of the field value
84
+ */
85
+ export interface FieldValidation<T = unknown> {
86
+ /** Required validation with optional custom message */
87
+ required?: boolean | string;
88
+ /** Minimum length for string values */
89
+ minLength?: number | { value: number; message: string };
90
+ /** Maximum length for string values */
91
+ maxLength?: number | { value: number; message: string };
92
+ /** Minimum value for number values */
93
+ min?: number | { value: number; message: string };
94
+ /** Maximum value for number values */
95
+ max?: number | { value: number; message: string };
96
+ /** Regular expression pattern validation */
97
+ pattern?: RegExp | { value: RegExp; message: string };
98
+ /** Custom validation function */
99
+ custom?: (value: T, formData: Record<string, unknown>) => boolean | string | Promise<boolean | string>;
100
+ /** Validate on change (real-time) */
101
+ validateOnChange?: boolean;
102
+ /** Validate on blur */
103
+ validateOnBlur?: boolean;
104
+ /** Debounce time in milliseconds for validation */
105
+ debounce?: number;
106
+ }
107
+
108
+ // ============================================================================
109
+ // Form Builder Types
110
+ // ============================================================================
111
+
112
+ /**
113
+ * Form configuration options
114
+ */
20
115
  export interface FormConfig {
21
- fields: FormField[];
116
+ /** Form fields */
117
+ fields?: FormField[];
118
+ /** Form action URL */
22
119
  action?: string;
120
+ /** Form submission method */
23
121
  method?: 'get' | 'post';
122
+ /** Form CSS class name */
24
123
  className?: string;
124
+ /** Submit button text */
25
125
  submitText?: string;
126
+ /** Form submit handler */
26
127
  onSubmit?: (data: FormData) => void | Promise<void>;
128
+ /** Form encoding type */
129
+ enctype?: 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain';
130
+ /** Whether to disable browser validation */
131
+ novalidate?: boolean;
132
+ /** Form ID */
133
+ id?: string;
27
134
  }
28
135
 
29
- export class FormBuilder {
30
- constructor(config: FormConfig);
31
- addField(field: FormField): this;
32
- removeField(name: string): this;
33
- build(): object;
34
- render(): object;
136
+ /**
137
+ * Typed form builder with generic form data shape
138
+ * @template T - The shape of the form data
139
+ */
140
+ export interface FormBuilder<T extends Record<string, unknown> = Record<string, unknown>> {
141
+ /**
142
+ * Add a field to the form
143
+ * @template K - The key in the form data
144
+ */
145
+ addField<K extends keyof T>(name: K, field: Omit<FormField<T[K]>, 'name'>): FormBuilder<T>;
146
+
147
+ /**
148
+ * Remove a field from the form
149
+ */
150
+ removeField(name: keyof T): FormBuilder<T>;
151
+
152
+ /**
153
+ * Set the form action URL
154
+ */
155
+ setAction(action: string): FormBuilder<T>;
156
+
157
+ /**
158
+ * Set the form submission method
159
+ */
160
+ setMethod(method: 'get' | 'post'): FormBuilder<T>;
161
+
162
+ /**
163
+ * Set the form submit handler
164
+ */
165
+ onSubmit(handler: (data: T) => void | Promise<void>): FormBuilder<T>;
166
+
167
+ /**
168
+ * Build the form as a CoherentNode
169
+ */
170
+ build(): CoherentNode;
171
+
172
+ /**
173
+ * Render the form (alias for build)
174
+ */
175
+ render(): CoherentNode;
176
+
177
+ /**
178
+ * Validate form data
179
+ */
180
+ validate(data: unknown): { valid: boolean; errors: Record<keyof T, string[]> };
181
+
182
+ /**
183
+ * Get current field definitions
184
+ */
185
+ getFields(): FormField[];
35
186
  }
36
187
 
37
- export function createFormBuilder(config: FormConfig): FormBuilder;
38
- export function buildForm(config: FormConfig): object;
188
+ /**
189
+ * Create a typed form builder
190
+ * @template T - The shape of the form data
191
+ */
192
+ export function createFormBuilder<T extends Record<string, unknown> = Record<string, unknown>>(
193
+ config?: FormConfig
194
+ ): FormBuilder<T>;
195
+
196
+ /**
197
+ * Build a form from configuration
198
+ */
199
+ export function buildForm(config: FormConfig): CoherentNode;
200
+
201
+ /**
202
+ * Render a single form field
203
+ */
204
+ export function renderField<T = unknown>(field: FormField<T>): CoherentNode;
205
+
206
+ /**
207
+ * Validate a single field value
208
+ * @returns Error message or null if valid
209
+ */
210
+ export function validateField<T>(field: FormField<T>, value: unknown): string | null;
211
+
212
+ // ============================================================================
213
+ // Form Builder Class
214
+ // ============================================================================
215
+
216
+ /**
217
+ * Form builder class implementation
218
+ */
219
+ export class FormBuilder<T extends Record<string, unknown> = Record<string, unknown>> {
220
+ constructor(config?: FormConfig);
221
+ addField<K extends keyof T>(name: K, field: Omit<FormField<T[K]>, 'name'>): this;
222
+ removeField(name: keyof T): this;
223
+ setAction(action: string): this;
224
+ setMethod(method: 'get' | 'post'): this;
225
+ onSubmit(handler: (data: T) => void | Promise<void>): this;
226
+ build(): CoherentNode;
227
+ render(): CoherentNode;
228
+ validate(data: unknown): { valid: boolean; errors: Record<keyof T, string[]> };
229
+ getFields(): FormField[];
230
+ }
39
231
 
40
- // ===== Form Hydration Types =====
232
+ // ============================================================================
233
+ // Form Hydration Types
234
+ // ============================================================================
41
235
 
236
+ /**
237
+ * Options for hydrating a form on the client
238
+ */
42
239
  export interface HydrationOptions {
240
+ /** Enable validation */
43
241
  validation?: boolean;
242
+ /** Enable real-time validation as user types */
44
243
  realTimeValidation?: boolean;
244
+ /** Form submit handler */
45
245
  onSubmit?: (event: Event, data: FormData) => void | Promise<void>;
246
+ /** Validation error handler */
46
247
  onValidate?: (errors: ValidationErrors) => void;
248
+ /** Prevent default form submission */
249
+ preventSubmit?: boolean;
47
250
  }
48
251
 
252
+ /**
253
+ * Hydrated form interface for client-side interaction
254
+ */
49
255
  export interface HydratedForm {
256
+ /** The form DOM element */
50
257
  element: HTMLFormElement;
258
+ /** Validate all form fields */
51
259
  validate(): ValidationResult;
260
+ /** Reset form to initial values */
52
261
  reset(): void;
262
+ /** Get current form data */
53
263
  getData(): FormData;
54
- setData(data: Record<string, any>): void;
264
+ /** Get form data as object */
265
+ getValues<T = Record<string, unknown>>(): T;
266
+ /** Set form field values */
267
+ setData(data: Record<string, unknown>): void;
268
+ /** Set a single field value */
269
+ setValue(name: string, value: unknown): void;
270
+ /** Destroy hydration and clean up event listeners */
55
271
  destroy(): void;
272
+ /** Check if form is valid */
273
+ isValid(): boolean;
274
+ /** Get validation errors */
275
+ getErrors(): ValidationErrors;
56
276
  }
57
277
 
58
- export function hydrateForm(formElement: HTMLFormElement | string, options?: HydrationOptions): HydratedForm;
278
+ /**
279
+ * Hydrate a form element for client-side interactivity
280
+ */
281
+ export function hydrateForm(
282
+ formElement: HTMLFormElement | string,
283
+ options?: HydrationOptions
284
+ ): HydratedForm;
59
285
 
60
- // ===== Validation Types =====
286
+ // ============================================================================
287
+ // Validation Types
288
+ // ============================================================================
61
289
 
290
+ /**
291
+ * Validation result
292
+ */
62
293
  export interface ValidationResult {
294
+ /** Whether all fields are valid */
63
295
  valid: boolean;
296
+ /** Validation errors by field name */
64
297
  errors: ValidationErrors;
65
298
  }
66
299
 
300
+ /**
301
+ * Validation errors mapped by field name
302
+ */
67
303
  export interface ValidationErrors {
68
304
  [fieldName: string]: string[];
69
305
  }
70
306
 
307
+ /**
308
+ * Validator function type
309
+ */
71
310
  export interface Validator {
72
- (value: any): boolean | string | Promise<boolean | string>;
311
+ (value: unknown): boolean | string | Promise<boolean | string>;
73
312
  }
74
313
 
314
+ /**
315
+ * Form validator class
316
+ */
75
317
  export class FormValidator {
76
318
  constructor(rules: Record<string, Validator[]>);
77
- validate(data: Record<string, any>): ValidationResult;
78
- validateAsync(data: Record<string, any>): Promise<ValidationResult>;
319
+ /** Synchronous validation */
320
+ validate(data: Record<string, unknown>): ValidationResult;
321
+ /** Asynchronous validation */
322
+ validateAsync(data: Record<string, unknown>): Promise<ValidationResult>;
323
+ /** Add a validation rule */
79
324
  addRule(field: string, validator: Validator): void;
325
+ /** Remove a validation rule */
80
326
  removeRule(field: string, validator: Validator): void;
327
+ /** Clear all rules for a field */
328
+ clearRules(field: string): void;
81
329
  }
82
330
 
331
+ /**
332
+ * Create a form validator
333
+ */
83
334
  export function createValidator(rules: Record<string, Validator[]>): FormValidator;
84
- export function validate(data: Record<string, any>, rules: Record<string, Validator[]>): ValidationResult;
85
335
 
86
- // ===== Built-in Validators =====
336
+ /**
337
+ * Validate data against rules
338
+ */
339
+ export function validate(
340
+ data: Record<string, unknown>,
341
+ rules: Record<string, Validator[]>
342
+ ): ValidationResult;
343
+
344
+ // ============================================================================
345
+ // Built-in Validators
346
+ // ============================================================================
87
347
 
348
+ /**
349
+ * Built-in validator functions
350
+ */
88
351
  export const validators: {
352
+ /** Require a value to be present */
89
353
  required(message?: string): Validator;
354
+ /** Validate email format */
90
355
  email(message?: string): Validator;
356
+ /** Minimum string length */
91
357
  minLength(length: number, message?: string): Validator;
358
+ /** Maximum string length */
92
359
  maxLength(length: number, message?: string): Validator;
360
+ /** Minimum numeric value */
93
361
  min(value: number, message?: string): Validator;
362
+ /** Maximum numeric value */
94
363
  max(value: number, message?: string): Validator;
364
+ /** Pattern matching */
95
365
  pattern(regex: RegExp, message?: string): Validator;
366
+ /** Match another field's value */
96
367
  matches(field: string, message?: string): Validator;
368
+ /** Validate URL format */
97
369
  url(message?: string): Validator;
370
+ /** Validate as number */
98
371
  number(message?: string): Validator;
372
+ /** Validate as integer */
99
373
  integer(message?: string): Validator;
374
+ /** Validate as positive number */
100
375
  positive(message?: string): Validator;
376
+ /** Validate as negative number */
101
377
  negative(message?: string): Validator;
378
+ /** Validate date format */
102
379
  date(message?: string): Validator;
103
- custom(fn: (value: any) => boolean | string, message?: string): Validator;
104
- async(fn: (value: any) => Promise<boolean | string>): Validator;
380
+ /** Custom validation function */
381
+ custom(fn: (value: unknown) => boolean | string, message?: string): Validator;
382
+ /** Async validation function */
383
+ async(fn: (value: unknown) => Promise<boolean | string>): Validator;
105
384
  };
106
385
 
386
+ /** Alias for validators */
107
387
  export const formValidators: typeof validators;
108
388
 
109
- // ===== Advanced Validation =====
389
+ // ============================================================================
390
+ // Advanced Validation
391
+ // ============================================================================
110
392
 
393
+ /**
394
+ * Validation rule configuration
395
+ */
111
396
  export interface ValidationRule {
397
+ /** The validator function */
112
398
  validator: Validator;
399
+ /** Custom error message */
113
400
  message?: string;
401
+ /** Whether this is an async validator */
114
402
  async?: boolean;
115
403
  }
116
404
 
117
- export interface FieldValidation {
118
- rules: ValidationRule[];
119
- validateOnChange?: boolean;
120
- validateOnBlur?: boolean;
121
- debounce?: number;
122
- }
405
+ /**
406
+ * Create an async validator
407
+ */
408
+ export function createAsyncValidator(
409
+ fn: (value: unknown) => Promise<boolean | string>
410
+ ): Validator;
123
411
 
124
- export function createAsyncValidator(fn: (value: any) => Promise<boolean | string>): Validator;
412
+ /**
413
+ * Combine multiple validators into one
414
+ */
125
415
  export function combineValidators(...validators: Validator[]): Validator;
126
- export function conditionalValidator(condition: (data: Record<string, any>) => boolean, validator: Validator): Validator;
127
416
 
128
- // ===== Deprecated SPA-only Functions (for backward compatibility) =====
417
+ /**
418
+ * Create a conditional validator
419
+ */
420
+ export function conditionalValidator(
421
+ condition: (data: Record<string, unknown>) => boolean,
422
+ validator: Validator
423
+ ): Validator;
424
+
425
+ // ============================================================================
426
+ // Form Utilities
427
+ // ============================================================================
428
+
429
+ /**
430
+ * Parse FormData to typed object
431
+ */
432
+ export function parseFormData<T extends Record<string, unknown>>(formData: FormData): T;
433
+
434
+ /**
435
+ * Serialize object to FormData
436
+ */
437
+ export function toFormData(data: Record<string, unknown>): FormData;
438
+
439
+ /**
440
+ * Create a form group (fieldset)
441
+ */
442
+ export function createFieldGroup(
443
+ legend: string,
444
+ fields: FormField[]
445
+ ): CoherentNode;
446
+
447
+ // ============================================================================
448
+ // Deprecated Functions (Backward Compatibility)
449
+ // ============================================================================
129
450
 
130
451
  /** @deprecated Use createFormBuilder() on server + hydrateForm() on client */
131
- export function createForm(config: FormConfig): object;
452
+ export function createForm(config: FormConfig): CoherentNode;
132
453
 
133
454
  /** @deprecated Use validators with hydrateForm() instead */
134
- export function enhancedForm(config: FormConfig & { validation?: Record<string, Validator[]> }): object;
455
+ export function enhancedForm(
456
+ config: FormConfig & { validation?: Record<string, Validator[]> }
457
+ ): CoherentNode;