import * as _remix_run_server_runtime from '@remix-run/server-runtime';
import { FetcherWithComponents, Form } from '@remix-run/react';
import React, { ComponentProps } from 'react';

type ValidationBehavior = "onBlur" | "onChange" | "onSubmit";
type ValidationBehaviorOptions = {
    initial: ValidationBehavior;
    whenTouched: ValidationBehavior;
    whenSubmitted: ValidationBehavior;
};
type HandledProps = "name" | "defaultValue" | "defaultChecked";
type Callbacks = "onChange" | "onBlur";
type MinimalInputProps = {
    onChange?: ((...args: any[]) => void) | undefined;
    onBlur?: ((...args: any[]) => void) | undefined;
    defaultValue?: any;
    defaultChecked?: boolean | undefined;
    name?: string | undefined;
    type?: string | undefined;
};
type GetInputProps = <T extends MinimalInputProps>(props?: Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>) => T;

/**
 * Returns whether or not the parent form is currently being submitted.
 * This is different from Remix's `useNavigation()` in that it
 * is aware of what form it's in and when _that_ form is being submitted.
 *
 * @param formId
 */
declare const useIsSubmitting: (formId?: string) => boolean;
/**
 * Returns whether or not the current form is valid.
 *
 * @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
 */
declare const useIsValid: (formId?: string) => boolean;
type FieldProps = {
    /**
     * The validation error message if there is one.
     */
    error?: string;
    /**
     * Clears the error message.
     */
    clearError: () => void;
    /**
     * Validates the field.
     */
    validate: () => void;
    /**
     * The default value of the field, if there is one.
     */
    defaultValue?: any;
    /**
     * Whether or not the field has been touched.
     */
    touched: boolean;
    /**
     * Helper to set the touched state of the field.
     */
    setTouched: (touched: boolean) => void;
    /**
     * Helper to get all the props necessary for a regular input.
     */
    getInputProps: GetInputProps;
};
/**
 * Provides the data and helpers necessary to set up a field.
 */
declare const useField: (name: string, options?: {
    /**
     * Allows you to configure a custom function that will be called
     * when the input needs to receive focus due to a validation error.
     * This is useful for custom components that use a hidden input.
     */
    handleReceiveFocus?: () => void;
    /**
     * Allows you to specify when a field gets validated (when using getInputProps)
     */
    validationBehavior?: Partial<ValidationBehaviorOptions>;
    /**
     * The formId of the form you want to use.
     * This is not necesary if the input is used inside a form.
     */
    formId?: string;
}) => FieldProps;
declare const useControlField: <T>(name: string, formId?: string) => readonly [T, (value: T) => void];
declare const useUpdateControlledField: (formId?: string) => (field: string, value: unknown) => void;

declare const FORM_DEFAULTS_FIELD: "__rvfInternalFormDefaults";

type FieldErrors = Record<string, string>;
type TouchedFields = Record<string, boolean>;
type GenericObject = {
    [key: string]: any;
};
type ValidatorError = {
    subaction?: string;
    formId?: string;
    fieldErrors: FieldErrors;
};
type ValidationErrorResponseData = {
    subaction?: string;
    formId?: string;
    fieldErrors: FieldErrors;
    repopulateFields?: unknown;
};
type BaseResult = {
    submittedData: GenericObject;
    formId?: string;
};
type ErrorResult = BaseResult & {
    error: ValidatorError;
    data: undefined;
};
type SuccessResult<DataType> = BaseResult & {
    data: DataType;
    error: undefined;
};
/**
 * The result when validating a form.
 */
type ValidationResult<DataType> = SuccessResult<DataType> | ErrorResult;
/**
 * The result when validating an individual field in a form.
 */
type ValidateFieldResult = {
    error?: string;
};
/**
 * A `Validator` can be passed to the `validator` prop of a `ValidatedForm`.
 */
type Validator<DataType> = {
    validate: (unvalidatedData: GenericObject) => Promise<ValidationResult<DataType>>;
    /**
     * @deprecated Will be removed in a future version of remix-validated-form
     */
    validateField?: (unvalidatedData: GenericObject, field: string) => Promise<ValidateFieldResult>;
};
type Valid<DataType> = {
    data: DataType;
    error: undefined;
};
type Invalid = {
    error: FieldErrors;
    data: undefined;
};
type CreateValidatorArg<DataType> = {
    validate: (unvalidatedData: GenericObject) => Promise<Valid<DataType> | Invalid>;
    validateField: (unvalidatedData: GenericObject, field: string) => Promise<ValidateFieldResult>;
};
type ValidatorData<T extends Validator<any>> = T extends Validator<infer U> ? U : never;

/**
 * Takes the errors from a `Validator` and returns a `Response`.
 * When you return this from your action, `ValidatedForm` on the frontend will automatically
 * display the errors on the correct fields on the correct form.
 *
 * You can also provide a second argument to `validationError`
 * to specify how to repopulate the form when JS is disabled.
 *
 * @example
 * ```ts
 * const result = validator.validate(await request.formData());
 * if (result.error) return validationError(result.error, result.submittedData);
 * ```
 */
declare function validationError(error: ValidatorError, repopulateFields?: unknown, init?: ResponseInit): _remix_run_server_runtime.TypedResponse<ValidationErrorResponseData>;
type FormDefaults = {
    [formDefaultsKey: `${typeof FORM_DEFAULTS_FIELD}_${string}`]: any;
};
type internal_FORM_DEFAULTS_FIELD = typeof FORM_DEFAULTS_FIELD;
declare const setFormDefaults: <DataType = any>(formId: string, defaultValues: Partial<DataType>) => FormDefaults;

type DeepPartial<T> = T extends object ? {
    [P in keyof T]?: DeepPartial<T[P]>;
} : T;
type SubactionData<DataType, Subaction extends string | undefined> = DataType & {
    subaction: Subaction;
};
type DataForSubaction<DataType, Subaction extends string | undefined> = Subaction extends string ? SubactionData<DataType, Subaction> extends undefined ? DataType : SubactionData<DataType, Subaction> : DataType;
type FormProps<DataType, Subaction extends string | undefined> = {
    /**
     * A `Validator` object that describes how to validate the form.
     */
    validator: Validator<DataType>;
    /**
     * A submit callback that gets called when the form is submitted
     * after all validations have been run.
     */
    onSubmit?: (data: DataForSubaction<DataType, Subaction>, event: React.FormEvent<HTMLFormElement>) => void | Promise<void>;
    /**
     * Allows you to provide a `fetcher` from Remix's `useFetcher` hook.
     * The form will use the fetcher for loading states, action data, etc
     * instead of the default form action.
     */
    fetcher?: FetcherWithComponents<any>;
    /**
     * Accepts an object of default values for the form
     * that will automatically be propagated to the form fields via `useField`.
     */
    defaultValues?: DeepPartial<DataForSubaction<DataType, Subaction>>;
    /**
     * A ref to the form element.
     */
    formRef?: React.RefObject<HTMLFormElement>;
    /**
     * An optional sub-action to use for the form.
     * Setting a value here will cause the form to be submitted with an extra `subaction` value.
     * This can be useful when there are multiple forms on the screen handled by the same action.
     */
    subaction?: Subaction;
    /**
     * Reset the form to the default values after the form has been successfully submitted.
     * This is useful if you want to submit the same form multiple times,
     * and don't redirect in-between submissions.
     */
    resetAfterSubmit?: boolean;
    /**
     * Normally, the first invalid input will be focused when the validation fails on form submit.
     * Set this to `false` to disable this behavior.
     */
    disableFocusOnError?: boolean;
} & Omit<ComponentProps<typeof Form>, "onSubmit">;
/**
 * The primary form component of `remix-validated-form`.
 */
declare function ValidatedForm<DataType extends {
    [fieldName: string]: any;
}, Subaction extends string | undefined>({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit, disableFocusOnError, method, replace, id, preventScrollReset, relative, encType, ...rest }: FormProps<DataType, Subaction>): JSX.Element;

/**
 * Used to create a validator for a form.
 * It provides built-in handling for unflattening nested objects and
 * extracting the values from FormData.
 */
declare function createValidator<T>(validator: CreateValidatorArg<T>): Validator<T>;

type FormContextValue = {
    /**
     * All the errors in all the fields in the form.
     */
    fieldErrors: FieldErrors;
    /**
     * Clear the errors of the specified fields.
     */
    clearError: (...names: string[]) => void;
    /**
     * Validate the specified field.
     */
    validateField: (fieldName: string) => Promise<string | null>;
    /**
     * The `action` prop of the form.
     */
    action?: string;
    /**
     * The `subaction` prop of the form.
     */
    subaction?: string;
    /**
     * Whether or not the form is submitting.
     */
    isSubmitting: boolean;
    /**
     * Whether or not a submission has been attempted.
     * This is true once the form has been submitted, even if there were validation errors.
     * Resets to false when the form is reset.
     */
    hasBeenSubmitted: boolean;
    /**
     * Whether or not the form is valid.
     */
    isValid: boolean;
    /**
     * The default values of the form.
     */
    defaultValues?: {
        [fieldName: string]: any;
    };
    /**
     * Register a custom focus handler to be used when
     * the field needs to receive focus due to a validation error.
     */
    registerReceiveFocus: (fieldName: string, handler: () => void) => () => void;
    /**
     * Any fields that have been touched by the user.
     */
    touchedFields: TouchedFields;
    /**
     * Change the touched state of the specified field.
     */
    setFieldTouched: (fieldName: string, touched: boolean) => void;
    /**
     * Validate the whole form and populate any errors.
     */
    validate: () => Promise<ValidationResult<unknown>>;
    /**
     * Clears all errors on the form.
     */
    clearAllErrors: () => void;
    /**
     * Resets the form.
     *
     * _Note_: The equivalent behavior can be achieved by calling formElement.reset()
     * or clicking a button element with `type="reset"`.
     */
    reset: () => void;
    /**
     * Submits the form, running all validations first.
     *
     * _Note_: This is equivalent to clicking a button element with `type="submit"` or calling formElement.submit().
     */
    submit: () => void;
    /**
     * Returns the current form values as FormData
     */
    getValues: () => FormData;
};
/**
 * Provides access to some of the internal state of the form.
 */
declare const useFormContext: (formId?: string) => FormContextValue;

type FieldArrayValidationBehavior = "onChange" | "onSubmit";
type FieldArrayValidationBehaviorOptions = {
    initial: FieldArrayValidationBehavior;
    whenSubmitted: FieldArrayValidationBehavior;
};
type FieldArrayItem<T> = {
    /**
     * The default value of the item.
     * This does not update as the field is changed by the user.
     */
    defaultValue: T;
    /**
     * A unique key for the item.
     * Use this as the key prop when rendering the item.
     */
    key: string;
};
type FieldArrayHelpers<Item = any> = {
    push: (item: Item) => void;
    swap: (indexA: number, indexB: number) => void;
    move: (from: number, to: number) => void;
    insert: (index: number, value: Item) => void;
    unshift: (value: Item) => void;
    remove: (index: number) => void;
    pop: () => void;
    replace: (index: number, value: Item) => void;
};
type UseFieldArrayOptions = {
    formId?: string;
    validationBehavior?: Partial<FieldArrayValidationBehaviorOptions>;
};
declare function useFieldArray<Item = any>(name: string, { formId, validationBehavior }?: UseFieldArrayOptions): [items: FieldArrayItem<Item>[], helpers: FieldArrayHelpers<any>, error: string | undefined];
type FieldArrayProps<Item> = {
    name: string;
    children: (items: FieldArrayItem<Item>[], helpers: FieldArrayHelpers<Item>, error: string | undefined) => React.ReactNode;
    formId?: string;
    validationBehavior?: FieldArrayValidationBehaviorOptions;
};
declare function FieldArray<Item = any>({ name, children, formId, validationBehavior, }: FieldArrayProps<Item>): JSX.Element;

export { BaseResult, CreateValidatorArg, ErrorResult, FieldArray, FieldArrayHelpers, FieldArrayProps, FieldErrors, FieldProps, FormContextValue, FormDefaults, FormProps, GenericObject, Invalid, SuccessResult, TouchedFields, Valid, ValidateFieldResult, ValidatedForm, ValidationErrorResponseData, ValidationResult, Validator, ValidatorData, ValidatorError, createValidator, internal_FORM_DEFAULTS_FIELD, setFormDefaults, useControlField, useField, useFieldArray, useFormContext, useIsSubmitting, useIsValid, useUpdateControlledField, validationError };
