import { FormState, UseFormStateReturn, UseFormWatch } from "react-hook-form"; import { FormGroup } from "../../core/form/form-groups"; /** * Callback function type for field value changes * * @template T - Form data type * @template K - Field key type * @param value - Current field value * @param previousValue - Previous field value (undefined if first change) * @param groupIndex - Index of the group containing the field * @param formData - Complete form data */ export type FieldWatchCallback = ( value: T[K], previousValue: T[K] | undefined, groupIndex: number, formData: { groups: FormGroup[] } ) => void; /** * Configuration for field watching * * @template T - Form data type * @template K - Field key type */ export interface FieldWatchConfig { /** * Field name to watch */ field: K; /** * Optional group index to limit watching to a specific group * If not provided, watches the field across all groups */ groupIndex?: number; /** * Callback function triggered when field value changes */ callback: FieldWatchCallback; /** * Debounce time in milliseconds * Useful for expensive operations or to limit API calls */ debounce?: number; /** * Whether to trigger the callback immediately with current value * @default false */ immediate?: boolean; } /** * Field watcher manager return type * * @template T - Form data type */ export interface FieldWatcherReturn { /** * Register a new field watcher * * @returns Unsubscribe function to remove the watcher * * @example * // Watch a specific field in all groups * const unsubscribe = watchField({ * field: 'email', * callback: (value, prevValue, groupIndex) => { * console.log(`Email changed to ${value} in group ${groupIndex}`); * } * }); * * // Later, when no longer needed * unsubscribe(); */ watchField: (config: FieldWatchConfig) => () => void; /** * Register multiple field watchers at once * * @returns Function to unsubscribe all registered watchers * * @example * // Watch multiple fields * const unsubscribeAll = watchFields([ * { * field: 'firstName', * callback: (value) => updateDisplayName(value) * }, * { * field: 'email', * callback: (value) => validateEmailAsync(value), * debounce: 500 * } * ]); */ watchFields: (configs: FieldWatchConfig[]) => () => void; /** * Get the current value of a field * * @example * const email = getFieldValue('email', 0); // Get email from first group */ getFieldValue: (field: K, groupIndex: number) => T[K] | undefined; /** * Manually trigger callbacks for a specific field * Useful when you need to force an update */ triggerFieldWatch: (field: K, groupIndex?: number) => void; } /** * Handler for form state changes * * @template T - Form data type */ export type FormStateChangeHandler = ( state: UseFormStateReturn<{ groups: FormGroup[] }>, previousState: Partial[] }>> | null ) => void; /** * Form state subscription object */ export interface FormStateSubscription { /** * Unsubscribe from form state changes */ unsubscribe: () => void; } /** * Configuration options for form state observer * * @template T - Form data type */ export interface FormStateObserverOptions { /** * Called on any form state change */ onChange?: FormStateChangeHandler; /** * Called when form dirty state changes * Useful for auto-save functionality */ onDirtyChange?: (isDirty: boolean) => void; /** * Called when form errors change * Useful for custom error handling or analytics */ onErrorsChange?: (hasErrors: boolean, errors: Record) => void; /** * Called when form submit count changes * Useful for tracking submission attempts */ onSubmitCountChange?: (submitCount: number) => void; /** * Called when touched fields change * Useful for progressive validation */ onTouchedChange?: ( isTouched: boolean, touchedFields: UseFormStateReturn<{ groups: FormGroup[] }>['touchedFields'] ) => void; /** * Called when form becomes valid or invalid */ onValidChange?: (isValid: boolean) => void; /** * Called when form submission state changes */ onSubmittingChange?: (isSubmitting: boolean) => void; } /** * Form state observer return type * * @template T - Form data type */ export interface FormStateObserverReturn { /** * Subscribe to form state changes * * @returns Subscription object with unsubscribe method * * @example * const subscription = formStateObserver.subscribe((state, prevState) => { * if (state.isDirty && !prevState?.isDirty) { * saveFormDraft(form.getValues()); * } * }); * * // Later, when no longer needed * subscription.unsubscribe(); */ subscribe: (handler: FormStateChangeHandler) => FormStateSubscription; /** * Get current form state */ getState: () => UseFormStateReturn<{ groups: FormGroup[] }>; /** * Get previous form state */ getPreviousState: () => Partial[] }>> | null; /** * Check if form is currently dirty */ isDirty: () => boolean; /** * Check if form has any errors */ hasErrors: () => boolean; /** * Check if form is currently being submitted */ isSubmitting: () => boolean; /** * Check if form is valid */ isValid: () => boolean; } /** * Combined return type for React Hook Form enhanced features * * @template T - Form data type */ export interface ReformHookFormEnhancementsReturn { /** * Field watcher functionality */ fieldWatcher: FieldWatcherReturn; /** * Form state observer functionality */ stateObserver: FormStateObserverReturn; }