New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@tanstack/form-core

Package Overview
Dependencies
Maintainers
2
Versions
129
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tanstack/form-core - npm Package Compare versions

Comparing version 0.3.7 to 0.4.0

build/legacy/types.cjs

1

build/legacy/FieldApi.d.ts
export { FieldApi, FieldApiOptions, FieldMeta, FieldOptions, FieldState, ResolveName, ValidationCause } from './index.js';
import './utils.js';
import '@tanstack/store';
import './types.js';

64

build/legacy/FieldApi.js

@@ -1,11 +0,5 @@

import {
__privateAdd,
__privateGet
} from "./chunk-4QZDOMDG.js";
// src/FieldApi.ts
import { Store } from "@tanstack/store";
var uid = 0;
var _leaseValidateAsync;
var _FieldApi = class _FieldApi {
var FieldApi = class _FieldApi {
constructor(opts) {

@@ -87,3 +81,21 @@ this.options = {};

this.getInfo().validationCount = validationCount;
const error = normalizeError(validate(value, this));
const doValidate = () => {
if (this.options.validator && typeof validate !== "function") {
return this.options.validator().validate(
value,
validate
);
}
if (this.form.options.validator && typeof validate !== "function") {
return this.form.options.validator().validate(
value,
validate
);
}
return validate(
value,
this
);
};
const error = normalizeError(doValidate());
const errorMapKey = getErrorMapKey(cause);

@@ -103,9 +115,9 @@ if (this.state.meta.errorMap[errorMapKey] !== error) {

};
__privateAdd(this, _leaseValidateAsync, () => {
this.__leaseValidateAsync = () => {
const count = (this.getInfo().validationAsyncCount || 0) + 1;
this.getInfo().validationAsyncCount = count;
return count;
});
};
this.cancelValidateAsync = () => {
__privateGet(this, _leaseValidateAsync).call(this);
this.__leaseValidateAsync();
this.setMeta((prev) => ({

@@ -130,5 +142,6 @@ ...prev,

const debounceMs = cause === "submit" ? 0 : (cause === "change" ? onChangeAsyncDebounceMs : onBlurAsyncDebounceMs) ?? asyncDebounceMs ?? 0;
if (this.state.meta.isValidating !== true)
if (this.state.meta.isValidating !== true) {
this.setMeta((prev) => ({ ...prev, isValidating: true }));
const validationAsyncCount = __privateGet(this, _leaseValidateAsync).call(this);
}
const validationAsyncCount = this.__leaseValidateAsync();
const checkLatest = () => validationAsyncCount === this.getInfo().validationAsyncCount;

@@ -144,6 +157,21 @@ if (!this.getInfo().validationPromise) {

}
const doValidate = () => {
if (this.options.validator && typeof validate !== "function") {
return this.options.validator().validateAsync(
value,
validate
);
}
if (this.form.options.validator && typeof validate !== "function") {
return this.form.options.validator().validateAsync(value, validate);
}
return validate(
value,
this
);
};
if (checkLatest()) {
const prevErrors = this.getMeta().errors;
try {
const rawError = await validate(value, this);
const rawError = await doValidate();
if (checkLatest()) {

@@ -178,5 +206,7 @@ const error = normalizeError(rawError);

return [];
const errorMapKey = getErrorMapKey(cause);
const prevError = this.getMeta().errorMap[errorMapKey];
this.validateSync(value, cause);
const errorMapKey = getErrorMapKey(cause);
if (this.getMeta().errorMap[errorMapKey]) {
const newError = this.getMeta().errorMap[errorMapKey];
if (prevError !== newError) {
if (!this.options.asyncAlways) {

@@ -235,4 +265,2 @@ return this.state.meta.errors;

};
_leaseValidateAsync = new WeakMap();
var FieldApi = _FieldApi;
function normalizeError(rawError) {

@@ -239,0 +267,0 @@ if (rawError) {

import '@tanstack/store';
import './utils.js';
export { FieldInfo, FormApi, FormOptions, FormState, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta } from './index.js';
export { FieldInfo, FormApi, FormOptions, FormState, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta } from './index.js';
import './types.js';

@@ -1,3 +0,1 @@

import "./chunk-4QZDOMDG.js";
// src/FormApi.ts

@@ -65,14 +63,12 @@ import { Store } from "@tanstack/store";

this.store.batch(() => {
void Object.values(this.fieldInfo).forEach(
(field) => {
Object.values(field.instances).forEach((instance) => {
if (!instance.state.meta.isTouched) {
instance.setMeta((prev) => ({ ...prev, isTouched: true }));
fieldValidationPromises.push(
Promise.resolve().then(() => instance.validate(cause))
);
}
});
}
);
void Object.values(this.fieldInfo).forEach((field) => {
Object.values(field.instances).forEach((instance) => {
if (!instance.state.meta.isTouched) {
instance.setMeta((prev) => ({ ...prev, isTouched: true }));
fieldValidationPromises.push(
Promise.resolve().then(() => instance.validate(cause))
);
}
});
});
});

@@ -79,0 +75,0 @@ return Promise.all(fieldValidationPromises);

import { Store } from '@tanstack/store';
import { DeepKeys, DeepValue, Updater } from './utils.js';
export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.js';
import { ValidationError, Validator } from './types.js';
type FormOptions<TData> = {
type ValidateFn$1<TData, ValidatorType> = (values: TData, formApi: FormApi<TData, ValidatorType>) => ValidationError;
type ValidateOrFn$1<TData, ValidatorType> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] : ValidateFn$1<TData, ValidatorType>;
type ValidateAsyncFn$1<TData, ValidatorType> = (value: TData, fieldApi: FormApi<TData, ValidatorType>) => ValidationError | Promise<ValidationError>;
type FormOptions<TData, ValidatorType> = {
defaultValues?: TData;
defaultState?: Partial<FormState<TData>>;
asyncDebounceMs?: number;
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError;
onMountAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
validator?: ValidatorType;
onMount?: ValidateOrFn$1<TData, ValidatorType>;
onMountAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
onMountAsyncDebounceMs?: number;
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError;
onChangeAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
onChange?: ValidateOrFn$1<TData, ValidatorType>;
onChangeAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
onChangeAsyncDebounceMs?: number;
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError;
onBlurAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
onBlur?: ValidateOrFn$1<TData, ValidatorType>;
onBlurAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
onBlurAsyncDebounceMs?: number;
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>;
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void;
onSubmit?: (values: TData, formApi: FormApi<TData, ValidatorType>) => any | Promise<any>;
onSubmitInvalid?: (values: TData, formApi: FormApi<TData, ValidatorType>) => void;
};
type FieldInfo<TFormData> = {
instances: Record<string, FieldApi<TFormData, any, any>>;
type FieldInfo<TFormData, ValidatorType> = {
instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>;
} & ValidationMeta;

@@ -31,3 +36,2 @@ type ValidationMeta = {

};
type ValidationError = undefined | false | null | string;
type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`;

@@ -54,11 +58,11 @@ type ValidationErrorMap = {

};
declare class FormApi<TFormData> {
options: FormOptions<TFormData>;
declare class FormApi<TFormData, ValidatorType> {
options: FormOptions<TFormData, ValidatorType>;
store: Store<FormState<TFormData>>;
state: FormState<TFormData>;
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>>;
fieldName?: string;
validationMeta: ValidationMeta;
constructor(opts?: FormOptions<TFormData>);
update: (options?: FormOptions<TFormData>) => void;
constructor(opts?: FormOptions<TFormData, ValidatorType>);
update: (options?: FormOptions<TFormData, ValidatorType>) => void;
reset: () => void;

@@ -69,3 +73,3 @@ validateAllFields: (cause: ValidationCause) => Promise<ValidationError[][]>;

getFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField) => FieldMeta | undefined;
getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData>;
getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData, ValidatorType>;
setFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>) => void;

@@ -75,6 +79,6 @@ setFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: {

}) => void;
pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>[number], opts?: {
pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
touch?: boolean;
}) => void;
insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>[number], opts?: {
insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
touch?: boolean;

@@ -89,15 +93,8 @@ }) => void;

type ValidationCause = 'change' | 'blur' | 'submit' | 'mount';
type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError;
type ValidateAsyncFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError | Promise<ValidationError>;
interface FieldOptions<TParentData,
/**
* This allows us to restrict the name to only be a valid field name while
* also assigning it to a generic
*/
TName extends DeepKeys<TParentData>,
/**
* If TData is unknown, we can use the TName generic to determine the type
*/
TData = DeepValue<TParentData, TName>> {
name: DeepKeys<TParentData>;
type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = (value: TData, fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>) => ValidationError;
type ValidateOrFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] | ValidateFn<TParentData, TName, ValidatorType, TData> : FormValidator extends Validator<TData> ? Parameters<ReturnType<FormValidator>['validate']>[1] | ValidateFn<TParentData, TName, ValidatorType, TData> : ValidateFn<TParentData, TName, ValidatorType, TData>;
type ValidateAsyncFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = (value: TData, fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>) => ValidationError | Promise<ValidationError>;
type AsyncValidateOrFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] | ValidateAsyncFn<TParentData, TName, ValidatorType, TData> : FormValidator extends Validator<TData> ? Parameters<ReturnType<FormValidator>['validate']>[1] | ValidateAsyncFn<TParentData, TName, ValidatorType, TData> : ValidateAsyncFn<TParentData, TName, ValidatorType, TData>;
interface FieldOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
name: TName;
index?: TData extends any[] ? number : never;

@@ -107,14 +104,15 @@ defaultValue?: TData;

asyncAlways?: boolean;
onMount?: (formApi: FieldApi<TParentData, TName>) => void;
onChange?: ValidateFn<TParentData, TName, TData>;
onChangeAsync?: ValidateAsyncFn<TParentData, TName, TData>;
validator?: ValidatorType;
onMount?: (formApi: FieldApi<TParentData, TName, ValidatorType, TData>) => void;
onChange?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onChangeAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onChangeAsyncDebounceMs?: number;
onBlur?: ValidateFn<TParentData, TName, TData>;
onBlurAsync?: ValidateAsyncFn<TParentData, TName, TData>;
onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onBlurAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onBlurAsyncDebounceMs?: number;
onSubmitAsync?: ValidateAsyncFn<TParentData, TName, TData>;
onSubmitAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
defaultMeta?: Partial<FieldMeta>;
}
interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, TData> {
form: FormApi<TParentData>;
interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, ValidatorType, FormValidator, TData> {
form: FormApi<TParentData, FormValidator>;
}

@@ -133,16 +131,13 @@ type FieldMeta = {

type ResolveName<TParentData> = unknown extends TParentData ? string : DeepKeys<TParentData>;
declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> {
#private;
declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
uid: number;
form: FieldApiOptions<TParentData, TName, TData>['form'];
form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form'];
name: DeepKeys<TParentData>;
options: FieldApiOptions<TParentData, TName>;
options: FieldApiOptions<TParentData, TName, ValidatorType, TData>;
store: Store<FieldState<TData>>;
state: FieldState<TData>;
prevState: FieldState<TData>;
constructor(opts: FieldApiOptions<TParentData, TName, TData> & {
form: FormApi<TParentData>;
});
constructor(opts: FieldApiOptions<TParentData, TName, ValidatorType, FormValidator, TData>);
mount: () => () => void;
update: (opts: FieldApiOptions<TParentData, TName, TData>) => void;
update: (opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>) => void;
getValue: () => TData;

@@ -156,3 +151,3 @@ setValue: (updater: Updater<TData>, options?: {

setMeta: (updater: Updater<FieldMeta>) => void;
getInfo: () => FieldInfo<TParentData>;
getInfo: () => FieldInfo<TParentData, TData>;
pushValue: (value: TData extends any[] ? TData[number] : never) => void;

@@ -162,4 +157,5 @@ insertValue: (index: number, value: TData extends any[] ? TData[number] : never) => void;

swapValues: (aIndex: number, bIndex: number) => void;
getSubField: <TSubName extends DeepKeys<TData>, TSubData = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, TSubData>;
getSubField: <TSubName extends DeepKeys<TData>, TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, ValidatorType, TSubData, DeepValue<TData, TSubName>>;
validateSync: (value: TData | undefined, cause: ValidationCause) => void;
__leaseValidateAsync: () => number;
cancelValidateAsync: () => void;

@@ -172,2 +168,2 @@ validateAsync: (value: TData | undefined, cause: ValidationCause) => Promise<ValidationError[]>;

export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta };
export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta, Validator };

@@ -5,2 +5,3 @@ // src/index.ts

export * from "./utils.js";
export * from "./types.js";
//# sourceMappingURL=index.js.map

@@ -1,3 +0,1 @@

import "./chunk-4QZDOMDG.js";
// src/utils.ts

@@ -4,0 +2,0 @@ function functionalUpdate(updater, input) {

export { FieldApi, FieldApiOptions, FieldMeta, FieldOptions, FieldState, ResolveName, ValidationCause } from './index.js';
import './utils.js';
import '@tanstack/store';
import './types.js';

@@ -79,3 +79,21 @@ // src/FieldApi.ts

this.getInfo().validationCount = validationCount;
const error = normalizeError(validate(value, this));
const doValidate = () => {
if (this.options.validator && typeof validate !== "function") {
return this.options.validator().validate(
value,
validate
);
}
if (this.form.options.validator && typeof validate !== "function") {
return this.form.options.validator().validate(
value,
validate
);
}
return validate(
value,
this
);
};
const error = normalizeError(doValidate());
const errorMapKey = getErrorMapKey(cause);

@@ -95,3 +113,3 @@ if (this.state.meta.errorMap[errorMapKey] !== error) {

};
this.#leaseValidateAsync = () => {
this.__leaseValidateAsync = () => {
const count = (this.getInfo().validationAsyncCount || 0) + 1;

@@ -102,3 +120,3 @@ this.getInfo().validationAsyncCount = count;

this.cancelValidateAsync = () => {
this.#leaseValidateAsync();
this.__leaseValidateAsync();
this.setMeta((prev) => ({

@@ -122,5 +140,6 @@ ...prev,

const debounceMs = cause === "submit" ? 0 : (cause === "change" ? onChangeAsyncDebounceMs : onBlurAsyncDebounceMs) ?? asyncDebounceMs ?? 0;
if (this.state.meta.isValidating !== true)
if (this.state.meta.isValidating !== true) {
this.setMeta((prev) => ({ ...prev, isValidating: true }));
const validationAsyncCount = this.#leaseValidateAsync();
}
const validationAsyncCount = this.__leaseValidateAsync();
const checkLatest = () => validationAsyncCount === this.getInfo().validationAsyncCount;

@@ -136,6 +155,21 @@ if (!this.getInfo().validationPromise) {

}
const doValidate = () => {
if (this.options.validator && typeof validate !== "function") {
return this.options.validator().validateAsync(
value,
validate
);
}
if (this.form.options.validator && typeof validate !== "function") {
return this.form.options.validator().validateAsync(value, validate);
}
return validate(
value,
this
);
};
if (checkLatest()) {
const prevErrors = this.getMeta().errors;
try {
const rawError = await validate(value, this);
const rawError = await doValidate();
if (checkLatest()) {

@@ -170,5 +204,7 @@ const error = normalizeError(rawError);

return [];
const errorMapKey = getErrorMapKey(cause);
const prevError = this.getMeta().errorMap[errorMapKey];
this.validateSync(value, cause);
const errorMapKey = getErrorMapKey(cause);
if (this.getMeta().errorMap[errorMapKey]) {
const newError = this.getMeta().errorMap[errorMapKey];
if (prevError !== newError) {
if (!this.options.asyncAlways) {

@@ -226,3 +262,2 @@ return this.state.meta.errors;

}
#leaseValidateAsync;
};

@@ -229,0 +264,0 @@ function normalizeError(rawError) {

import '@tanstack/store';
import './utils.js';
export { FieldInfo, FormApi, FormOptions, FormState, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta } from './index.js';
export { FieldInfo, FormApi, FormOptions, FormState, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta } from './index.js';
import './types.js';

@@ -60,14 +60,12 @@ // src/FormApi.ts

this.store.batch(() => {
void Object.values(this.fieldInfo).forEach(
(field) => {
Object.values(field.instances).forEach((instance) => {
if (!instance.state.meta.isTouched) {
instance.setMeta((prev) => ({ ...prev, isTouched: true }));
fieldValidationPromises.push(
Promise.resolve().then(() => instance.validate(cause))
);
}
});
}
);
void Object.values(this.fieldInfo).forEach((field) => {
Object.values(field.instances).forEach((instance) => {
if (!instance.state.meta.isTouched) {
instance.setMeta((prev) => ({ ...prev, isTouched: true }));
fieldValidationPromises.push(
Promise.resolve().then(() => instance.validate(cause))
);
}
});
});
});

@@ -74,0 +72,0 @@ return Promise.all(fieldValidationPromises);

import { Store } from '@tanstack/store';
import { DeepKeys, DeepValue, Updater } from './utils.js';
export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.js';
import { ValidationError, Validator } from './types.js';
type FormOptions<TData> = {
type ValidateFn$1<TData, ValidatorType> = (values: TData, formApi: FormApi<TData, ValidatorType>) => ValidationError;
type ValidateOrFn$1<TData, ValidatorType> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] : ValidateFn$1<TData, ValidatorType>;
type ValidateAsyncFn$1<TData, ValidatorType> = (value: TData, fieldApi: FormApi<TData, ValidatorType>) => ValidationError | Promise<ValidationError>;
type FormOptions<TData, ValidatorType> = {
defaultValues?: TData;
defaultState?: Partial<FormState<TData>>;
asyncDebounceMs?: number;
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError;
onMountAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
validator?: ValidatorType;
onMount?: ValidateOrFn$1<TData, ValidatorType>;
onMountAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
onMountAsyncDebounceMs?: number;
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError;
onChangeAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
onChange?: ValidateOrFn$1<TData, ValidatorType>;
onChangeAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
onChangeAsyncDebounceMs?: number;
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError;
onBlurAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
onBlur?: ValidateOrFn$1<TData, ValidatorType>;
onBlurAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
onBlurAsyncDebounceMs?: number;
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>;
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void;
onSubmit?: (values: TData, formApi: FormApi<TData, ValidatorType>) => any | Promise<any>;
onSubmitInvalid?: (values: TData, formApi: FormApi<TData, ValidatorType>) => void;
};
type FieldInfo<TFormData> = {
instances: Record<string, FieldApi<TFormData, any, any>>;
type FieldInfo<TFormData, ValidatorType> = {
instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>;
} & ValidationMeta;

@@ -31,3 +36,2 @@ type ValidationMeta = {

};
type ValidationError = undefined | false | null | string;
type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`;

@@ -54,11 +58,11 @@ type ValidationErrorMap = {

};
declare class FormApi<TFormData> {
options: FormOptions<TFormData>;
declare class FormApi<TFormData, ValidatorType> {
options: FormOptions<TFormData, ValidatorType>;
store: Store<FormState<TFormData>>;
state: FormState<TFormData>;
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>>;
fieldName?: string;
validationMeta: ValidationMeta;
constructor(opts?: FormOptions<TFormData>);
update: (options?: FormOptions<TFormData>) => void;
constructor(opts?: FormOptions<TFormData, ValidatorType>);
update: (options?: FormOptions<TFormData, ValidatorType>) => void;
reset: () => void;

@@ -69,3 +73,3 @@ validateAllFields: (cause: ValidationCause) => Promise<ValidationError[][]>;

getFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField) => FieldMeta | undefined;
getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData>;
getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData, ValidatorType>;
setFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>) => void;

@@ -75,6 +79,6 @@ setFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: {

}) => void;
pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>[number], opts?: {
pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
touch?: boolean;
}) => void;
insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>[number], opts?: {
insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
touch?: boolean;

@@ -89,15 +93,8 @@ }) => void;

type ValidationCause = 'change' | 'blur' | 'submit' | 'mount';
type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError;
type ValidateAsyncFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError | Promise<ValidationError>;
interface FieldOptions<TParentData,
/**
* This allows us to restrict the name to only be a valid field name while
* also assigning it to a generic
*/
TName extends DeepKeys<TParentData>,
/**
* If TData is unknown, we can use the TName generic to determine the type
*/
TData = DeepValue<TParentData, TName>> {
name: DeepKeys<TParentData>;
type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = (value: TData, fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>) => ValidationError;
type ValidateOrFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] | ValidateFn<TParentData, TName, ValidatorType, TData> : FormValidator extends Validator<TData> ? Parameters<ReturnType<FormValidator>['validate']>[1] | ValidateFn<TParentData, TName, ValidatorType, TData> : ValidateFn<TParentData, TName, ValidatorType, TData>;
type ValidateAsyncFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = (value: TData, fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>) => ValidationError | Promise<ValidationError>;
type AsyncValidateOrFn<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] | ValidateAsyncFn<TParentData, TName, ValidatorType, TData> : FormValidator extends Validator<TData> ? Parameters<ReturnType<FormValidator>['validate']>[1] | ValidateAsyncFn<TParentData, TName, ValidatorType, TData> : ValidateAsyncFn<TParentData, TName, ValidatorType, TData>;
interface FieldOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
name: TName;
index?: TData extends any[] ? number : never;

@@ -107,14 +104,15 @@ defaultValue?: TData;

asyncAlways?: boolean;
onMount?: (formApi: FieldApi<TParentData, TName>) => void;
onChange?: ValidateFn<TParentData, TName, TData>;
onChangeAsync?: ValidateAsyncFn<TParentData, TName, TData>;
validator?: ValidatorType;
onMount?: (formApi: FieldApi<TParentData, TName, ValidatorType, TData>) => void;
onChange?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onChangeAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onChangeAsyncDebounceMs?: number;
onBlur?: ValidateFn<TParentData, TName, TData>;
onBlurAsync?: ValidateAsyncFn<TParentData, TName, TData>;
onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onBlurAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
onBlurAsyncDebounceMs?: number;
onSubmitAsync?: ValidateAsyncFn<TParentData, TName, TData>;
onSubmitAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
defaultMeta?: Partial<FieldMeta>;
}
interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, TData> {
form: FormApi<TParentData>;
interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, ValidatorType, FormValidator, TData> {
form: FormApi<TParentData, FormValidator>;
}

@@ -133,16 +131,13 @@ type FieldMeta = {

type ResolveName<TParentData> = unknown extends TParentData ? string : DeepKeys<TParentData>;
declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> {
#private;
declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
uid: number;
form: FieldApiOptions<TParentData, TName, TData>['form'];
form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form'];
name: DeepKeys<TParentData>;
options: FieldApiOptions<TParentData, TName>;
options: FieldApiOptions<TParentData, TName, ValidatorType, TData>;
store: Store<FieldState<TData>>;
state: FieldState<TData>;
prevState: FieldState<TData>;
constructor(opts: FieldApiOptions<TParentData, TName, TData> & {
form: FormApi<TParentData>;
});
constructor(opts: FieldApiOptions<TParentData, TName, ValidatorType, FormValidator, TData>);
mount: () => () => void;
update: (opts: FieldApiOptions<TParentData, TName, TData>) => void;
update: (opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>) => void;
getValue: () => TData;

@@ -156,3 +151,3 @@ setValue: (updater: Updater<TData>, options?: {

setMeta: (updater: Updater<FieldMeta>) => void;
getInfo: () => FieldInfo<TParentData>;
getInfo: () => FieldInfo<TParentData, TData>;
pushValue: (value: TData extends any[] ? TData[number] : never) => void;

@@ -162,4 +157,5 @@ insertValue: (index: number, value: TData extends any[] ? TData[number] : never) => void;

swapValues: (aIndex: number, bIndex: number) => void;
getSubField: <TSubName extends DeepKeys<TData>, TSubData = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, TSubData>;
getSubField: <TSubName extends DeepKeys<TData>, TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, ValidatorType, TSubData, DeepValue<TData, TSubName>>;
validateSync: (value: TData | undefined, cause: ValidationCause) => void;
__leaseValidateAsync: () => number;
cancelValidateAsync: () => void;

@@ -172,2 +168,2 @@ validateAsync: (value: TData | undefined, cause: ValidationCause) => Promise<ValidationError[]>;

export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta };
export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta, Validator };

@@ -5,2 +5,3 @@ // src/index.ts

export * from "./utils.js";
export * from "./types.js";
//# sourceMappingURL=index.js.map
{
"name": "@tanstack/form-core",
"version": "0.3.7",
"version": "0.4.0",
"description": "Powerful, type-safe, framework agnostic forms.",

@@ -5,0 +5,0 @@ "author": "tannerlinsley",

import { type DeepKeys, type DeepValue, type Updater } from './utils'
import type { FormApi, ValidationError, ValidationErrorMap } from './FormApi'
import type { FormApi, ValidationErrorMap } from './FormApi'
import { Store } from '@tanstack/store'
import type { Validator, ValidationError } from './types'
export type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'
type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (
type ValidateFn<
TParentData,
TName extends DeepKeys<TParentData>,
ValidatorType,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> = (
value: TData,
fieldApi: FieldApi<TParentData, TName>,
fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>,
) => ValidationError
type ValidateOrFn<
TParentData,
TName extends DeepKeys<TParentData>,
ValidatorType,
FormValidator,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> = ValidatorType extends Validator<TData>
?
| Parameters<ReturnType<ValidatorType>['validate']>[1]
| ValidateFn<TParentData, TName, ValidatorType, TData>
: FormValidator extends Validator<TData>
?
| Parameters<ReturnType<FormValidator>['validate']>[1]
| ValidateFn<TParentData, TName, ValidatorType, TData>
: ValidateFn<TParentData, TName, ValidatorType, TData>
type ValidateAsyncFn<
TParentData,
TName extends DeepKeys<TParentData>,
TData,
ValidatorType,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> = (
value: TData,
fieldApi: FieldApi<TParentData, TName>,
fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>,
) => ValidationError | Promise<ValidationError>
type AsyncValidateOrFn<
TParentData,
TName extends DeepKeys<TParentData>,
ValidatorType,
FormValidator,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> = ValidatorType extends Validator<TData>
?
| Parameters<ReturnType<ValidatorType>['validate']>[1]
| ValidateAsyncFn<TParentData, TName, ValidatorType, TData>
: FormValidator extends Validator<TData>
?
| Parameters<ReturnType<FormValidator>['validate']>[1]
| ValidateAsyncFn<TParentData, TName, ValidatorType, TData>
: ValidateAsyncFn<TParentData, TName, ValidatorType, TData>
export interface FieldOptions<
TParentData,
/**
* This allows us to restrict the name to only be a valid field name while
* also assigning it to a generic
*/
TName extends DeepKeys<TParentData>,
/**
* If TData is unknown, we can use the TName generic to determine the type
*/
TData = DeepValue<TParentData, TName>,
ValidatorType,
FormValidator,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> {
name: DeepKeys<TParentData>
name: TName
index?: TData extends any[] ? number : never

@@ -38,10 +72,37 @@ defaultValue?: TData

asyncAlways?: boolean
onMount?: (formApi: FieldApi<TParentData, TName>) => void
onChange?: ValidateFn<TParentData, TName, TData>
onChangeAsync?: ValidateAsyncFn<TParentData, TName, TData>
validator?: ValidatorType
onMount?: (
formApi: FieldApi<TParentData, TName, ValidatorType, TData>,
) => void
onChange?: ValidateOrFn<
TParentData,
TName,
ValidatorType,
FormValidator,
TData
>
onChangeAsync?: AsyncValidateOrFn<
TParentData,
TName,
ValidatorType,
FormValidator,
TData
>
onChangeAsyncDebounceMs?: number
onBlur?: ValidateFn<TParentData, TName, TData>
onBlurAsync?: ValidateAsyncFn<TParentData, TName, TData>
onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>
onBlurAsync?: AsyncValidateOrFn<
TParentData,
TName,
ValidatorType,
FormValidator,
TData
>
onBlurAsyncDebounceMs?: number
onSubmitAsync?: ValidateAsyncFn<TParentData, TName, TData>
onSubmitAsync?: AsyncValidateOrFn<
TParentData,
TName,
ValidatorType,
FormValidator,
TData
>
defaultMeta?: Partial<FieldMeta>

@@ -53,5 +114,13 @@ }

TName extends DeepKeys<TParentData>,
TData = DeepValue<TParentData, TName>,
> extends FieldOptions<TParentData, TName, TData> {
form: FormApi<TParentData>
ValidatorType,
FormValidator,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> extends FieldOptions<
TParentData,
TName,
ValidatorType,
FormValidator,
TData
> {
form: FormApi<TParentData, FormValidator>
}

@@ -81,8 +150,10 @@

TName extends DeepKeys<TParentData>,
TData = DeepValue<TParentData, TName>,
ValidatorType,
FormValidator,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> {
uid: number
form: FieldApiOptions<TParentData, TName, TData>['form']
form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form']
name!: DeepKeys<TParentData>
options: FieldApiOptions<TParentData, TName> = {} as any
options: FieldApiOptions<TParentData, TName, ValidatorType, TData> = {} as any
store!: Store<FieldState<TData>>

@@ -93,7 +164,11 @@ state!: FieldState<TData>

constructor(
opts: FieldApiOptions<TParentData, TName, TData> & {
form: FormApi<TParentData>
},
opts: FieldApiOptions<
TParentData,
TName,
ValidatorType,
FormValidator,
TData
>,
) {
this.form = opts.form
this.form = opts.form as never
this.uid = uid++

@@ -106,3 +181,3 @@ // Support field prefixing from FieldScope

this.name = opts.name as any
this.name = opts.name as never

@@ -175,3 +250,3 @@ if (opts.defaultValue !== undefined) {

if (!Object.keys(info.instances).length) {
delete this.form.fieldInfo[this.name]
delete this.form.fieldInfo[this.name as never]
}

@@ -181,3 +256,5 @@ }

update = (opts: FieldApiOptions<TParentData, TName, TData>) => {
update = (
opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>,
) => {
// Default Value

@@ -248,6 +325,6 @@ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition

TSubName extends DeepKeys<TData>,
TSubData = DeepValue<TData, TSubName>,
TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>,
>(
name: TSubName,
): FieldApi<TData, TSubName, TSubData> =>
): FieldApi<TData, TSubName, ValidatorType, TSubData> =>
new FieldApi({

@@ -262,2 +339,3 @@ name: `${this.name}.${name}` as never,

cause === 'submit' ? undefined : cause === 'change' ? onChange : onBlur
if (!validate) return

@@ -269,3 +347,25 @@

this.getInfo().validationCount = validationCount
const error = normalizeError(validate(value as never, this as never))
const doValidate = () => {
if (this.options.validator && typeof validate !== 'function') {
return (this.options.validator as Validator<TData>)().validate(
value,
validate,
)
}
if (this.form.options.validator && typeof validate !== 'function') {
return (this.form.options.validator as Validator<TData>)().validate(
value,
validate,
)
}
return (validate as ValidateFn<TParentData, TName, ValidatorType, TData>)(
value,
this as never,
)
}
const error = normalizeError(doValidate())
const errorMapKey = getErrorMapKey(cause)

@@ -288,3 +388,3 @@ if (this.state.meta.errorMap[errorMapKey] !== error) {

#leaseValidateAsync = () => {
__leaseValidateAsync = () => {
const count = (this.getInfo().validationAsyncCount || 0) + 1

@@ -297,3 +397,3 @@ this.getInfo().validationAsyncCount = count

// Lease a new validation count to ignore any pending validations
this.#leaseValidateAsync()
this.__leaseValidateAsync()
// Cancel any pending validation state

@@ -332,8 +432,9 @@ this.setMeta((prev) => ({

if (this.state.meta.isValidating !== true)
if (this.state.meta.isValidating !== true) {
this.setMeta((prev) => ({ ...prev, isValidating: true }))
}
// Use the validationCount for all field instances to
// track freshness of the validation
const validationAsyncCount = this.#leaseValidateAsync()
const validationAsyncCount = this.__leaseValidateAsync()

@@ -354,2 +455,22 @@ const checkLatest = () =>

const doValidate = () => {
if (this.options.validator && typeof validate !== 'function') {
return (this.options.validator as Validator<TData>)().validateAsync(
value,
validate,
)
}
if (this.form.options.validator && typeof validate !== 'function') {
return (
this.form.options.validator as Validator<TData>
)().validateAsync(value, validate)
}
return (validate as ValidateFn<TParentData, TName, ValidatorType, TData>)(
value,
this as never,
)
}
// Only kick off validation if this validation is the latest attempt

@@ -359,3 +480,3 @@ if (checkLatest()) {

try {
const rawError = await validate(value as never, this as never)
const rawError = await doValidate()
if (checkLatest()) {

@@ -396,8 +517,14 @@ const error = normalizeError(rawError)

if (!this.state.meta.isTouched) return []
// Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)
const errorMapKey = getErrorMapKey(cause)
const prevError = this.getMeta().errorMap[errorMapKey]
// Attempt to sync validate first
this.validateSync(value, cause)
const errorMapKey = getErrorMapKey(cause)
// If there is an error mapped to the errorMapKey (eg. onChange, onBlur, onSubmit), return the errors array, do not attempt async validation
if (this.getMeta().errorMap[errorMapKey]) {
// If there is a new error mapped to the errorMapKey (eg. onChange, onBlur, onSubmit), return the errors array, do not attempt async validation
const newError = this.getMeta().errorMap[errorMapKey]
if (prevError !== newError) {
if (!this.options.asyncAlways) {

@@ -404,0 +531,0 @@ return this.state.meta.errors

import { Store } from '@tanstack/store'
//
import type { DeepKeys, DeepValue, Updater } from './utils'
import { functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils'
import type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'
import type { ValidationError, Validator } from './types'
export type FormOptions<TData> = {
type ValidateFn<TData, ValidatorType> = (
values: TData,
formApi: FormApi<TData, ValidatorType>,
) => ValidationError
type ValidateOrFn<TData, ValidatorType> = ValidatorType extends Validator<TData>
? Parameters<ReturnType<ValidatorType>['validate']>[1]
: ValidateFn<TData, ValidatorType>
type ValidateAsyncFn<TData, ValidatorType> = (
value: TData,
fieldApi: FormApi<TData, ValidatorType>,
) => ValidationError | Promise<ValidationError>
export type FormOptions<TData, ValidatorType> = {
defaultValues?: TData
defaultState?: Partial<FormState<TData>>
asyncDebounceMs?: number
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError
onMountAsync?: (
values: TData,
formApi: FormApi<TData>,
) => ValidationError | Promise<ValidationError>
validator?: ValidatorType
onMount?: ValidateOrFn<TData, ValidatorType>
onMountAsync?: ValidateAsyncFn<TData, ValidatorType>
onMountAsyncDebounceMs?: number
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError
onChangeAsync?: (
values: TData,
formApi: FormApi<TData>,
) => ValidationError | Promise<ValidationError>
onChange?: ValidateOrFn<TData, ValidatorType>
onChangeAsync?: ValidateAsyncFn<TData, ValidatorType>
onChangeAsyncDebounceMs?: number
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError
onBlurAsync?: (
onBlur?: ValidateOrFn<TData, ValidatorType>
onBlurAsync?: ValidateAsyncFn<TData, ValidatorType>
onBlurAsyncDebounceMs?: number
onSubmit?: (
values: TData,
formApi: FormApi<TData>,
) => ValidationError | Promise<ValidationError>
onBlurAsyncDebounceMs?: number
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void
formApi: FormApi<TData, ValidatorType>,
) => any | Promise<any>
onSubmitInvalid?: (
values: TData,
formApi: FormApi<TData, ValidatorType>,
) => void
}
export type FieldInfo<TFormData> = {
instances: Record<string, FieldApi<TFormData, any, any>>
export type FieldInfo<TFormData, ValidatorType> = {
instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>
} & ValidationMeta

@@ -45,4 +57,2 @@

export type ValidationError = undefined | false | null | string
export type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`

@@ -96,5 +106,5 @@

export class FormApi<TFormData> {
export class FormApi<TFormData, ValidatorType> {
// // This carries the context for nested fields
options: FormOptions<TFormData> = {}
options: FormOptions<TFormData, ValidatorType> = {}
store!: Store<FormState<TFormData>>

@@ -104,7 +114,8 @@ // Do not use __state directly, as it is not reactive.

state!: FormState<TFormData>
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>> = {} as any
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>> =
{} as any
fieldName?: string
validationMeta: ValidationMeta = {}
constructor(opts?: FormOptions<TFormData>) {
constructor(opts?: FormOptions<TFormData, ValidatorType>) {
this.store = new Store<FormState<TFormData>>(

@@ -163,3 +174,3 @@ getDefaultFormState({

update = (options?: FormOptions<TFormData>) => {
update = (options?: FormOptions<TFormData, ValidatorType>) => {
if (!options) return

@@ -209,17 +220,17 @@

this.store.batch(() => {
void (Object.values(this.fieldInfo) as FieldInfo<any>[]).forEach(
(field) => {
Object.values(field.instances).forEach((instance) => {
// If any fields are not touched
if (!instance.state.meta.isTouched) {
// Mark them as touched
instance.setMeta((prev) => ({ ...prev, isTouched: true }))
// Validate the field
fieldValidationPromises.push(
Promise.resolve().then(() => instance.validate(cause)),
)
}
})
},
)
void (
Object.values(this.fieldInfo) as FieldInfo<any, ValidatorType>[]
).forEach((field) => {
Object.values(field.instances).forEach((instance) => {
// If any fields are not touched
if (!instance.state.meta.isTouched) {
// Mark them as touched
instance.setMeta((prev) => ({ ...prev, isTouched: true }))
// Validate the field
fieldValidationPromises.push(
Promise.resolve().then(() => instance.validate(cause)),
)
}
})
})
})

@@ -298,3 +309,3 @@

field: TField,
): FieldInfo<TFormData> => {
): FieldInfo<TFormData, ValidatorType> => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition

@@ -347,3 +358,5 @@ return (this.fieldInfo[field] ||= {

field: TField,
value: DeepValue<TFormData, TField>[number],
value: DeepValue<TFormData, TField> extends any[]
? DeepValue<TFormData, TField>[number]
: never,
opts?: { touch?: boolean },

@@ -361,3 +374,5 @@ ) => {

index: number,
value: DeepValue<TFormData, TField>[number],
value: DeepValue<TFormData, TField> extends any[]
? DeepValue<TFormData, TField>[number]
: never,
opts?: { touch?: boolean },

@@ -364,0 +379,0 @@ ) => {

export * from './FormApi'
export * from './FieldApi'
export * from './utils'
export * from './types'

@@ -554,3 +554,3 @@ import { expect } from 'vitest'

}
const form = new FormApi<Form>()
const form = new FormApi<Form, unknown>()

@@ -557,0 +557,0 @@ const field = new FieldApi({

@@ -5,20 +5,17 @@ import { assertType } from 'vitest'

it('should type a subfield properly', () => {
it('should type value properly', () => {
const form = new FormApi({
defaultValues: {
names: {
first: 'one',
second: 'two',
},
} as const,
})
name: 'test',
},
} as const)
const field = new FieldApi({
form,
name: 'names',
name: 'name',
})
const subfield = field.getSubField('first')
assertType<'one'>(subfield.getValue())
assertType<'test'>(field.state.value)
assertType<'name'>(field.options.name)
assertType<'test'>(field.getValue())
})

@@ -43,1 +40,19 @@

})
it('should type onChangeAsync properly', () => {
const form = new FormApi({
defaultValues: {
name: 'test',
},
} as const)
const field = new FieldApi({
form,
name: 'name',
onChangeAsync: async (value) => {
assertType<'test'>(value)
return undefined
},
})
})

@@ -122,3 +122,3 @@ import { expect } from 'vitest'

form.pushFieldValue('name', 'other')
form.setFieldValue('name', 'other')
form.state.submissionAttempts = 300

@@ -125,0 +125,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc