/** * vapor-chamber - Form Bus * * v0.5.0 — Reactive form state management built on the command bus. * * createFormBus wraps a command bus around a typed form, giving you: * - Reactive values, errors, dirty, valid, and submitting state * - Per-field validation rules * - Full plugin pipeline on every form command (logger, throttle, authGuard, etc.) * - Undo/redo via the history plugin * * @example * const form = createFormBus({ * fields: { email: '', password: '' }, * rules: { * email: (v) => v.includes('@') ? null : 'Invalid email', * password: (v) => v.length >= 8 ? null : 'Too short', * }, * onSubmit: async (values) => await api.login(values), * }); * * form.set('email', 'user@example.com'); * await form.submit(); // runs validation, then onSubmit * form.reset(); // restores initial field values */ import type { Signal } from './signal'; import type { CommandBus, Plugin, PluginOptions } from './command-bus'; export type FormRules> = { [K in keyof T]?: (value: T[K], values: T) => string | null | Promise; }; export type FormBusOptions> = { /** Initial field values — also used as the reset target. */ fields: T; /** Per-field validation rules. Return a string on error, null on pass. */ rules?: FormRules; /** Called after successful validation on submit(). May be async. */ onSubmit?: (values: T) => void | Promise; /** * Create reactive signals for all form state (values, errors, isDirty, etc.). * Default: true. Set to false for headless / server-side / batch use cases * where reactivity is not needed — avoids 7 signal allocations per form. * When false, all Signal fields still work as plain get/set wrappers. */ reactive?: boolean; /** * Inject an external command bus instead of creating an isolated one. * When provided, form commands (formSet, formTouch, formReset, formValidate) * flow through this bus — making them visible to DevTools, metrics, logger, * and global listeners. * * @example * const bus = getCommandBus(); * const form = createFormBus({ fields: { email: '' }, bus }); * // formSet, formTouch, etc. now visible in setupDevtools() */ bus?: CommandBus; }; export type FormBus> = { /** Reactive current field values. */ values: Signal; /** Reactive per-field error messages. Empty when all fields pass. */ errors: Signal>>; /** Reactive set of fields the user has interacted with. */ touched: Signal>>; /** True when any field differs from its initial value. */ isDirty: Signal; /** True when no validation errors exist. */ isValid: Signal; /** True while onSubmit is in flight. */ isSubmitting: Signal; /** True while async validation is running. */ isValidating: Signal; /** True when either validating or submitting — use for disabling submit buttons. */ isBusy: Signal; /** Set a single field value and re-run validation. */ set(field: K, value: T[K]): void; /** Mark a field as touched (shows errors for that field). */ touch(field: K): void; /** Validate and call onSubmit. Returns true on success, false on validation failure. */ submit(): Promise; /** Reset all fields to their initial values and clear errors/touched state. */ reset(): void; /** Attach a plugin to the form's internal command bus. */ use(plugin: Plugin, options?: PluginOptions): void; /** The underlying command bus — for advanced use (DevTools, testing). */ bus: CommandBus; }; /** * createFormBus — reactive form state manager built on the command bus. * * All form mutations go through the internal bus, so plugins (logger, * throttle, authGuard, etc.) intercept them like any other command. */ export declare function createFormBus>(options: FormBusOptions): FormBus; //# sourceMappingURL=form.d.ts.map