@tanstack/react-form 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/nextjs/createServerValidate.cjs +9 -2
- package/dist/cjs/nextjs/createServerValidate.cjs.map +1 -1
- package/dist/cjs/start/createServerValidate.cjs +9 -2
- package/dist/cjs/start/createServerValidate.cjs.map +1 -1
- package/dist/cjs/useField.cjs.map +1 -1
- package/dist/cjs/useForm.cjs.map +1 -1
- package/dist/esm/nextjs/createServerValidate.js +9 -2
- package/dist/esm/nextjs/createServerValidate.js.map +1 -1
- package/dist/esm/start/createServerValidate.js +9 -2
- package/dist/esm/start/createServerValidate.js.map +1 -1
- package/dist/esm/useField.js.map +1 -1
- package/dist/esm/useForm.js.map +1 -1
- package/package.json +5 -5
- package/src/nextjs/createServerValidate.ts +23 -3
- package/src/start/createServerValidate.tsx +23 -3
- package/src/useField.tsx +2 -1
- package/src/useForm.tsx +2 -1
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const decodeFormdata = require("decode-formdata");
|
|
4
4
|
const error = require("./error.cjs");
|
|
5
|
+
const isFormValidationError = (error2) => {
|
|
6
|
+
return typeof error2 === "object";
|
|
7
|
+
};
|
|
5
8
|
const createServerValidate = (defaultOpts) => async (formData, info) => {
|
|
6
9
|
const { validatorAdapter, onServerValidate } = defaultOpts;
|
|
7
10
|
const runValidator = async (propsValue) => {
|
|
@@ -11,14 +14,18 @@ const createServerValidate = (defaultOpts) => async (formData, info) => {
|
|
|
11
14
|
return onServerValidate(propsValue);
|
|
12
15
|
};
|
|
13
16
|
const values = decodeFormdata.decode(formData, info);
|
|
14
|
-
const onServerError = await runValidator({
|
|
17
|
+
const onServerError = await runValidator({
|
|
18
|
+
value: values,
|
|
19
|
+
validationSource: "form"
|
|
20
|
+
});
|
|
15
21
|
if (!onServerError) return;
|
|
22
|
+
const onServerErrorStr = onServerError && typeof onServerError !== "string" && isFormValidationError(onServerError) ? onServerError.form : onServerError;
|
|
16
23
|
const formState = {
|
|
17
24
|
errorMap: {
|
|
18
25
|
onServer: onServerError
|
|
19
26
|
},
|
|
20
27
|
values,
|
|
21
|
-
errors:
|
|
28
|
+
errors: onServerErrorStr ? [onServerErrorStr] : []
|
|
22
29
|
};
|
|
23
30
|
throw new error.ServerValidateError({
|
|
24
31
|
formState
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerValidate.cjs","sources":["../../../src/nextjs/createServerValidate.ts"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { ServerFormState } from './types'\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {
|
|
1
|
+
{"version":3,"file":"createServerValidate.cjs","sources":["../../../src/nextjs/createServerValidate.ts"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n FormValidationError,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { ServerFormState } from './types'\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nconst isFormValidationError = (\n error: unknown,\n): error is FormValidationError<unknown> => {\n return typeof error === 'object'\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {\n value: TFormData\n validationSource: 'form'\n }) => {\n if (validatorAdapter && typeof onServerValidate !== 'function') {\n return validatorAdapter().validateAsync(propsValue, onServerValidate)\n }\n\n return (onServerValidate as OnServerValidateFn<TFormData>)(propsValue)\n }\n\n const values = decode(formData, info) as never as TFormData\n\n const onServerError = await runValidator({\n value: values,\n validationSource: 'form',\n })\n\n if (!onServerError) return\n\n const onServerErrorStr =\n onServerError &&\n typeof onServerError !== 'string' &&\n isFormValidationError(onServerError)\n ? onServerError.form\n : onServerError\n\n const formState: ServerFormState<TFormData> = {\n errorMap: {\n onServer: onServerError,\n },\n values,\n errors: onServerErrorStr ? [onServerErrorStr] : [],\n }\n\n throw new ServerValidateError({\n formState,\n })\n }\n\nexport const initialFormState: ServerFormState<any> = {\n errorMap: {\n onServer: undefined,\n },\n values: undefined,\n errors: [],\n}\n"],"names":["error","decode","ServerValidateError"],"mappings":";;;;AA6BA,MAAM,wBAAwB,CAC5BA,WAC0C;AAC1C,SAAO,OAAOA,WAAU;AAC1B;AAEO,MAAM,uBACX,CAME,gBAEF,OAAO,UAAoB,SAAwC;AAC3D,QAAA,EAAE,kBAAkB,iBAAqB,IAAA;AAEzC,QAAA,eAAe,OAAO,eAGtB;AACA,QAAA,oBAAoB,OAAO,qBAAqB,YAAY;AAC9D,aAAO,iBAAiB,EAAE,cAAc,YAAY,gBAAgB;AAAA,IACtE;AAEA,WAAQ,iBAAmD,UAAU;AAAA,EAAA;AAGjE,QAAA,SAASC,eAAAA,OAAO,UAAU,IAAI;AAE9B,QAAA,gBAAgB,MAAM,aAAa;AAAA,IACvC,OAAO;AAAA,IACP,kBAAkB;AAAA,EAAA,CACnB;AAED,MAAI,CAAC,cAAe;AAEd,QAAA,mBACJ,iBACA,OAAO,kBAAkB,YACzB,sBAAsB,aAAa,IAC/B,cAAc,OACd;AAEN,QAAM,YAAwC;AAAA,IAC5C,UAAU;AAAA,MACR,UAAU;AAAA,IACZ;AAAA,IACA;AAAA,IACA,QAAQ,mBAAmB,CAAC,gBAAgB,IAAI,CAAC;AAAA,EAAA;AAGnD,QAAM,IAAIC,MAAAA,oBAAoB;AAAA,IAC5B;AAAA,EAAA,CACD;AACH;AAEK,MAAM,mBAAyC;AAAA,EACpD,UAAU;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,EACR,QAAQ,CAAC;AACX;;;"}
|
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const decodeFormdata = require("decode-formdata");
|
|
4
4
|
const utils = require("./utils.cjs");
|
|
5
5
|
const error = require("./error.cjs");
|
|
6
|
+
const isFormValidationError = (error2) => {
|
|
7
|
+
return typeof error2 === "object";
|
|
8
|
+
};
|
|
6
9
|
const createServerValidate = (defaultOpts) => async (ctx, formData, info) => {
|
|
7
10
|
const { validatorAdapter, onServerValidate } = defaultOpts;
|
|
8
11
|
const runValidator = async (propsValue) => {
|
|
@@ -13,14 +16,18 @@ const createServerValidate = (defaultOpts) => async (ctx, formData, info) => {
|
|
|
13
16
|
};
|
|
14
17
|
const referer = ctx.request.headers.get("referer");
|
|
15
18
|
const data = decodeFormdata.decode(formData, info);
|
|
16
|
-
const onServerError = await runValidator({
|
|
19
|
+
const onServerError = await runValidator({
|
|
20
|
+
value: data,
|
|
21
|
+
validationSource: "form"
|
|
22
|
+
});
|
|
17
23
|
if (!onServerError) return;
|
|
24
|
+
const onServerErrorStr = onServerError && typeof onServerError !== "string" && isFormValidationError(onServerError) ? onServerError.form : onServerError;
|
|
18
25
|
const formState = {
|
|
19
26
|
errorMap: {
|
|
20
27
|
onServer: onServerError
|
|
21
28
|
},
|
|
22
29
|
values: data,
|
|
23
|
-
errors:
|
|
30
|
+
errors: onServerErrorStr ? [onServerErrorStr] : []
|
|
24
31
|
};
|
|
25
32
|
const cookie = await utils._tanstackInternalsCookie.serialize(formState);
|
|
26
33
|
throw new error.ServerValidateError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerValidate.cjs","sources":["../../../src/start/createServerValidate.tsx"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { _tanstackInternalsCookie } from './utils'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { FetchFn } from '@tanstack/start'\nimport type { ServerFormState } from './types'\n\ntype Ctx = Parameters<FetchFn<FormData, unknown>>[1]\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (ctx: Ctx, formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {
|
|
1
|
+
{"version":3,"file":"createServerValidate.cjs","sources":["../../../src/start/createServerValidate.tsx"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { _tanstackInternalsCookie } from './utils'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n FormValidationError,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { FetchFn } from '@tanstack/start'\nimport type { ServerFormState } from './types'\n\ntype Ctx = Parameters<FetchFn<FormData, unknown>>[1]\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nconst isFormValidationError = (\n error: unknown,\n): error is FormValidationError<unknown> => {\n return typeof error === 'object'\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (ctx: Ctx, formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {\n value: TFormData\n validationSource: 'form'\n }) => {\n if (validatorAdapter && typeof onServerValidate !== 'function') {\n return validatorAdapter().validateAsync(propsValue, onServerValidate)\n }\n\n return (onServerValidate as OnServerValidateFn<TFormData>)(propsValue)\n }\n\n const referer = ctx.request.headers.get('referer')!\n\n const data = decode(formData, info) as never as TFormData\n\n const onServerError = await runValidator({\n value: data,\n validationSource: 'form',\n })\n\n if (!onServerError) return\n\n const onServerErrorStr =\n onServerError &&\n typeof onServerError !== 'string' &&\n isFormValidationError(onServerError)\n ? onServerError.form\n : onServerError\n\n const formState: ServerFormState<TFormData> = {\n errorMap: {\n onServer: onServerError,\n },\n values: data,\n errors: onServerErrorStr ? [onServerErrorStr] : [],\n }\n\n const cookie = await _tanstackInternalsCookie.serialize(formState)\n\n throw new ServerValidateError({\n response: new Response('ok', {\n headers: {\n Location: referer,\n 'Set-Cookie': cookie,\n },\n status: 302,\n }),\n formState: formState,\n })\n }\n"],"names":["error","decode","_tanstackInternalsCookie","ServerValidateError"],"mappings":";;;;;AAiCA,MAAM,wBAAwB,CAC5BA,WAC0C;AAC1C,SAAO,OAAOA,WAAU;AAC1B;AAEO,MAAM,uBACX,CAME,gBAEF,OAAO,KAAU,UAAoB,SAAwC;AACrE,QAAA,EAAE,kBAAkB,iBAAqB,IAAA;AAEzC,QAAA,eAAe,OAAO,eAGtB;AACA,QAAA,oBAAoB,OAAO,qBAAqB,YAAY;AAC9D,aAAO,iBAAiB,EAAE,cAAc,YAAY,gBAAgB;AAAA,IACtE;AAEA,WAAQ,iBAAmD,UAAU;AAAA,EAAA;AAGvE,QAAM,UAAU,IAAI,QAAQ,QAAQ,IAAI,SAAS;AAE3C,QAAA,OAAOC,eAAAA,OAAO,UAAU,IAAI;AAE5B,QAAA,gBAAgB,MAAM,aAAa;AAAA,IACvC,OAAO;AAAA,IACP,kBAAkB;AAAA,EAAA,CACnB;AAED,MAAI,CAAC,cAAe;AAEd,QAAA,mBACJ,iBACA,OAAO,kBAAkB,YACzB,sBAAsB,aAAa,IAC/B,cAAc,OACd;AAEN,QAAM,YAAwC;AAAA,IAC5C,UAAU;AAAA,MACR,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,mBAAmB,CAAC,gBAAgB,IAAI,CAAC;AAAA,EAAA;AAGnD,QAAM,SAAS,MAAMC,MAAAA,yBAAyB,UAAU,SAAS;AAEjE,QAAM,IAAIC,MAAAA,oBAAoB;AAAA,IAC5B,UAAU,IAAI,SAAS,MAAM;AAAA,MAC3B,SAAS;AAAA,QACP,UAAU;AAAA,QACV,cAAc;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AAAA,IACD;AAAA,EAAA,CACD;AACH;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useField.cjs","sources":["../../src/useField.tsx"],"sourcesContent":["import React, {
|
|
1
|
+
{"version":3,"file":"useField.cjs","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { FunctionComponent } from 'react'\nimport type { NodeType, UseFieldOptions } from './types'\nimport type { DeepKeys, DeepValue, Validator } from '@tanstack/form-core'\n\ninterface ReactFieldApi<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> {\n /**\n * A pre-bound and type-safe sub-field component using this field as a root.\n */\n Field: FieldComponent<TParentData, TFormValidator>\n}\n\n/**\n * A type representing a hook for using a field in a form with the given form data type.\n *\n * A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field.\n */\nexport type UseField<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: Omit<\n UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>,\n 'form'\n >,\n) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\n/**\n * A hook for managing a field in a form.\n * @param opts An object with field options.\n *\n * @returns The `FieldApi` instance for the specified field.\n */\nexport function useField<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n) {\n const [fieldApi] = useState(() => {\n const api = new FieldApi({\n ...opts,\n form: opts.form,\n name: opts.name,\n })\n\n const extendedApi: typeof api & ReactFieldApi<TParentData, TFormValidator> =\n api as never\n\n extendedApi.Field = Field as never\n\n return extendedApi\n })\n\n useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])\n\n /**\n * fieldApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n fieldApi.update(opts)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state) => {\n return [state.meta, Object.keys(state.value ?? []).length]\n }\n : undefined,\n )\n\n return fieldApi\n}\n\n/**\n * @param children A render function that takes a field API instance and returns a React element.\n */\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = {\n children: (\n fieldApi: FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n ) => NodeType\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\n/**\n * A type alias representing a field component for a specific form data type.\n */\nexport type FieldComponent<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: Omit<\n FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n 'form'\n>) => NodeType\n\n/**\n * A function component that takes field options and a render function as children and returns a React component.\n *\n * The `Field` component uses the `useField` hook internally to manage the field instance.\n */\nexport const Field = (<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n>): NodeType => {\n const fieldApi = useField(fieldOptions as any)\n\n return (<>{functionalUpdate(children, fieldApi as any)}</>) as never\n}) satisfies FunctionComponent<FieldComponentProps<any, any, any, any, any>>\n"],"names":["useState","FieldApi","useIsomorphicLayoutEffect","useStore","jsx","Fragment","functionalUpdate"],"mappings":";;;;;;;AAiDO,SAAS,SAWd,MAOA;AACA,QAAM,CAAC,QAAQ,IAAIA,MAAAA,SAAS,MAAM;AAC1B,UAAA,MAAM,IAAIC,kBAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,IAAA,CACZ;AAED,UAAM,cACJ;AAEF,gBAAY,QAAQ;AAEb,WAAA;AAAA,EAAA,CACR;AAEDC,4BAAAA,0BAA0B,SAAS,OAAO,CAAC,QAAQ,CAAC;AAMpDA,4BAAAA,0BAA0B,MAAM;AAC9B,aAAS,OAAO,IAAI;AAAA,EAAA,CACrB;AAEDC,aAAA;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,SAAS,CAAA,CAAE,EAAE,MAAM;AAAA,IAE3D,IAAA;AAAA,EAAA;AAGC,SAAA;AACT;AA4DO,MAAM,QAAS,CAUpB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAMgB;AACR,QAAA,WAAW,SAAS,YAAmB;AAE7C,SAAWC,2BAAA,IAAAC,WAAA,UAAA,EAAA,UAAAC,SAAA,iBAAiB,UAAU,QAAe,EAAE,CAAA;AACzD;;;"}
|
package/dist/cjs/useForm.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.cjs","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, { useState } from 'react'\nimport { Field,
|
|
1
|
+
{"version":3,"file":"useForm.cjs","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, { useState } from 'react'\nimport { Field, useField } from './useField'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { FieldComponent, UseField } from './useField'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\nimport type { NodeType } from './types'\n\n/**\n * Fields that are added onto the `FormAPI` from `@tanstack/form-core` and returned from `useForm`\n */\nexport interface ReactFormApi<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * A React component to render form fields. With this, you can render and manage individual form fields.\n */\n Field: FieldComponent<TFormData, TFormValidator>\n /**\n * A custom React hook that provides functionalities related to individual form fields. It gives you access to field values, errors, and allows you to set or update field values.\n */\n useField: UseField<TFormData, TFormValidator>\n /**\n * A `useStore` hook that connects to the internal store of the form. It can be used to access the form's current state or any other related state information. You can optionally pass in a selector function to cherry-pick specific parts of the state\n */\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n /**\n * A `Subscribe` function that allows you to listen and react to changes in the form's state. It's especially useful when you need to execute side effects or render specific components in response to state updates.\n */\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n /**\n TypeScript versions <=5.0.4 have a bug that prevents\n the type of the `TSelected` generic from being inferred\n from the return type of this method.\n\n In these versions, `TSelected` will fall back to the default\n type (or `unknown` if that's not defined).\n\n @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}\n @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}\n */\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => NodeType) | NodeType\n }) => NodeType\n}\n\n/**\n * A custom React Hook that returns an extended instance of the `FormApi` class.\n *\n * This API encapsulates all the necessary functionalities related to the form. It allows you to manage form state, handle submissions, and interact with form fields\n */\nexport function useForm<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n>(opts?: FormOptions<TFormData, TFormValidator>) {\n const [formApi] = useState(() => {\n const api = new FormApi<TFormData, TFormValidator>(opts)\n\n const extendedApi: typeof api & ReactFormApi<TFormData, TFormValidator> =\n api as never\n extendedApi.Field = function APIField(props) {\n return (<Field {...props} form={api} />) as never\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n extendedApi.useField = (props) => useField({ ...props, form: api })\n extendedApi.useStore = (selector) => {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(api.store as any, selector as any) as any\n }\n extendedApi.Subscribe = (props) => {\n return functionalUpdate(\n props.children,\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(api.store as any, props.selector as any),\n ) as any\n }\n\n return extendedApi\n })\n\n useIsomorphicLayoutEffect(formApi.mount, [])\n\n formApi.useStore((state) => state.isSubmitting)\n\n /**\n * formApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n formApi.update(opts)\n })\n\n return formApi\n}\n"],"names":["useState","FormApi","jsx","Field","useField","useStore","functionalUpdate","useIsomorphicLayoutEffect"],"mappings":";;;;;;;;AAwDO,SAAS,QAGd,MAA+C;AAC/C,QAAM,CAAC,OAAO,IAAIA,MAAAA,SAAS,MAAM;AACzB,UAAA,MAAM,IAAIC,iBAAmC,IAAI;AAEvD,UAAM,cACJ;AACU,gBAAA,QAAQ,SAAS,SAAS,OAAO;AAC3C,aAASC,2BAAAA,IAAAC,SAAAA,OAAA,EAAO,GAAG,OAAO,MAAM,IAAK,CAAA;AAAA,IAAA;AAG3B,gBAAA,WAAW,CAAC,UAAUC,SAAA,SAAS,EAAE,GAAG,OAAO,MAAM,IAAA,CAAK;AACtD,gBAAA,WAAW,CAAC,aAAa;AAE5B,aAAAC,oBAAS,IAAI,OAAc,QAAe;AAAA,IAAA;AAEvC,gBAAA,YAAY,CAAC,UAAU;AAC1B,aAAAC,SAAA;AAAA,QACL,MAAM;AAAA;AAAA,QAEND,WAAAA,SAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAAA;AAAA,IAClD;AAGK,WAAA;AAAA,EAAA,CACR;AAEyBE,4BAAAA,0BAAA,QAAQ,OAAO,CAAA,CAAE;AAE3C,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9CA,4BAAAA,0BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;;"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { decode } from "decode-formdata";
|
|
2
2
|
import { ServerValidateError } from "./error.js";
|
|
3
|
+
const isFormValidationError = (error) => {
|
|
4
|
+
return typeof error === "object";
|
|
5
|
+
};
|
|
3
6
|
const createServerValidate = (defaultOpts) => async (formData, info) => {
|
|
4
7
|
const { validatorAdapter, onServerValidate } = defaultOpts;
|
|
5
8
|
const runValidator = async (propsValue) => {
|
|
@@ -9,14 +12,18 @@ const createServerValidate = (defaultOpts) => async (formData, info) => {
|
|
|
9
12
|
return onServerValidate(propsValue);
|
|
10
13
|
};
|
|
11
14
|
const values = decode(formData, info);
|
|
12
|
-
const onServerError = await runValidator({
|
|
15
|
+
const onServerError = await runValidator({
|
|
16
|
+
value: values,
|
|
17
|
+
validationSource: "form"
|
|
18
|
+
});
|
|
13
19
|
if (!onServerError) return;
|
|
20
|
+
const onServerErrorStr = onServerError && typeof onServerError !== "string" && isFormValidationError(onServerError) ? onServerError.form : onServerError;
|
|
14
21
|
const formState = {
|
|
15
22
|
errorMap: {
|
|
16
23
|
onServer: onServerError
|
|
17
24
|
},
|
|
18
25
|
values,
|
|
19
|
-
errors:
|
|
26
|
+
errors: onServerErrorStr ? [onServerErrorStr] : []
|
|
20
27
|
};
|
|
21
28
|
throw new ServerValidateError({
|
|
22
29
|
formState
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerValidate.js","sources":["../../../src/nextjs/createServerValidate.ts"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { ServerFormState } from './types'\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {
|
|
1
|
+
{"version":3,"file":"createServerValidate.js","sources":["../../../src/nextjs/createServerValidate.ts"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n FormValidationError,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { ServerFormState } from './types'\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nconst isFormValidationError = (\n error: unknown,\n): error is FormValidationError<unknown> => {\n return typeof error === 'object'\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {\n value: TFormData\n validationSource: 'form'\n }) => {\n if (validatorAdapter && typeof onServerValidate !== 'function') {\n return validatorAdapter().validateAsync(propsValue, onServerValidate)\n }\n\n return (onServerValidate as OnServerValidateFn<TFormData>)(propsValue)\n }\n\n const values = decode(formData, info) as never as TFormData\n\n const onServerError = await runValidator({\n value: values,\n validationSource: 'form',\n })\n\n if (!onServerError) return\n\n const onServerErrorStr =\n onServerError &&\n typeof onServerError !== 'string' &&\n isFormValidationError(onServerError)\n ? onServerError.form\n : onServerError\n\n const formState: ServerFormState<TFormData> = {\n errorMap: {\n onServer: onServerError,\n },\n values,\n errors: onServerErrorStr ? [onServerErrorStr] : [],\n }\n\n throw new ServerValidateError({\n formState,\n })\n }\n\nexport const initialFormState: ServerFormState<any> = {\n errorMap: {\n onServer: undefined,\n },\n values: undefined,\n errors: [],\n}\n"],"names":[],"mappings":";;AA6BA,MAAM,wBAAwB,CAC5B,UAC0C;AAC1C,SAAO,OAAO,UAAU;AAC1B;AAEO,MAAM,uBACX,CAME,gBAEF,OAAO,UAAoB,SAAwC;AAC3D,QAAA,EAAE,kBAAkB,iBAAqB,IAAA;AAEzC,QAAA,eAAe,OAAO,eAGtB;AACA,QAAA,oBAAoB,OAAO,qBAAqB,YAAY;AAC9D,aAAO,iBAAiB,EAAE,cAAc,YAAY,gBAAgB;AAAA,IACtE;AAEA,WAAQ,iBAAmD,UAAU;AAAA,EAAA;AAGjE,QAAA,SAAS,OAAO,UAAU,IAAI;AAE9B,QAAA,gBAAgB,MAAM,aAAa;AAAA,IACvC,OAAO;AAAA,IACP,kBAAkB;AAAA,EAAA,CACnB;AAED,MAAI,CAAC,cAAe;AAEd,QAAA,mBACJ,iBACA,OAAO,kBAAkB,YACzB,sBAAsB,aAAa,IAC/B,cAAc,OACd;AAEN,QAAM,YAAwC;AAAA,IAC5C,UAAU;AAAA,MACR,UAAU;AAAA,IACZ;AAAA,IACA;AAAA,IACA,QAAQ,mBAAmB,CAAC,gBAAgB,IAAI,CAAC;AAAA,EAAA;AAGnD,QAAM,IAAI,oBAAoB;AAAA,IAC5B;AAAA,EAAA,CACD;AACH;AAEK,MAAM,mBAAyC;AAAA,EACpD,UAAU;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,EACR,QAAQ,CAAC;AACX;"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { decode } from "decode-formdata";
|
|
2
2
|
import { _tanstackInternalsCookie } from "./utils.js";
|
|
3
3
|
import { ServerValidateError } from "./error.js";
|
|
4
|
+
const isFormValidationError = (error) => {
|
|
5
|
+
return typeof error === "object";
|
|
6
|
+
};
|
|
4
7
|
const createServerValidate = (defaultOpts) => async (ctx, formData, info) => {
|
|
5
8
|
const { validatorAdapter, onServerValidate } = defaultOpts;
|
|
6
9
|
const runValidator = async (propsValue) => {
|
|
@@ -11,14 +14,18 @@ const createServerValidate = (defaultOpts) => async (ctx, formData, info) => {
|
|
|
11
14
|
};
|
|
12
15
|
const referer = ctx.request.headers.get("referer");
|
|
13
16
|
const data = decode(formData, info);
|
|
14
|
-
const onServerError = await runValidator({
|
|
17
|
+
const onServerError = await runValidator({
|
|
18
|
+
value: data,
|
|
19
|
+
validationSource: "form"
|
|
20
|
+
});
|
|
15
21
|
if (!onServerError) return;
|
|
22
|
+
const onServerErrorStr = onServerError && typeof onServerError !== "string" && isFormValidationError(onServerError) ? onServerError.form : onServerError;
|
|
16
23
|
const formState = {
|
|
17
24
|
errorMap: {
|
|
18
25
|
onServer: onServerError
|
|
19
26
|
},
|
|
20
27
|
values: data,
|
|
21
|
-
errors:
|
|
28
|
+
errors: onServerErrorStr ? [onServerErrorStr] : []
|
|
22
29
|
};
|
|
23
30
|
const cookie = await _tanstackInternalsCookie.serialize(formState);
|
|
24
31
|
throw new ServerValidateError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerValidate.js","sources":["../../../src/start/createServerValidate.tsx"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { _tanstackInternalsCookie } from './utils'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { FetchFn } from '@tanstack/start'\nimport type { ServerFormState } from './types'\n\ntype Ctx = Parameters<FetchFn<FormData, unknown>>[1]\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (ctx: Ctx, formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {
|
|
1
|
+
{"version":3,"file":"createServerValidate.js","sources":["../../../src/start/createServerValidate.tsx"],"sourcesContent":["import { decode } from 'decode-formdata'\nimport { _tanstackInternalsCookie } from './utils'\nimport { ServerValidateError } from './error'\nimport type {\n FormOptions,\n FormValidationError,\n ValidationError,\n Validator,\n} from '@tanstack/form-core'\nimport type { FetchFn } from '@tanstack/start'\nimport type { ServerFormState } from './types'\n\ntype Ctx = Parameters<FetchFn<FormData, unknown>>[1]\n\ntype OnServerValidateFn<TFormData> = (props: {\n value: TFormData\n}) => ValidationError | Promise<ValidationError>\n\ntype OnServerValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | OnServerValidateFn<TFormData>\n : OnServerValidateFn<TFormData>\n\ninterface CreateServerValidateOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> extends FormOptions<TFormData, TFormValidator> {\n onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>\n}\n\nconst isFormValidationError = (\n error: unknown,\n): error is FormValidationError<unknown> => {\n return typeof error === 'object'\n}\n\nexport const createServerValidate =\n <\n TFormData,\n TFormValidator extends\n | Validator<TFormData, unknown>\n | undefined = undefined,\n >(\n defaultOpts: CreateServerValidateOptions<TFormData, TFormValidator>,\n ) =>\n async (ctx: Ctx, formData: FormData, info?: Parameters<typeof decode>[1]) => {\n const { validatorAdapter, onServerValidate } = defaultOpts\n\n const runValidator = async (propsValue: {\n value: TFormData\n validationSource: 'form'\n }) => {\n if (validatorAdapter && typeof onServerValidate !== 'function') {\n return validatorAdapter().validateAsync(propsValue, onServerValidate)\n }\n\n return (onServerValidate as OnServerValidateFn<TFormData>)(propsValue)\n }\n\n const referer = ctx.request.headers.get('referer')!\n\n const data = decode(formData, info) as never as TFormData\n\n const onServerError = await runValidator({\n value: data,\n validationSource: 'form',\n })\n\n if (!onServerError) return\n\n const onServerErrorStr =\n onServerError &&\n typeof onServerError !== 'string' &&\n isFormValidationError(onServerError)\n ? onServerError.form\n : onServerError\n\n const formState: ServerFormState<TFormData> = {\n errorMap: {\n onServer: onServerError,\n },\n values: data,\n errors: onServerErrorStr ? [onServerErrorStr] : [],\n }\n\n const cookie = await _tanstackInternalsCookie.serialize(formState)\n\n throw new ServerValidateError({\n response: new Response('ok', {\n headers: {\n Location: referer,\n 'Set-Cookie': cookie,\n },\n status: 302,\n }),\n formState: formState,\n })\n }\n"],"names":[],"mappings":";;;AAiCA,MAAM,wBAAwB,CAC5B,UAC0C;AAC1C,SAAO,OAAO,UAAU;AAC1B;AAEO,MAAM,uBACX,CAME,gBAEF,OAAO,KAAU,UAAoB,SAAwC;AACrE,QAAA,EAAE,kBAAkB,iBAAqB,IAAA;AAEzC,QAAA,eAAe,OAAO,eAGtB;AACA,QAAA,oBAAoB,OAAO,qBAAqB,YAAY;AAC9D,aAAO,iBAAiB,EAAE,cAAc,YAAY,gBAAgB;AAAA,IACtE;AAEA,WAAQ,iBAAmD,UAAU;AAAA,EAAA;AAGvE,QAAM,UAAU,IAAI,QAAQ,QAAQ,IAAI,SAAS;AAE3C,QAAA,OAAO,OAAO,UAAU,IAAI;AAE5B,QAAA,gBAAgB,MAAM,aAAa;AAAA,IACvC,OAAO;AAAA,IACP,kBAAkB;AAAA,EAAA,CACnB;AAED,MAAI,CAAC,cAAe;AAEd,QAAA,mBACJ,iBACA,OAAO,kBAAkB,YACzB,sBAAsB,aAAa,IAC/B,cAAc,OACd;AAEN,QAAM,YAAwC;AAAA,IAC5C,UAAU;AAAA,MACR,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,mBAAmB,CAAC,gBAAgB,IAAI,CAAC;AAAA,EAAA;AAGnD,QAAM,SAAS,MAAM,yBAAyB,UAAU,SAAS;AAEjE,QAAM,IAAI,oBAAoB;AAAA,IAC5B,UAAU,IAAI,SAAS,MAAM;AAAA,MAC3B,SAAS;AAAA,QACP,UAAU;AAAA,QACV,cAAc;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AAAA,IACD;AAAA,EAAA,CACD;AACH;"}
|
package/dist/esm/useField.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useField.js","sources":["../../src/useField.tsx"],"sourcesContent":["import React, {
|
|
1
|
+
{"version":3,"file":"useField.js","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { FunctionComponent } from 'react'\nimport type { NodeType, UseFieldOptions } from './types'\nimport type { DeepKeys, DeepValue, Validator } from '@tanstack/form-core'\n\ninterface ReactFieldApi<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> {\n /**\n * A pre-bound and type-safe sub-field component using this field as a root.\n */\n Field: FieldComponent<TParentData, TFormValidator>\n}\n\n/**\n * A type representing a hook for using a field in a form with the given form data type.\n *\n * A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field.\n */\nexport type UseField<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: Omit<\n UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>,\n 'form'\n >,\n) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\n/**\n * A hook for managing a field in a form.\n * @param opts An object with field options.\n *\n * @returns The `FieldApi` instance for the specified field.\n */\nexport function useField<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n) {\n const [fieldApi] = useState(() => {\n const api = new FieldApi({\n ...opts,\n form: opts.form,\n name: opts.name,\n })\n\n const extendedApi: typeof api & ReactFieldApi<TParentData, TFormValidator> =\n api as never\n\n extendedApi.Field = Field as never\n\n return extendedApi\n })\n\n useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])\n\n /**\n * fieldApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n fieldApi.update(opts)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state) => {\n return [state.meta, Object.keys(state.value ?? []).length]\n }\n : undefined,\n )\n\n return fieldApi\n}\n\n/**\n * @param children A render function that takes a field API instance and returns a React element.\n */\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = {\n children: (\n fieldApi: FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n ) => NodeType\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\n/**\n * A type alias representing a field component for a specific form data type.\n */\nexport type FieldComponent<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: Omit<\n FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n 'form'\n>) => NodeType\n\n/**\n * A function component that takes field options and a render function as children and returns a React component.\n *\n * The `Field` component uses the `useField` hook internally to manage the field instance.\n */\nexport const Field = (<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n>): NodeType => {\n const fieldApi = useField(fieldOptions as any)\n\n return (<>{functionalUpdate(children, fieldApi as any)}</>) as never\n}) satisfies FunctionComponent<FieldComponentProps<any, any, any, any, any>>\n"],"names":[],"mappings":";;;;;AAiDO,SAAS,SAWd,MAOA;AACA,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM;AAC1B,UAAA,MAAM,IAAI,SAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,IAAA,CACZ;AAED,UAAM,cACJ;AAEF,gBAAY,QAAQ;AAEb,WAAA;AAAA,EAAA,CACR;AAED,4BAA0B,SAAS,OAAO,CAAC,QAAQ,CAAC;AAMpD,4BAA0B,MAAM;AAC9B,aAAS,OAAO,IAAI;AAAA,EAAA,CACrB;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,SAAS,CAAA,CAAE,EAAE,MAAM;AAAA,IAE3D,IAAA;AAAA,EAAA;AAGC,SAAA;AACT;AA4DO,MAAM,QAAS,CAUpB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAMgB;AACR,QAAA,WAAW,SAAS,YAAmB;AAE7C,SAAW,oBAAA,UAAA,EAAA,UAAA,iBAAiB,UAAU,QAAe,EAAE,CAAA;AACzD;"}
|
package/dist/esm/useForm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.js","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, { useState } from 'react'\nimport { Field,
|
|
1
|
+
{"version":3,"file":"useForm.js","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, { useState } from 'react'\nimport { Field, useField } from './useField'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { FieldComponent, UseField } from './useField'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\nimport type { NodeType } from './types'\n\n/**\n * Fields that are added onto the `FormAPI` from `@tanstack/form-core` and returned from `useForm`\n */\nexport interface ReactFormApi<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * A React component to render form fields. With this, you can render and manage individual form fields.\n */\n Field: FieldComponent<TFormData, TFormValidator>\n /**\n * A custom React hook that provides functionalities related to individual form fields. It gives you access to field values, errors, and allows you to set or update field values.\n */\n useField: UseField<TFormData, TFormValidator>\n /**\n * A `useStore` hook that connects to the internal store of the form. It can be used to access the form's current state or any other related state information. You can optionally pass in a selector function to cherry-pick specific parts of the state\n */\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n /**\n * A `Subscribe` function that allows you to listen and react to changes in the form's state. It's especially useful when you need to execute side effects or render specific components in response to state updates.\n */\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n /**\n TypeScript versions <=5.0.4 have a bug that prevents\n the type of the `TSelected` generic from being inferred\n from the return type of this method.\n\n In these versions, `TSelected` will fall back to the default\n type (or `unknown` if that's not defined).\n\n @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}\n @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}\n */\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => NodeType) | NodeType\n }) => NodeType\n}\n\n/**\n * A custom React Hook that returns an extended instance of the `FormApi` class.\n *\n * This API encapsulates all the necessary functionalities related to the form. It allows you to manage form state, handle submissions, and interact with form fields\n */\nexport function useForm<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n>(opts?: FormOptions<TFormData, TFormValidator>) {\n const [formApi] = useState(() => {\n const api = new FormApi<TFormData, TFormValidator>(opts)\n\n const extendedApi: typeof api & ReactFormApi<TFormData, TFormValidator> =\n api as never\n extendedApi.Field = function APIField(props) {\n return (<Field {...props} form={api} />) as never\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n extendedApi.useField = (props) => useField({ ...props, form: api })\n extendedApi.useStore = (selector) => {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(api.store as any, selector as any) as any\n }\n extendedApi.Subscribe = (props) => {\n return functionalUpdate(\n props.children,\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(api.store as any, props.selector as any),\n ) as any\n }\n\n return extendedApi\n })\n\n useIsomorphicLayoutEffect(formApi.mount, [])\n\n formApi.useStore((state) => state.isSubmitting)\n\n /**\n * formApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n formApi.update(opts)\n })\n\n return formApi\n}\n"],"names":[],"mappings":";;;;;;AAwDO,SAAS,QAGd,MAA+C;AAC/C,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM;AACzB,UAAA,MAAM,IAAI,QAAmC,IAAI;AAEvD,UAAM,cACJ;AACU,gBAAA,QAAQ,SAAS,SAAS,OAAO;AAC3C,aAAS,oBAAA,OAAA,EAAO,GAAG,OAAO,MAAM,IAAK,CAAA;AAAA,IAAA;AAG3B,gBAAA,WAAW,CAAC,UAAU,SAAS,EAAE,GAAG,OAAO,MAAM,IAAA,CAAK;AACtD,gBAAA,WAAW,CAAC,aAAa;AAE5B,aAAA,SAAS,IAAI,OAAc,QAAe;AAAA,IAAA;AAEvC,gBAAA,YAAY,CAAC,UAAU;AAC1B,aAAA;AAAA,QACL,MAAM;AAAA;AAAA,QAEN,SAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAAA;AAAA,IAClD;AAGK,WAAA;AAAA,EAAA,CACR;AAEyB,4BAAA,QAAQ,OAAO,CAAA,CAAE;AAE3C,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,4BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-form",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Powerful, type-safe forms for React.",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -57,19 +57,19 @@
|
|
|
57
57
|
"src"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@remix-run/node": "^2.
|
|
60
|
+
"@remix-run/node": "^2.12.0",
|
|
61
61
|
"@tanstack/react-store": "^0.5.5",
|
|
62
62
|
"decode-formdata": "^0.8.0",
|
|
63
|
-
"@tanstack/form-core": "0.
|
|
63
|
+
"@tanstack/form-core": "0.33.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@tanstack/start": "^1.
|
|
66
|
+
"@tanstack/start": "^1.57.15",
|
|
67
67
|
"@types/react": "^18.3.3",
|
|
68
68
|
"@types/react-dom": "^18.3.0",
|
|
69
69
|
"@vitejs/plugin-react": "^4.3.1",
|
|
70
70
|
"react": "^18.3.1",
|
|
71
71
|
"react-dom": "^18.3.1",
|
|
72
|
-
"vite": "^5.4.
|
|
72
|
+
"vite": "^5.4.5"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"@tanstack/start": "^1.43.13",
|
|
@@ -2,6 +2,7 @@ import { decode } from 'decode-formdata'
|
|
|
2
2
|
import { ServerValidateError } from './error'
|
|
3
3
|
import type {
|
|
4
4
|
FormOptions,
|
|
5
|
+
FormValidationError,
|
|
5
6
|
ValidationError,
|
|
6
7
|
Validator,
|
|
7
8
|
} from '@tanstack/form-core'
|
|
@@ -26,6 +27,12 @@ interface CreateServerValidateOptions<
|
|
|
26
27
|
onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
const isFormValidationError = (
|
|
31
|
+
error: unknown,
|
|
32
|
+
): error is FormValidationError<unknown> => {
|
|
33
|
+
return typeof error === 'object'
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
export const createServerValidate =
|
|
30
37
|
<
|
|
31
38
|
TFormData,
|
|
@@ -38,7 +45,10 @@ export const createServerValidate =
|
|
|
38
45
|
async (formData: FormData, info?: Parameters<typeof decode>[1]) => {
|
|
39
46
|
const { validatorAdapter, onServerValidate } = defaultOpts
|
|
40
47
|
|
|
41
|
-
const runValidator = async (propsValue: {
|
|
48
|
+
const runValidator = async (propsValue: {
|
|
49
|
+
value: TFormData
|
|
50
|
+
validationSource: 'form'
|
|
51
|
+
}) => {
|
|
42
52
|
if (validatorAdapter && typeof onServerValidate !== 'function') {
|
|
43
53
|
return validatorAdapter().validateAsync(propsValue, onServerValidate)
|
|
44
54
|
}
|
|
@@ -48,16 +58,26 @@ export const createServerValidate =
|
|
|
48
58
|
|
|
49
59
|
const values = decode(formData, info) as never as TFormData
|
|
50
60
|
|
|
51
|
-
const onServerError = await runValidator({
|
|
61
|
+
const onServerError = await runValidator({
|
|
62
|
+
value: values,
|
|
63
|
+
validationSource: 'form',
|
|
64
|
+
})
|
|
52
65
|
|
|
53
66
|
if (!onServerError) return
|
|
54
67
|
|
|
68
|
+
const onServerErrorStr =
|
|
69
|
+
onServerError &&
|
|
70
|
+
typeof onServerError !== 'string' &&
|
|
71
|
+
isFormValidationError(onServerError)
|
|
72
|
+
? onServerError.form
|
|
73
|
+
: onServerError
|
|
74
|
+
|
|
55
75
|
const formState: ServerFormState<TFormData> = {
|
|
56
76
|
errorMap: {
|
|
57
77
|
onServer: onServerError,
|
|
58
78
|
},
|
|
59
79
|
values,
|
|
60
|
-
errors:
|
|
80
|
+
errors: onServerErrorStr ? [onServerErrorStr] : [],
|
|
61
81
|
}
|
|
62
82
|
|
|
63
83
|
throw new ServerValidateError({
|
|
@@ -3,6 +3,7 @@ import { _tanstackInternalsCookie } from './utils'
|
|
|
3
3
|
import { ServerValidateError } from './error'
|
|
4
4
|
import type {
|
|
5
5
|
FormOptions,
|
|
6
|
+
FormValidationError,
|
|
6
7
|
ValidationError,
|
|
7
8
|
Validator,
|
|
8
9
|
} from '@tanstack/form-core'
|
|
@@ -30,6 +31,12 @@ interface CreateServerValidateOptions<
|
|
|
30
31
|
onServerValidate: OnServerValidateOrFn<TFormData, TFormValidator>
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
const isFormValidationError = (
|
|
35
|
+
error: unknown,
|
|
36
|
+
): error is FormValidationError<unknown> => {
|
|
37
|
+
return typeof error === 'object'
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
export const createServerValidate =
|
|
34
41
|
<
|
|
35
42
|
TFormData,
|
|
@@ -42,7 +49,10 @@ export const createServerValidate =
|
|
|
42
49
|
async (ctx: Ctx, formData: FormData, info?: Parameters<typeof decode>[1]) => {
|
|
43
50
|
const { validatorAdapter, onServerValidate } = defaultOpts
|
|
44
51
|
|
|
45
|
-
const runValidator = async (propsValue: {
|
|
52
|
+
const runValidator = async (propsValue: {
|
|
53
|
+
value: TFormData
|
|
54
|
+
validationSource: 'form'
|
|
55
|
+
}) => {
|
|
46
56
|
if (validatorAdapter && typeof onServerValidate !== 'function') {
|
|
47
57
|
return validatorAdapter().validateAsync(propsValue, onServerValidate)
|
|
48
58
|
}
|
|
@@ -54,16 +64,26 @@ export const createServerValidate =
|
|
|
54
64
|
|
|
55
65
|
const data = decode(formData, info) as never as TFormData
|
|
56
66
|
|
|
57
|
-
const onServerError = await runValidator({
|
|
67
|
+
const onServerError = await runValidator({
|
|
68
|
+
value: data,
|
|
69
|
+
validationSource: 'form',
|
|
70
|
+
})
|
|
58
71
|
|
|
59
72
|
if (!onServerError) return
|
|
60
73
|
|
|
74
|
+
const onServerErrorStr =
|
|
75
|
+
onServerError &&
|
|
76
|
+
typeof onServerError !== 'string' &&
|
|
77
|
+
isFormValidationError(onServerError)
|
|
78
|
+
? onServerError.form
|
|
79
|
+
: onServerError
|
|
80
|
+
|
|
61
81
|
const formState: ServerFormState<TFormData> = {
|
|
62
82
|
errorMap: {
|
|
63
83
|
onServer: onServerError,
|
|
64
84
|
},
|
|
65
85
|
values: data,
|
|
66
|
-
errors:
|
|
86
|
+
errors: onServerErrorStr ? [onServerErrorStr] : [],
|
|
67
87
|
}
|
|
68
88
|
|
|
69
89
|
const cookie = await _tanstackInternalsCookie.serialize(formState)
|
package/src/useField.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
2
|
import { useStore } from '@tanstack/react-store'
|
|
3
3
|
import { FieldApi, functionalUpdate } from '@tanstack/form-core'
|
|
4
4
|
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
|
|
5
|
+
import type { FunctionComponent } from 'react'
|
|
5
6
|
import type { NodeType, UseFieldOptions } from './types'
|
|
6
7
|
import type { DeepKeys, DeepValue, Validator } from '@tanstack/form-core'
|
|
7
8
|
|
package/src/useForm.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { FormApi, functionalUpdate } from '@tanstack/form-core'
|
|
2
2
|
import { useStore } from '@tanstack/react-store'
|
|
3
3
|
import React, { useState } from 'react'
|
|
4
|
-
import { Field,
|
|
4
|
+
import { Field, useField } from './useField'
|
|
5
5
|
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
|
|
6
|
+
import type { FieldComponent, UseField } from './useField'
|
|
6
7
|
import type { NoInfer } from '@tanstack/react-store'
|
|
7
8
|
import type { FormOptions, FormState, Validator } from '@tanstack/form-core'
|
|
8
9
|
import type { NodeType } from './types'
|