Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 2x 2x 2x 4x 4x 4x 4x 4x 4x 2x 2x 8x 15x 7x 7x 8x 8x 1x 1x 8x 8x 8x | import { onCleanup } from './lifecycle.js';
import { exception, model } from './ref.js';
import { subscribe } from './subscription.js';
import type { ExceptionMap, ExceptionType, LinkableSchema, ModelInput, ModelOutput, StateChange } from './types.js';
export type FormOptions = {
onChange?: (event: StateChange) => void;
safeInit?: boolean;
};
/**
* Creates a form with validation based on the provided schema.
*
* @template S - The linkable schema type
* @template T - The model input type based on the schema
* @param schema - The validation schema to use for the form
* @param init - Initial values for the form
* @param options - Optional configuration for the form
* @returns A tuple containing:
* - state: Mutable form state that can be updated by user input
* - errors: Validation errors for the form fields
*/
export function form<S extends LinkableSchema, T extends ModelInput<S>>(
schema: S,
init: T,
options?: FormOptions
): [ModelOutput<S>, ExceptionMap<ModelOutput<S>>] {
const state = model(schema, init, { safeParse: true });
const { errors, destroy } = exception(state);
if (options?.safeInit === false) {
const initParse = schema.safeParse(init);
if (!initParse.success) {
for (const issue of initParse.error.issues) {
const key = issue.path.join('.');
(errors as ExceptionMap<Record<string, unknown>>)[key as never] = {
issues: [issue],
message: issue.message,
} as ExceptionType;
}
}
}
const unsubscribe = subscribe(state, (_c, event) => {
if (event.type !== 'init') {
options?.onChange?.(event);
}
});
onCleanup(() => {
unsubscribe();
destroy();
});
return [state, errors];
}
|