svelte-common-hooks
Version:
Common hooks for Svelte
180 lines (179 loc) • 6.27 kB
TypeScript
import { z } from 'zod/v4';
/**
* The props for `createFormState`.
*
* @template {z.ZodObject<any>} T The zod schema that will validate the form state.
* @template {z.infer<T>} Initial The initial value of the form state.
*/
export type FormStateProps<T extends z.ZodObject<any>, Initial extends z.infer<T> = z.infer<T>> = {
/**
* zod/v4 schema
* @link https://zod.dev/v4
*/
schema: T;
/**
* initial value of the form state, the property that is not exist in the schema is allowed but ignored
*/
initial?: Initial;
/**
* attributes that will be applied to the form fields, use `createAttribute` to help you create the attributes
*/
attribute?: FormAttribute<T>;
};
/**
* Attributes for a form field
*/
type FormAttribute<T extends z.ZodObject<any>> = {
[K in keyof z.infer<T>]?: ReturnType<typeof createAttribute>;
};
/**
* The config of the form state
*/
type FormStateConfig<T extends z.ZodObject<any>> = {
[K in keyof z.infer<T>]: {
/**
* errors of the form field
*/
errors: string[];
/**
* whether the form field has error
*/
hasError: boolean;
};
};
/**
* Necessary attributes for a form field
*/
type FormStateAttribute<T extends z.ZodObject<any>> = {
[K in keyof z.infer<T>]: {
/**
* aria-invalid attribute
*/
'aria-invalid': boolean;
/**
* oninput event, it will validate the form field on input if the result has error
*/
oninput: (event: Event & {
currentTarget: EventTarget & HTMLElement;
}) => void;
/**
* onblur event, it will validate the form field on blur
*/
onblur: (event: Event & {
currentTarget: EventTarget & HTMLElement;
}) => void;
};
};
/**
* The helper to create attributes for a form field
* @example
* ```svelte
* <script lang="ts">
* import type { HTMLInputAttributes } from 'svelte/elements';
* import { createAttribute } from 'svelte-common-hooks';
* const attribute = createAttribute<HTMLInputAttributes>({
* type: 'text',
* placeholder: 'Enter your name',
* required: true,
* customAttribute: 'customAttribute',
* });
* </script>
* ```
* @param attribute the attributes that will be applied to the form field
*/
export declare function createAttribute<InputAttribute extends Record<string, any>>(attribute: InputAttribute & Record<string, unknown>): InputAttribute & Record<string, unknown>;
/**
* Creates and manages the state of a form based on a Zod schema.
*
* @example
* ```svelte
* <script lang="ts">
* import { createFormState } from 'svelte-common-hooks';
* import { z } from 'zod/v4';
* const formState = createFormState({
* schema: z.object({
* name: z.string().min(1),
* email: z.string().email(),
* age: z.number().min(18)
* }),
* // optionally set the initial value
* initial: {
* name: '',
* email: '',
* age: 0
* },
* // optionally append more attribute to the form field
* attribute: {
* name: createAttribute<HTMLInputAttributes>({
* type: 'text',
* placeholder: 'Enter your name',
* required: true,
* customAttribute: 'customAttribute',
* }),
* email: createAttribute<HTMLInputAttributes>({
* type: 'email',
* required: true
* }),
* age: createAttribute<HTMLInputAttributes>({
* type: 'number',
* required: true
* })
* }
* });
* </script>
* <form action="" method="post">
* <div>
* <label for="name">Name</label>
* <input bind:value={formState.value.name} {...formState.attribute.name} />
* {#if formState.result.name.errors.length}
* {#each formState.result.name.errors as error}
* <span>{error}</span>
* {/each}
* {/if}
* </div>
* <div>
* <label for="email">Email</label>
* <input bind:value={formState.value.email} {...formState.attribute.email} />
* {#if formState.result.email.errors.length}
* {#each formState.result.email.errors as error}
* <span>{error}</span>
* {/each}
* {/if}
* </div>
* <div>
* <label for="age">Age</label>
* <input bind:value={formState.value.age} {...formState.attribute.age} />
* {#if formState.result.age.errors.length}
* {#each formState.result.age.errors as error}
* <span>{error}</span>
* {/each}
* {/if}
* </div>
* </form>
* ```
* @template T - The Zod object schema defining the structure of the form.
* @template Initial - The initial values of the form state, inferred from the schema.
* @param {FormStateProps<T, Initial>} props - The configuration properties for the form state.
* @property {FormStateValue<Initial>} value - The current values of the form fields.
* @property {FormStateAttribute<T>} attribute - The attributes for each form field.
* @property {FormStateConfig<T>} result - The validation result for each form field.
* @property {Function} addErrors - Function to add errors to a specific form field.
* @property {Function} setValue - Function to set the value of a specific form field.
* @property {Function} validate - Function to validate a specific form field.
* @property {Function} validateAll - Function to validate the entire form.
*/
export declare function createFormState<T extends z.ZodObject<any>, Initial extends z.infer<T> = z.infer<T>>(props: FormStateProps<T, Initial>): {
value: Initial;
readonly attribute: FormStateAttribute<T> extends infer T_1 ? { [K in keyof T_1]: FormStateAttribute<T>[K]; } : never;
readonly result: FormStateConfig<T> extends infer T_1 ? { [K in keyof T_1]: FormStateConfig<T>[K]; } : never;
addErrors: (key: keyof z.infer<T>, errors: string[]) => void;
setValue: <K extends keyof Initial>(key: K, newValue: Initial[K], config?: {
validateFirst?: boolean;
addErrorIfInvalid: boolean;
}) => Initial[K] | undefined;
validate: (key: keyof z.infer<T>) => z.ZodSafeParseResult<Record<string, unknown>>;
validateAll: <ExtendedData extends Initial>(extendedData?: ExtendedData) => z.ZodSafeParseResult<z.core.output<T>>;
resetError: () => void;
setErrors: (newErrors: { [K in keyof Initial]?: string[]; }) => void;
};
export {};