Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@rvf/react

Package Overview
Dependencies
Maintainers
1
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rvf/react - npm Package Compare versions

Comparing version
8.1.1
to
8.1.2
+758
dist/index.d.mts
import { FormScope, FieldArrayValidationBehaviorConfig, ValidationBehaviorConfig, SubmitStatus, SubmitterOptions, FieldValues, NonContradictingSupertype, Validator, BeforeSubmitApi, FieldErrors, experimental_FormEventListener, StateSubmitHandler, DomSubmitHandler } from '@rvf/core';
export { BeforeSubmitApi, CreateValidatorArg, DomSubmitHandler, FieldArrayValidationBehavior, FieldArrayValidationBehaviorConfig, FieldErrors, FieldValue, FieldValues, FormScope, Invalid, MultiFileInputValue, NativeValueByType, NumberInputValue, ScopedValues, SingleFileInputValue, StateSubmitHandler, SubmitStatus, Valid, ValidationBehavior, ValidationBehaviorConfig, ValidationErrorResponseData, ValidationResult, Validator, ValidatorData, ValidatorError, ValueOfInputType, getOriginalObject, isValidationErrorResponse, parseFormData, preprocessFormData } from '@rvf/core';
import { ValidStringPaths, ValueAtPath, StringToPathTuple, ValidStringPathsToArrays } from '@rvf/set-get';
import { RefCallback, LegacyRef, ComponentProps, PropsWithChildren, RefObject, ReactNode } from 'react';
import { StandardSchemaV1 } from '@standard-schema/spec';
import * as react_jsx_runtime from 'react/jsx-runtime';
interface FieldArrayApi<FormInputData extends Array<any>> {
/**
* Normally, when a user submits a form and it contains validation error,
* the first invalid element in the form will be focused.
* Pass this ref to a focusable element to simulate this behavior when there are array-level errors
* for this field array.
*/
errorFocusElement: RefCallback<HTMLElement>;
/**
* Gets field name of the array.
*/
name: () => string;
/**
* Gets the error message for the array itself, if any.
*/
error: () => string | null;
/**
* Gets the length of the array.
* @willRerender
*/
length: () => number;
/**
* Returns an array of the keys used when mapping over the array.
* The identity of the array is stable and only updates (and causes a rerender)
* when the number of items in the array changes, or the array is reset.
* This is usually not necesary, but can be useful for some advanced scenarios.
*/
keys: () => string[];
/**
* Maps over and renders the array items.
* Using the `form` parameter passed to the callback will isolate rerenders to each individual item.
* Changes to the length of the array will also be isoated to this `map` call.
*/
map: <Value>(callback: (key: string, form: FormApi<FormInputData[number]>, index: number) => Value) => Value[];
/**
* Adds an item to the array. Just like `Array.push`.
*/
push: (value: FormInputData[number]) => Promise<void>;
/**
* Pops the last item in the array. Similar to `Array.pop`.
*/
pop: () => Promise<void>;
/**
* Removes the first item in the array. Similar to `Array.shift`.
*/
shift: () => Promise<void>;
/**
* Inserts an item at the start of the array. Just like `Array.unshift`.
*/
unshift: (value: FormInputData[number]) => Promise<void>;
/**
* Inserts an item at a specific index in the array.
*/
insert: (index: number, value: FormInputData[number]) => Promise<void>;
/**
* Moves an item from `fromIndex` to `toIndex` in the array.
* This process happens by removing the item at `fromIndex` and inserting it at `toIndex`.
* Keep this in mind if your `toIndex` is after the `fromIndex`.
*/
move: (fromIndex: number, toIndex: number) => Promise<void>;
/**
* Removes an item from the array.
*/
remove: (index: number) => Promise<void>;
/**
* Swaps the items at `fromIndex` and `toIndex` in the array.
*/
swap: (fromIndex: number, toIndex: number) => Promise<void>;
/**
* Replaces an item in the array.
* The new value will be treated as a new field, which will reset any `touched`, `dirty`, or `validationErrors` for the item.
* It will also generate a new key for the item.
*/
replace: (index: number, value: FormInputData[number]) => Promise<void>;
}
type UseFieldArrayOpts = {
validationBehavior?: FieldArrayValidationBehaviorConfig;
};
declare function useFieldArray<FormInputData extends any[]>(form: FormScope<FormInputData>, { validationBehavior }?: UseFieldArrayOpts): FieldArrayApi<FormInputData>;
declare function useFieldArray<FormInputData extends any[] = unknown[]>(name: string, opts?: UseFieldArrayOpts): FieldArrayApi<FormInputData>;
type FieldArrayPropsWithScope<FormInputData extends any[]> = {
scope: FormScope<FormInputData>;
children: (field: FieldArrayApi<FormInputData>) => React.ReactNode;
};
type FieldArrayPropsWithName<FormInputData extends any[]> = {
name: string;
children: (field: FieldArrayApi<FormInputData>) => React.ReactNode;
};
declare function FieldArray<FormInputData extends any[] = unknown[]>(props: FieldArrayPropsWithName<FormInputData> | FieldArrayPropsWithScope<FormInputData>): React.ReactNode;
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;
ref?: LegacyRef<any>;
value?: string | number | readonly string[];
form?: string;
};
type ValidInputPropsValues = string | string[] | number | boolean;
type GetInputPropsParam<T extends MinimalInputProps> = Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>;
type GetInputProps = <T extends MinimalInputProps>(props?: GetInputPropsParam<T>) => T;
type GetControlPropsParam<FieldValue> = {
onChange?: (value: FieldValue) => void;
onBlur?: () => void;
};
type GetControlPropsResult<FieldValue> = {
name: string;
onChange: (value: FieldValue) => void;
onBlur: () => void;
value: FieldValue;
ref: RefCallback<HTMLElement>;
};
type GetHiddenInputPropsParam<FieldValue> = {
serialize?: (value: FieldValue) => string;
};
type GetHiddenInputPropsResult = {
name: string;
value: string;
type: "hidden";
form: string;
ref: RefCallback<HTMLInputElement>;
};
interface FieldApi<FormInputData> {
/**
* Returns props that can be spread onto native form controls or thin wrappers around them.
* It's important that the component you spread the props into accepts the `ref` prop.
* This allows the field to be focused when it has an error and also disables RVF's default
* behavior of automatically listening to changes in the field.
*/
getInputProps: GetInputProps;
/**
* Returns props that can be spread into controlled components to use as a field.
* It's important to pass the provided `ref` to something with a `focus` method.
* This allows the field to be focused when it has an error and also disables RVF's default
* behavior of automatically listening to changes in the field.
*/
getControlProps: (props?: GetControlPropsParam<FormInputData>) => GetControlPropsResult<FormInputData>;
/**
* Returns props that can be spread into a native form control to use as a hidden field.
* This is useful in combination with `getControlProps`.
*/
getHiddenInputProps: (opts?: GetHiddenInputPropsParam<FormInputData>) => GetHiddenInputPropsResult;
refs: {
controlled: () => RefCallback<HTMLElement>;
transient: () => RefCallback<HTMLElement>;
};
/**
* Gets the name of the field.
*/
name: () => string;
onChange: (value: FormInputData) => void;
onBlur: () => void;
value(): FormInputData;
setValue(value: FormInputData): void;
defaultValue(): FormInputData;
touched(): boolean;
setTouched(value: boolean): void;
dirty(): boolean;
setDirty(value: boolean): void;
error(): string | null;
clearError(): void;
reset(opts?: ResetFieldOpts<FormInputData>): void;
validate(): void;
}
type UseFieldOpts = {
validationBehavior?: ValidationBehaviorConfig;
};
type ScopeData<Scope> = Scope extends FormScope<infer Data> ? Data : never;
declare function useField<Scope extends FormScope<any>>(form: Scope, { validationBehavior }?: UseFieldOpts): FieldApi<ScopeData<Scope>>;
declare function useField<FormInputData = unknown>(name: string, opts?: UseFieldOpts): FieldApi<FormInputData>;
type FieldPropsWithScope<FormInputData> = {
scope: FormScope<FormInputData>;
children: (field: FieldApi<FormInputData>) => React.ReactNode;
};
type FieldPropsWithName<FormInputData> = {
name: string;
children: (field: FieldApi<FormInputData>) => React.ReactNode;
};
declare function Field<FormInputData = unknown>(props: FieldPropsWithName<FormInputData> | FieldPropsWithScope<FormInputData>): React.ReactNode;
type MinimalFormApi<FieldPaths extends string> = {
dirty: (fieldName?: FieldPaths) => boolean;
};
type FormFields<Form> = Form extends MinimalFormApi<infer FieldPaths> ? FieldPaths : never;
interface FormProps {
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
onReset: (event: React.FormEvent<HTMLFormElement>) => void;
ref: React.Ref<HTMLFormElement>;
id: string;
action?: string;
}
type ManualSubmitOption = SubmitterOptions & {
name?: string;
value?: string;
};
type FormState = {
isSubmitting: boolean;
hasBeenSubmitted: boolean;
submitStatus: SubmitStatus;
isValid: boolean;
isDirty: boolean;
isTouched: boolean;
touchedFields: Record<string, boolean>;
dirtyFields: Record<string, boolean>;
fieldErrors: Record<string, string>;
};
type ResetFieldOpts<FieldValue> = {
/**
* This will update the `defaultValue` of the field to the new value.
* If you call `resetForm`, this will overwrite any changes made by `resetField`.
*/
defaultValue?: FieldValue;
/**
* When this is true, resetting the field won't clear any errors on the field.
*/
keepError?: boolean;
};
type NonUndefined<T> = Exclude<T, undefined>;
type MutableArray<T> = T extends readonly (infer Item)[] ? Item[] : T;
interface FormApi<FormInputData> {
/**
* Gets whether the field has been touched.
* @willRerender
*/
touched: (fieldName?: ValidStringPaths<FormInputData>) => boolean;
/**
* Gets whether the field has been dirty.
* @willRerender
*/
dirty: (fieldName?: ValidStringPaths<FormInputData>) => boolean;
/**
* Gets the current error for the field if any.
* @willRerender
*/
error: (fieldName?: ValidStringPaths<FormInputData>) => string | null;
/**
* Gets the current value of the entire form.
* If using a scoped form, this will be the value of the scoped form.
* @willRerender
*/
value(): FormInputData;
/**
* Gets the current value of the specified field.
* @willRerender
*/
value<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): ValueAtPath<FormInputData, StringToPathTuple<Field>>;
/**
* Gets the default value of the entire form.
* If using a scoped form, this will be the value of the scoped form.
* @willRerender
*/
defaultValue(): FormInputData;
/**
* Gets the default value of the specified field.
* @willRerender
*/
defaultValue<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): ValueAtPath<FormInputData, StringToPathTuple<Field>>;
/**
* State accessors that always return the latest value and don't cause rerenders.
* This is mostly useful for event handlers.
*/
transient: {
/**
* Gets whether the field has been touched.
*/
touched: (fieldName?: ValidStringPaths<FormInputData>) => boolean;
/**
* Gets whether the field has been dirty.
*/
dirty: (fieldName?: ValidStringPaths<FormInputData>) => boolean;
/**
* Gets the current error for the field if any.
*/
error: (fieldName?: ValidStringPaths<FormInputData>) => string | null;
/**
* Gets the current value of the entire form.
* If using a scoped form, this will be the value of the scoped form.
*/
value(): FormInputData;
/**
* Gets the current value of the specified field.
*/
value<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): ValueAtPath<FormInputData, StringToPathTuple<Field>>;
/**
* Gets the default value of the entire form.
* If using a scoped form, this will be the value of the scoped form.
*/
defaultValue(): FormInputData;
/**
* Gets the default value of the specified field.
*/
defaultValue<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): ValueAtPath<FormInputData, StringToPathTuple<Field>>;
formState: FormState;
};
formOptions: {
action?: string;
formId: string;
};
formState: FormState;
/**
* Various subscription helpers. These should be used in an effect and do not cause rerenders.
*/
subscribe: {
/**
* Subscribes to any change in the values of the form, or the value in scope.
* @returns A function that can be called to unsubscribe.
* @example `useEffect(() => form.subscribe.value(console.log), [])`
*/
value(callback: (values: FormInputData) => void): () => void;
/**
* Subscribes to any change in value of the specified field.
* @returns A function that can be called to unsubscribe.
* @example `useEffect(() => form.subscribe.value('myfield', console.log), [])`
*/
value<Field extends ValidStringPaths<FormInputData>>(fieldName: Field, callback: (values: ValueAtPath<FormInputData, StringToPathTuple<Field>>) => void): () => void;
};
/**
* Focus the field with the specified name.
* This only works if the `ref` provided by `getInputProps` or `getControlProp` was passed to a focusable element.
*/
focus: (fieldName: ValidStringPaths<FormInputData>) => void;
/**
* Sets the value of the field with the specified name.
* This works for both controlled and uncontrolled fields.
* For uncontrolled fields, this will manually set the value of the form control using the `ref` returned by `getInputProps`.
*/
setValue<Field extends ValidStringPaths<FormInputData>>(fieldName: Field, value: ValueAtPath<FormInputData, StringToPathTuple<Field>>): void;
/**
* Sets the value of the entire scope of this form.
* This is most useful when using an already scoped form.
*/
setValue(value: FormInputData): void;
/**
* Set the dirty state of the specified field.
*/
setDirty(fieldName: ValidStringPaths<FormInputData>, value: boolean): void;
/**
* Set the dirty state of the field in scope.
*/
setDirty(value: boolean): void;
/**
* Set the touched state of the specified field.
*/
setTouched(fieldName: ValidStringPaths<FormInputData>, value: boolean): void;
/**
* Set the touched state of the field in scope.
*/
setTouched(value: boolean): void;
/**
* @unstable This API may change
*
* Sets a custom error message on the specified field.
* By using this, you're taking manual control of the validation lifecycle for this particular error message.
*
* When a field has a custom error message, it will always be displayed, regardless of the field's touched state.
* Custom errors are not cleared until you explicitly clear them.
* Clear custom errors by calling this helper again with `null` as the error.
*
* When a form with a custom error message is submitted, `onBeforeSubmit` will be called, but `onSubmit` will not.
* This gives you a chance to re-check your custom validation and maybe clear it.
* If you don't clear the error in `onBeforeSubmit` or explicitly call `performSubmit`, then the submit will fail and `onInvalidSubmit` will be called.
*/
unstable_setCustomError(fieldName: ValidStringPaths<FormInputData>, error: string | null): void;
/**
* @unstable This API may change
*
* Sets a custom error message on the field in scope.
* By using this, you're taking manual control of the validation lifecycle for this particular error message.
*
* When a field has a custom error message, it will always be displayed, regardless of the field's touched state.
* Custom errors are not cleared until you explicitly clear them.
* Clear custom errors by calling this helper again with `null` as the error.
*
* When a form with a custom error message is submitted, `onBeforeSubmit` will be called, but `onSubmit` will not.
* This gives you a chance to re-check your custom validation and maybe clear it.
* If you don't clear the error in `onBeforeSubmit` or explicitly call `performSubmit`, then the submit will fail and `onInvalidSubmit` will be called.
*/
unstable_setCustomError(error: string | null): void;
/**
* Clears the error of the specified field.
*/
clearError(fieldName: ValidStringPaths<FormInputData>): void;
/**
* Set the current error of the field in scope.
*/
clearError(): void;
/**
* Manually validates the form.
* You usually don't need to do this.
*/
validate: () => Promise<Record<string, string>>;
/**
* Resets the form to its initial state.
* All fields will be reset to their initial values.
* All touched, dirty, and validation errors will be reset.
* Optionally, you can provide new initial values to reset.
*/
resetForm: (nextValues?: FormInputData) => void;
/**
* Resets the field with the specified name to its initial value.
* This also resets any touched, dirty, or validation errors for the field.
* This works for both controlled and uncontrolled fields.
* For uncontrolled fields, this will manually set the value of the form control using the `ref` returned by `field`.
*/
resetField<FieldName extends ValidStringPaths<FormInputData>>(fieldName: FieldName, opts?: ResetFieldOpts<ValueAtPath<FormInputData, StringToPathTuple<FieldName>>>): void;
/**
* Resets the currently in-scope field with the specified name to its initial value.
* This also resets any touched, dirty, or validation errors for the field.
* This works for both controlled and uncontrolled fields.
* For uncontrolled fields, this will manually set the value of the form control using the `ref` returned by `field`.
*
* Optionally, you can pass a default value to reset to.
* This will reset cause `form.defaultValue('myField')` to return the new default value,
* and for `form.dirty('myField')` to return use this new default for comparison.
*
* Calling `resetForm` will undo any default value changes made by `resetField`.
*/
resetField(opts?: ResetFieldOpts<FormInputData>): void;
/**
* Creates an `FormScope` scoped to the specified field.
* This is useful for creating subforms.
* In order to use this, you can pass it to `useForm`.
*
* @example
* ```tsx
* type PersonFormProps = {
* rvf: FormScope<{ name: string }>;
* }
*
* const PersonForm = ({ rvf }: PersonFormProps) => {
* const form = useForm(rvf);
* return (
* <div>
* <MyInputField lable="Name" {...personForm.field('name')} />
* </div>
* );
* };
*
* const LargerForm = () => {
* const form = useForm({
* defaultValues: {
* person: {
* name: "",
* },
* },
* // ... other options
* });
* return (
* <div>
* <PersonForm rvf={form.scope('person')} />
* </div>
* );
* }
* ```
*/
scope<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): FormScope<ValueAtPath<FormInputData, StringToPathTuple<Field>>>;
/**
* Returns an `FormScope` without scoping any further.
*/
scope(): FormScope<FormInputData>;
/**
* You should call this in every form you have and pass the result to your form element.
*
* @example
* ```tsx
* const form = useForm({
* // ...
* });
*
* return (
* <form {...form.getFormProps()}>
* <YourFormElements />
* </form>
* );
* ```
*/
getFormProps: (props?: Partial<FormProps>) => FormProps;
/**
* Get array helpers for the form.
* This is only useful if you're using a form that has been scoped to an array.
*/
array(_no_args: FormInputData extends Array<any> ? void : never): FormInputData extends Array<any> ? FieldArrayApi<FormInputData> : never;
/**
* Get array helpers for the specified field array.
*/
array<Field extends ValidStringPathsToArrays<FormInputData>>(fieldName: Field): MutableArray<NonUndefined<ValueAtPath<FormInputData, StringToPathTuple<Field>>>> extends Array<any> ? FieldArrayApi<MutableArray<NonUndefined<ValueAtPath<FormInputData, StringToPathTuple<Field>>>>> : never;
/**
* Get the name of the specified field.
*/
name<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): string;
/**
* Get the name of the current field in scope.
*/
name(): string;
/**
* Returns props that can be spread onto native form controls or thin wrappers around them.
* It's generally recommended to use this with native form controls.
* And pass any other props through this helper.
*
* It's important that the component you spread the props into accepts the `ref` prop.
* This allows RVF to set the value of the field when setValue is called, and is used
* to focus the field when it has an error.
*
* @example
* ```tsx
* <input {...form.getInputProps("myField", { type: "number" })} />
* ```
*/
getInputProps: <Field extends ValidStringPaths<FormInputData, ValidInputPropsValues>, T extends MinimalInputProps>(fieldName: Field, props?: GetInputPropsParam<T>) => T;
/**
* Returns props that can be spread into controlled components to use as a field.
* It's important to pass the provided `ref` to something with a `focus` method.
* This allows the field to be focused when it has an error and also disables RVF's default
* behavior of automatically listening to changes in the field.
* @willRerender
*/
getControlProps: <Field extends ValidStringPaths<FormInputData>>(name: Field, props?: GetControlPropsParam<ValueAtPath<FormInputData, StringToPathTuple<Field>>>) => GetControlPropsResult<ValueAtPath<FormInputData, StringToPathTuple<Field>>>;
/**
* Returns props that can be spread into a native form control to use as a hidden field.
* This is useful in combination with `getControlProps`.
* @willRerender
*/
getHiddenInputProps: <Field extends ValidStringPaths<FormInputData>>(name: Field, opts?: GetHiddenInputPropsParam<ValueAtPath<FormInputData, StringToPathTuple<Field>>>) => GetHiddenInputPropsResult;
/**
* Get field helpers for the specified field.
*/
field<Field extends ValidStringPaths<FormInputData>>(fieldName: Field): FieldApi<ValueAtPath<FormInputData, StringToPathTuple<Field>>>;
/**
* Get field helpers for the field in scope.
* This is only useful if you're using a form that has been scoped to a single field.
*/
field(): FieldApi<FormInputData>;
/**
* Pass this to your form's `onSubmit` handler.
*/
submit: (option?: ManualSubmitOption) => void;
/**
* Renders a hidden input that sets passes the form id to your server.
* This is only useful if you're supporting users who don't have JS enabled
* and you're returning validation errors from your server.
*/
renderFormIdInput: () => React.ReactNode;
}
type FormSubmitOpts<FormOutputData, ResponseData> = {
submitSource: "state";
handleSubmit: StateSubmitHandler<FormOutputData, ResponseData>;
} | {
submitSource?: "dom";
handleSubmit?: DomSubmitHandler<FormOutputData, ResponseData>;
};
type internal_BaseFormOpts<FormInputData extends FieldValues = FieldValues, FormOutputData = never, SubmitResponseData = unknown> = {
/**
* Called before when the form is submitted before any validations are run.
* Can be used to run custom, async validations and/or cancel the form submission.
*/
onBeforeSubmit?: (beforeSubmitApi: BeforeSubmitApi<FormInputData, FormOutputData>) => void | Promise<void>;
/**
* Called after the form has been successfully submitted with whatever data was returned from the `handleSubmit` function.
* Can be useful for showing a toast message or redirecting the user to a different page.
* If you return a `Promise` from this callback, the `isSubmitting` state will still be `true` while this callback is running.
*
* If you're using an adapter like `@rvf/react-router`, this will be called even if you aren't using `handleSubmit`.
*/
onSubmitSuccess?: (handleSubmitResponse: NoInfer<SubmitResponseData>) => void | Promise<void>;
/**
* Called when the `handleSubmit` function throws an error.
* Can be useful for showing a toast message or redirecting the user to a different page.
* If you return a `Promise` from this callback, the `isSubmitting` state will still be `true` while this callback is running.
*
* If you're using an adapter like `@rvf/react-router`, this will be called even if you aren't using `handleSubmit`.
*/
onSubmitFailure?: (error: unknown) => void | Promise<void>;
/**
* Called when the user attempts to submit the form with invalid data.
* This is called after the first invalid field is focused.
* Can be useful if you want to take deeper control over how you handle invalid forms.
*/
onInvalidSubmit?: () => void | Promise<void>;
/**
* A shortcut setting that resets the form to the default values after the form has been successfully submitted.
* This is equivalent to calling `resetForm` in the `onSubmitSuccess` callback.
*/
resetAfterSubmit?: boolean;
/**
* Allows you to customize the validation behavior of the form.
*/
validationBehaviorConfig?: ValidationBehaviorConfig;
/**
* The action prop of the form element.
* This will be automatically set on the form element if you use `getFormProps`.
*/
action?: string;
/**
* The id of the form element.
* This will be automatically set on the form element if you use `getFormProps`.
*/
id?: string;
/**
* Disables the default behavior of focusing the first invalid field when a submit fails due to validation errors.
*/
disableFocusOnError?: boolean;
/**
* When set to true, a valid form will be submitted natively with a full page reload.
* _Note_: This is only supported in the `dom` submit source.
*/
reloadDocument?: boolean;
/**
* Optionally, you can pass other props to the form element here.
* This is primarily useful for writing custom hooks around `useForm`.
* For most use-cases, you can simply pass the props directly to the form element.
*/
otherFormProps?: Omit<ComponentProps<"form">, "id" | "action">;
/**
* Can be used to set the default errors of the entire form.
* This is most useful went integrating with server-side validation.
*
* **CAREFUL**: this will cause an update every time the identity of `serverValidationErrors` changes.
* So make sure the identity of `serverValidationErrors` is stable.
*/
serverValidationErrors?: FieldErrors;
experimental_eventListener?: experimental_FormEventListener;
};
type internal_ValidatorAndDefaultValueOpts<SchemaInput extends FieldValues, SchemaOutput, DefaultValues extends FieldValues, FormInputData extends FieldValues> = ({
/**
* A validator object created by a validation adapter such a `withZod` or `withYup`.
* See [these docs](https://rvf-js.io/validation-library-support) for more details
* and information on how to create a validator for other validation libraries.
*
* This option is soft-deprecated. For libraries that support Standard Schema,
* we recommend passing the schema directly to the `schema` option.
* For `yup`, the `withYup` adapter will eventually return a Standard Schema intead of a custom validator.
* If you have a custom adapter, we recommend using this approach as well, if the library doesn't support Standard Schema.
*/
validator: Validator<SchemaOutput>;
/**
* Sets the default values of the form.
*
* For Typescript users, `defaultValues` is one of the most important props you'll use.
* The type of the object you pass here, will determine the type of the data you get
* when interacting with the form. For example, `form.value('myField')` will be typed based on
* the type of `defaultValues.myField`.
*
* It's recommended that you provide a default value for every field in the form.
*/
defaultValues?: FormInputData;
} & {
schema?: never;
}) | ({
/**
* A [Standard Schema](https://standardschema.dev/) compliant schema.
* The input type of this schema will be used to help make `defaultValues` typesafe,
* as well as determine the types when using the `FormApi` returned from this hook.
*/
schema: StandardSchemaV1<SchemaInput, SchemaOutput>;
} & {
/**
* Sets the default values of the form.
*
* For Typescript users, `defaultValues` is one of the most important props you'll use.
* The type of the object you pass here, will determine the type of the data you get
* when interacting with the form. For example, `form.value('myField')` will be typed based on
* the type of `defaultValues.myField`.
*
* It's recommended that you provide a default value for every field in the form.
*/
defaultValues: NonContradictingSupertype<SchemaInput, Readonly<DefaultValues>>;
});
type FormOpts<SchemaInput extends FieldValues = any, SchemaOutput = unknown, SubmitResponseData = unknown, DefaultValues extends FieldValues = SchemaInput, FormInputData extends FieldValues = NonContradictingSupertype<SchemaInput, DefaultValues>> = internal_ValidatorAndDefaultValueOpts<SchemaInput, SchemaOutput, DefaultValues, FormInputData> & internal_BaseFormOpts<NoInfer<FormInputData>, NoInfer<SchemaOutput>, SubmitResponseData> & FormSubmitOpts<NoInfer<SchemaOutput>, SubmitResponseData>;
/**
* Create and use a `FormScope`.
*/
declare function useForm<SchemaInput extends FieldValues = any, SchemaOutput = unknown, SubmitResponseData = unknown, const DefaultValues extends FieldValues = SchemaInput, FormInputData extends FieldValues = NonContradictingSupertype<SchemaInput, DefaultValues>>(options: FormOpts<SchemaInput, SchemaOutput, SubmitResponseData, DefaultValues, FormInputData>): FormApi<FormInputData>;
type ValidatedFormProps<SchemaInput extends FieldValues, SchemaOutput, SubmitResponseData = unknown, DefaultValues extends FieldValues = SchemaInput, FormInputData extends FieldValues = NonContradictingSupertype<SchemaInput, DefaultValues>> = FormOpts<SchemaInput, SchemaOutput, SubmitResponseData, DefaultValues, FormInputData> & Omit<React.ComponentProps<"form">, "children"> & {
/**
* A ref to the form element.
*/
formRef?: React.RefObject<HTMLFormElement>;
children: React.ReactNode | ((form: FormApi<FormInputData>) => React.ReactNode);
};
declare const ValidatedForm: <SchemaInput extends FieldValues, SchemaOutput, SubmitResponseData = unknown, const DefaultValues extends FieldValues = SchemaInput, FormInputData extends FieldValues = NonContradictingSupertype<SchemaInput, DefaultValues>>(props: ValidatedFormProps<SchemaInput, SchemaOutput, SubmitResponseData, DefaultValues, FormInputData>) => react_jsx_runtime.JSX.Element;
type FormProviderProps = {
scope: FormScope<any>;
};
declare const FormProvider: ({ scope, children, }: PropsWithChildren<FormProviderProps>) => react_jsx_runtime.JSX.Element;
declare const useFormContext: <TData>() => FormApi<TData>;
declare const useFormScopeOrContext: <TData>(rvf?: FormScope<TData>) => FormApi<TData>;
/**
* Interprets an `FormScope` created via `form.scope`, for use in a subcomponent.
*/
declare function useFormScope<FormInputData>(form: FormScope<FormInputData>): FormApi<FormInputData>;
declare const useNativeValidity: (ref: RefObject<(HTMLElement & {
setCustomValidity: (error: string) => void;
}) | null>, error?: string | null) => void;
/**
* Automatically sets the validity of all form controls in the form using the
* native HTML `setCustomValidity` method.
*
* If you need more granular control over which fields use this method,
* you can pass a form scope for a deeper part of the form (e.g. `useNativeValidityForForm(form.scope("subform"))`).
* Or you can use `useNativeValidity` instead for inputs.
*/
declare const useNativeValidityForForm: (scope: FormScope<any>) => void;
declare const Isolate: <FormValue>({ scope, render, }: {
scope: FormScope<FormValue>;
render: (scope: FormApi<FormValue>) => ReactNode;
}) => ReactNode;
/**
* 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.
*
* Can optionally accept an `FormScope` to grab the data from that instead.
*
* @deprecated Provided for backwards compatibility with `remix-validated-form`.
* You can instead get this data directly off of the `useForm` hook.
*/
declare const useIsSubmitting: (rvf?: FormScope<any>) => boolean;
/**
* Returns whether or not the current form is valid.
*
* Can optionally accept an `FormScope` to grab the data from that instead.
*
* @deprecated Provided for backwards compatibility with `remix-validated-form`.
* You can instead get this data directly off of the `useForm` hook.
*/
declare const useIsValid: (rvf?: FormScope<any>) => boolean;
/**
* @deprecated Can get the value and set the value directly off of the `useForm` hook.
*/
declare const useControlField: <T>(name: string, rvf?: FormScope<any>) => readonly [T, (value: T) => void];
/**
* @deprecated Can set the value directly off of the `useForm` hook.
*/
declare const useUpdateControlledField: (rvf?: FormScope<any>) => (name: string, value: any) => void;
declare const createFormScope: <SchemaInput extends FieldValues = any, SchemaOutput = unknown, SubmitResponseData = unknown, const DefaultValues extends FieldValues = SchemaInput, FormInputData extends FieldValues = NonContradictingSupertype<SchemaInput, DefaultValues>>(options: FormOpts<SchemaInput, SchemaOutput, SubmitResponseData, DefaultValues, FormInputData>) => FormScope<FormInputData>;
export { Field, type FieldApi, FieldArray, type FieldArrayApi, type FieldArrayPropsWithName, type FieldArrayPropsWithScope, type FieldPropsWithName, type FieldPropsWithScope, type FormApi, type FormFields, type FormOpts, FormProvider, type FormProviderProps, type GetControlPropsParam, type GetControlPropsResult, type GetHiddenInputPropsParam, type GetHiddenInputPropsResult, type GetInputProps, type GetInputPropsParam, Isolate, type MinimalInputProps, type UseFieldArrayOpts, type UseFieldOpts, ValidatedForm, type ValidatedFormProps, type internal_BaseFormOpts, type internal_ValidatorAndDefaultValueOpts, createFormScope as unstable_createFormScope, useControlField, useField, useFieldArray, useForm, useFormContext, useFormScope, useFormScopeOrContext, useIsSubmitting, useIsValid, useNativeValidity, useNativeValidityForForm, useUpdateControlledField };
+33
-57

@@ -21,4 +21,4 @@ "use strict";

// src/index.ts
var src_exports = {};
__export(src_exports, {
var index_exports = {};
__export(index_exports, {
Field: () => Field,

@@ -47,5 +47,9 @@ FieldArray: () => FieldArray,

});
module.exports = __toCommonJS(src_exports);
module.exports = __toCommonJS(index_exports);
var import_core11 = require("@rvf/core");
// src/useForm.tsx
var import_react5 = require("react");
var import_core7 = require("@rvf/core");
// src/base.tsx

@@ -67,4 +71,3 @@ var import_react4 = require("react");

const existingImpl = implCache.get(fullName);
if (existingImpl)
return existingImpl;
if (existingImpl) return existingImpl;
const impl = create(fieldName ?? "");

@@ -109,4 +112,3 @@ implCache.set(fullName, impl);

}
if (typeof rvfOrName !== "string")
return rvfOrName;
if (typeof rvfOrName !== "string") return rvfOrName;
if (!value)

@@ -144,4 +146,3 @@ throw new Error("useFormContext must be used within a FormProvider");

const value = (0, import_core2.getFieldValue)(form.__store__.store.getState(), fieldName);
if (value != null)
(0, import_core2.setFormControlValue)(el, value);
if (value != null) (0, import_core2.setFormControlValue)(el, value);
}

@@ -179,6 +180,4 @@ };

const val = (0, import_core3.getFieldValue)(trackedState, arrayFieldName);
if (val == null)
return 0;
if (Array.isArray(val))
return val.length;
if (val == null) return 0;
if (Array.isArray(val)) return val.length;
console.warn(

@@ -335,10 +334,6 @@ "Tried to treat a non-array as an array. Make sure you used the correct field name and set a default value."

ref: (element) => {
if (typeof props.ref === "function")
props.ref(element);
else if (props.ref)
props.ref.current = element;
if (typeof rvfRef === "function")
rvfRef(element);
else if (rvfRef)
rvfRef.current = element;
if (typeof props.ref === "function") props.ref(element);
else if (props.ref) props.ref.current = element;
if (typeof rvfRef === "function") rvfRef(element);
else if (rvfRef) rvfRef.current = element;
}

@@ -466,4 +461,3 @@ };

const [a, b] = args;
if (typeof a === "string")
return [f(a), b];
if (typeof a === "string") return [f(a), b];
return [prefix, a];

@@ -545,4 +539,3 @@ };

const prevValue = fieldName ? (0, import_set_get2.getPath)(prevState.values, fieldName) : prevState.values;
if (prevValue === value)
return;
if (prevValue === value) return;
callback(value);

@@ -567,4 +560,3 @@ });

const formElement = form.__store__.formRef.current;
if (formElement)
formElement.reset();
if (formElement) formElement.reset();
form.__store__.store.getState().reset(...args);

@@ -588,4 +580,3 @@ },

formProps.onSubmit?.(event);
if (event.defaultPrevented)
return;
if (event.defaultPrevented) return;
event.preventDefault();

@@ -603,4 +594,3 @@ const nativeEvent = event.nativeEvent;

const buttonFormAction = submitter?.getAttribute("formAction");
if (buttonFormAction)
submitterOptions.formAction = buttonFormAction;
if (buttonFormAction) submitterOptions.formAction = buttonFormAction;
transientState().onSubmit(submitterData, submitterOptions);

@@ -610,9 +600,7 @@ },

formProps.onReset?.(event);
if (event.defaultPrevented)
return;
if (event.defaultPrevented) return;
transientState().reset();
},
ref: (el) => {
if (typeof formProps.ref === "function")
formProps.ref(el);
if (typeof formProps.ref === "function") formProps.ref(el);
else if (formProps.ref) {

@@ -639,4 +627,3 @@ formProps.ref.current = el;

const formId = (0, import_core6.getFormIdOption)(trackedState);
if (!formId)
return null;
if (!formId) return null;
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "hidden", name: import_core6.FORM_ID_FIELD_NAME, value: formId });

@@ -677,4 +664,2 @@ }

// src/useForm.tsx
var import_react5 = require("react");
var import_core7 = require("@rvf/core");
var noOp = () => {

@@ -720,6 +705,4 @@ };

const formElement = form.__store__.formRef.current;
if (formElement)
formElement.reset();
else
form.__store__.store.getState().reset();
if (formElement) formElement.reset();
else form.__store__.store.getState().reset();
}

@@ -758,6 +741,4 @@ },

const formElement = form.__store__.formRef.current;
if (formElement)
formElement.reset();
else
form.__store__.store.getState().reset();
if (formElement) formElement.reset();
else form.__store__.store.getState().reset();
}

@@ -814,4 +795,3 @@ });

(0, import_react5.useEffect)(() => {
if (!serverValidationErrors)
return;
if (!serverValidationErrors) return;
form.__store__.store.getState().syncServerValidationErrors(serverValidationErrors ?? {});

@@ -890,4 +870,3 @@ }, [serverValidationErrors, form.__store__.store]);

(0, import_react6.useEffect)(() => {
if (!ref.current)
return;
if (!ref.current) return;
ref.current.setCustomValidity(error ?? "");

@@ -917,4 +896,3 @@ }, [error, ref]);

const formElement = scope.__store__.formRef.current;
if (!formElement)
return [];
if (!formElement) return [];
const unregisteredFormControls = (0, import_core8.sortByPosition)(

@@ -1016,6 +994,4 @@ (0, import_core8.getElementsWithNames)([field], formElement)

const formElement = rvf.__store__.formRef.current;
if (formElement)
formElement.reset();
else
rvf.__store__.store.getState().reset();
if (formElement) formElement.reset();
else rvf.__store__.store.getState().reset();
}

@@ -1022,0 +998,0 @@ },

@@ -1,2 +0,2 @@

import { FieldArrayValidationBehaviorConfig, FormScope, ValidationBehaviorConfig, SubmitterOptions, SubmitStatus, FieldValues, BeforeSubmitApi, FieldErrors, experimental_FormEventListener, Validator, NonContradictingSupertype, StateSubmitHandler, DomSubmitHandler } from '@rvf/core';
import { FormScope, FieldArrayValidationBehaviorConfig, ValidationBehaviorConfig, SubmitStatus, SubmitterOptions, FieldValues, NonContradictingSupertype, Validator, BeforeSubmitApi, FieldErrors, experimental_FormEventListener, StateSubmitHandler, DomSubmitHandler } from '@rvf/core';
export { BeforeSubmitApi, CreateValidatorArg, DomSubmitHandler, FieldArrayValidationBehavior, FieldArrayValidationBehaviorConfig, FieldErrors, FieldValue, FieldValues, FormScope, Invalid, MultiFileInputValue, NativeValueByType, NumberInputValue, ScopedValues, SingleFileInputValue, StateSubmitHandler, SubmitStatus, Valid, ValidationBehavior, ValidationBehaviorConfig, ValidationErrorResponseData, ValidationResult, Validator, ValidatorData, ValidatorError, ValueOfInputType, getOriginalObject, isValidationErrorResponse, parseFormData, preprocessFormData } from '@rvf/core';

@@ -758,2 +758,2 @@ import { ValidStringPaths, ValueAtPath, StringToPathTuple, ValidStringPathsToArrays } from '@rvf/set-get';

export { Field, FieldApi, FieldArray, FieldArrayApi, FieldArrayPropsWithName, FieldArrayPropsWithScope, FieldPropsWithName, FieldPropsWithScope, FormApi, FormFields, FormOpts, FormProvider, FormProviderProps, GetControlPropsParam, GetControlPropsResult, GetHiddenInputPropsParam, GetHiddenInputPropsResult, GetInputProps, GetInputPropsParam, Isolate, MinimalInputProps, UseFieldArrayOpts, UseFieldOpts, ValidatedForm, ValidatedFormProps, internal_BaseFormOpts, internal_ValidatorAndDefaultValueOpts, createFormScope as unstable_createFormScope, useControlField, useField, useFieldArray, useForm, useFormContext, useFormScope, useFormScopeOrContext, useIsSubmitting, useIsValid, useNativeValidity, useNativeValidityForForm, useUpdateControlledField };
export { Field, type FieldApi, FieldArray, type FieldArrayApi, type FieldArrayPropsWithName, type FieldArrayPropsWithScope, type FieldPropsWithName, type FieldPropsWithScope, type FormApi, type FormFields, type FormOpts, FormProvider, type FormProviderProps, type GetControlPropsParam, type GetControlPropsResult, type GetHiddenInputPropsParam, type GetHiddenInputPropsResult, type GetInputProps, type GetInputPropsParam, Isolate, type MinimalInputProps, type UseFieldArrayOpts, type UseFieldOpts, ValidatedForm, type ValidatedFormProps, type internal_BaseFormOpts, type internal_ValidatorAndDefaultValueOpts, createFormScope as unstable_createFormScope, useControlField, useField, useFieldArray, useForm, useFormContext, useFormScope, useFormScopeOrContext, useIsSubmitting, useIsValid, useNativeValidity, useNativeValidityForForm, useUpdateControlledField };

@@ -9,2 +9,10 @@ // src/index.ts

// src/useForm.tsx
import { useEffect as useEffect3, useState, useId } from "react";
import {
createFormScope,
registerFormElementEvents,
withStandardSchema
} from "@rvf/core";
// src/base.tsx

@@ -50,4 +58,3 @@ import { useEffect as useEffect2, useMemo as useMemo4, useSyncExternalStore } from "react";

const existingImpl = implCache.get(fullName);
if (existingImpl)
return existingImpl;
if (existingImpl) return existingImpl;
const impl = create(fieldName ?? "");

@@ -97,4 +104,3 @@ implCache.set(fullName, impl);

}
if (typeof rvfOrName !== "string")
return rvfOrName;
if (typeof rvfOrName !== "string") return rvfOrName;
if (!value)

@@ -136,4 +142,3 @@ throw new Error("useFormContext must be used within a FormProvider");

const value = getFieldValue(form.__store__.store.getState(), fieldName);
if (value != null)
setFormControlValue(el, value);
if (value != null) setFormControlValue(el, value);
}

@@ -171,6 +176,4 @@ };

const val = getFieldValue2(trackedState, arrayFieldName);
if (val == null)
return 0;
if (Array.isArray(val))
return val.length;
if (val == null) return 0;
if (Array.isArray(val)) return val.length;
console.warn(

@@ -340,10 +343,6 @@ "Tried to treat a non-array as an array. Make sure you used the correct field name and set a default value."

ref: (element) => {
if (typeof props.ref === "function")
props.ref(element);
else if (props.ref)
props.ref.current = element;
if (typeof rvfRef === "function")
rvfRef(element);
else if (rvfRef)
rvfRef.current = element;
if (typeof props.ref === "function") props.ref(element);
else if (props.ref) props.ref.current = element;
if (typeof rvfRef === "function") rvfRef(element);
else if (rvfRef) rvfRef.current = element;
}

@@ -471,4 +470,3 @@ };

const [a, b] = args;
if (typeof a === "string")
return [f(a), b];
if (typeof a === "string") return [f(a), b];
return [prefix, a];

@@ -550,4 +548,3 @@ };

const prevValue = fieldName ? getPath(prevState.values, fieldName) : prevState.values;
if (prevValue === value)
return;
if (prevValue === value) return;
callback(value);

@@ -572,4 +569,3 @@ });

const formElement = form.__store__.formRef.current;
if (formElement)
formElement.reset();
if (formElement) formElement.reset();
form.__store__.store.getState().reset(...args);

@@ -593,4 +589,3 @@ },

formProps.onSubmit?.(event);
if (event.defaultPrevented)
return;
if (event.defaultPrevented) return;
event.preventDefault();

@@ -608,4 +603,3 @@ const nativeEvent = event.nativeEvent;

const buttonFormAction = submitter?.getAttribute("formAction");
if (buttonFormAction)
submitterOptions.formAction = buttonFormAction;
if (buttonFormAction) submitterOptions.formAction = buttonFormAction;
transientState().onSubmit(submitterData, submitterOptions);

@@ -615,9 +609,7 @@ },

formProps.onReset?.(event);
if (event.defaultPrevented)
return;
if (event.defaultPrevented) return;
transientState().reset();
},
ref: (el) => {
if (typeof formProps.ref === "function")
formProps.ref(el);
if (typeof formProps.ref === "function") formProps.ref(el);
else if (formProps.ref) {

@@ -644,4 +636,3 @@ formProps.ref.current = el;

const formId = getFormIdOption(trackedState);
if (!formId)
return null;
if (!formId) return null;
return /* @__PURE__ */ jsx2("input", { type: "hidden", name: FORM_ID_FIELD_NAME, value: formId });

@@ -682,8 +673,2 @@ }

// src/useForm.tsx
import { useEffect as useEffect3, useState, useId } from "react";
import {
createFormScope,
registerFormElementEvents,
withStandardSchema
} from "@rvf/core";
var noOp = () => {

@@ -729,6 +714,4 @@ };

const formElement = form.__store__.formRef.current;
if (formElement)
formElement.reset();
else
form.__store__.store.getState().reset();
if (formElement) formElement.reset();
else form.__store__.store.getState().reset();
}

@@ -767,6 +750,4 @@ },

const formElement = form.__store__.formRef.current;
if (formElement)
formElement.reset();
else
form.__store__.store.getState().reset();
if (formElement) formElement.reset();
else form.__store__.store.getState().reset();
}

@@ -823,4 +804,3 @@ });

useEffect3(() => {
if (!serverValidationErrors)
return;
if (!serverValidationErrors) return;
form.__store__.store.getState().syncServerValidationErrors(serverValidationErrors ?? {});

@@ -904,4 +884,3 @@ }, [serverValidationErrors, form.__store__.store]);

useEffect4(() => {
if (!ref.current)
return;
if (!ref.current) return;
ref.current.setCustomValidity(error ?? "");

@@ -931,4 +910,3 @@ }, [error, ref]);

const formElement = scope.__store__.formRef.current;
if (!formElement)
return [];
if (!formElement) return [];
const unregisteredFormControls = sortByPosition(

@@ -1032,6 +1010,4 @@ getElementsWithNames([field], formElement)

const formElement = rvf.__store__.formRef.current;
if (formElement)
formElement.reset();
else
rvf.__store__.store.getState().reset();
if (formElement) formElement.reset();
else rvf.__store__.store.getState().reset();
}

@@ -1038,0 +1014,0 @@ },

{
"name": "@rvf/react",
"version": "8.1.1",
"version": "8.1.2",
"description": "Easy, predictable form state management for React",

@@ -39,6 +39,6 @@ "main": "./dist/index.cjs.js",

"dependencies": {
"@rvf/core": ">= 8.1.0 < 9.0.0",
"@rvf/set-get": ">= 7.0.1 < 8.0.0",
"@rvf/core": ">= 8.1.1 < 9.0.0",
"@rvf/set-get": ">= 7.0.2 < 8.0.0",
"@standard-schema/spec": "^1.0.0"
}
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display