@tanstack/form-core 0.3.7 → 0.4.1

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.
Files changed (59) hide show
  1. package/build/legacy/FieldApi.cjs +46 -26
  2. package/build/legacy/FieldApi.cjs.map +1 -1
  3. package/build/legacy/FieldApi.d.cts +1 -0
  4. package/build/legacy/FieldApi.d.ts +1 -0
  5. package/build/legacy/FieldApi.js +46 -18
  6. package/build/legacy/FieldApi.js.map +1 -1
  7. package/build/legacy/FormApi.cjs +10 -12
  8. package/build/legacy/FormApi.cjs.map +1 -1
  9. package/build/legacy/FormApi.d.cts +2 -1
  10. package/build/legacy/FormApi.d.ts +2 -1
  11. package/build/legacy/FormApi.js +10 -14
  12. package/build/legacy/FormApi.js.map +1 -1
  13. package/build/legacy/index.cjs +3 -1
  14. package/build/legacy/index.cjs.map +1 -1
  15. package/build/legacy/index.d.cts +48 -52
  16. package/build/legacy/index.d.ts +48 -52
  17. package/build/legacy/index.js +1 -0
  18. package/build/legacy/index.js.map +1 -1
  19. package/build/legacy/types.cjs +19 -0
  20. package/build/legacy/types.cjs.map +1 -0
  21. package/build/legacy/types.d.cts +7 -0
  22. package/build/legacy/types.d.ts +7 -0
  23. package/build/legacy/types.js +1 -0
  24. package/build/legacy/utils.js +0 -2
  25. package/build/legacy/utils.js.map +1 -1
  26. package/build/modern/FieldApi.cjs +44 -9
  27. package/build/modern/FieldApi.cjs.map +1 -1
  28. package/build/modern/FieldApi.d.cts +1 -0
  29. package/build/modern/FieldApi.d.ts +1 -0
  30. package/build/modern/FieldApi.js +44 -9
  31. package/build/modern/FieldApi.js.map +1 -1
  32. package/build/modern/FormApi.cjs +10 -12
  33. package/build/modern/FormApi.cjs.map +1 -1
  34. package/build/modern/FormApi.d.cts +2 -1
  35. package/build/modern/FormApi.d.ts +2 -1
  36. package/build/modern/FormApi.js +10 -12
  37. package/build/modern/FormApi.js.map +1 -1
  38. package/build/modern/index.cjs +3 -1
  39. package/build/modern/index.cjs.map +1 -1
  40. package/build/modern/index.d.cts +48 -52
  41. package/build/modern/index.d.ts +48 -52
  42. package/build/modern/index.js +1 -0
  43. package/build/modern/index.js.map +1 -1
  44. package/build/modern/types.cjs +19 -0
  45. package/build/modern/types.cjs.map +1 -0
  46. package/build/modern/types.d.cts +7 -0
  47. package/build/modern/types.d.ts +7 -0
  48. package/build/modern/types.js +1 -0
  49. package/build/modern/types.js.map +1 -0
  50. package/package.json +1 -1
  51. package/src/FieldApi.ts +171 -44
  52. package/src/FormApi.ts +61 -46
  53. package/src/index.ts +1 -0
  54. package/src/tests/FieldApi.spec.ts +1 -1
  55. package/src/tests/FieldApi.test-d.ts +26 -11
  56. package/src/tests/FormApi.spec.ts +1 -1
  57. package/src/types.ts +7 -0
  58. package/build/legacy/chunk-4QZDOMDG.js +0 -19
  59. /package/build/legacy/{chunk-4QZDOMDG.js.map → types.js.map} +0 -0
@@ -1,5 +1,3 @@
1
- import "./chunk-4QZDOMDG.js";
2
-
3
1
  // src/FormApi.ts
4
2
  import { Store } from "@tanstack/store";
5
3
  import { functionalUpdate, getBy, isNonEmptyArray, setBy } from "./utils.js";
@@ -62,18 +60,16 @@ var FormApi = class {
62
60
  this.validateAllFields = async (cause) => {
63
61
  const fieldValidationPromises = [];
64
62
  this.store.batch(() => {
65
- void Object.values(this.fieldInfo).forEach(
66
- (field) => {
67
- Object.values(field.instances).forEach((instance) => {
68
- if (!instance.state.meta.isTouched) {
69
- instance.setMeta((prev) => ({ ...prev, isTouched: true }));
70
- fieldValidationPromises.push(
71
- Promise.resolve().then(() => instance.validate(cause))
72
- );
73
- }
74
- });
75
- }
76
- );
63
+ void Object.values(this.fieldInfo).forEach((field) => {
64
+ Object.values(field.instances).forEach((instance) => {
65
+ if (!instance.state.meta.isTouched) {
66
+ instance.setMeta((prev) => ({ ...prev, isTouched: true }));
67
+ fieldValidationPromises.push(
68
+ Promise.resolve().then(() => instance.validate(cause))
69
+ );
70
+ }
71
+ });
72
+ });
77
73
  });
78
74
  return Promise.all(fieldValidationPromises);
79
75
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\n//\nimport type { DeepKeys, DeepValue, Updater } from './utils'\nimport { functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils'\nimport type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'\n\nexport type FormOptions<TData> = {\n defaultValues?: TData\n defaultState?: Partial<FormState<TData>>\n asyncDebounceMs?: number\n onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError\n onMountAsync?: (\n values: TData,\n formApi: FormApi<TData>,\n ) => ValidationError | Promise<ValidationError>\n onMountAsyncDebounceMs?: number\n onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError\n onChangeAsync?: (\n values: TData,\n formApi: FormApi<TData>,\n ) => ValidationError | Promise<ValidationError>\n onChangeAsyncDebounceMs?: number\n onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError\n onBlurAsync?: (\n values: TData,\n formApi: FormApi<TData>,\n ) => ValidationError | Promise<ValidationError>\n onBlurAsyncDebounceMs?: number\n onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>\n onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void\n}\n\nexport type FieldInfo<TFormData> = {\n instances: Record<string, FieldApi<TFormData, any, any>>\n} & ValidationMeta\n\nexport type ValidationMeta = {\n validationCount?: number\n validationAsyncCount?: number\n validationPromise?: Promise<ValidationError[]>\n validationResolve?: (errors: ValidationError[]) => void\n validationReject?: (errors: unknown) => void\n}\n\nexport type ValidationError = undefined | false | null | string\n\nexport type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`\n\nexport type ValidationErrorMap = {\n [K in ValidationErrorMapKeys]?: ValidationError\n}\n\nexport type FormState<TData> = {\n values: TData\n // Form Validation\n isFormValidating: boolean\n formValidationCount: number\n isFormValid: boolean\n formError?: ValidationError\n // Fields\n fieldMeta: Record<DeepKeys<TData>, FieldMeta>\n isFieldsValidating: boolean\n isFieldsValid: boolean\n isSubmitting: boolean\n // General\n isTouched: boolean\n isSubmitted: boolean\n isValidating: boolean\n isValid: boolean\n canSubmit: boolean\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TData>(\n defaultState: Partial<FormState<TData>>,\n): FormState<TData> {\n return {\n values: defaultState.values ?? ({} as never),\n fieldMeta: defaultState.fieldMeta ?? ({} as never),\n canSubmit: defaultState.canSubmit ?? true,\n isFieldsValid: defaultState.isFieldsValid ?? false,\n isFieldsValidating: defaultState.isFieldsValidating ?? false,\n isFormValid: defaultState.isFormValid ?? false,\n isFormValidating: defaultState.isFormValidating ?? false,\n isSubmitted: defaultState.isSubmitted ?? false,\n isSubmitting: defaultState.isSubmitting ?? false,\n isTouched: defaultState.isTouched ?? false,\n isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n formValidationCount: defaultState.formValidationCount ?? 0,\n }\n}\n\nexport class FormApi<TFormData> {\n // // This carries the context for nested fields\n options: FormOptions<TFormData> = {}\n store!: Store<FormState<TFormData>>\n // Do not use __state directly, as it is not reactive.\n // Please use form.useStore() utility to subscribe to state\n state!: FormState<TFormData>\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>> = {} as any\n fieldName?: string\n validationMeta: ValidationMeta = {}\n\n constructor(opts?: FormOptions<TFormData>) {\n this.store = new Store<FormState<TFormData>>(\n getDefaultFormState({\n ...(opts?.defaultState as any),\n values: opts?.defaultValues ?? opts?.defaultState?.values,\n isFormValid: true,\n }),\n {\n onUpdate: () => {\n let { state } = this.store\n // Computed state\n const fieldMetaValues = Object.values(state.fieldMeta) as (\n | FieldMeta\n | undefined\n )[]\n\n const isFieldsValidating = fieldMetaValues.some(\n (field) => field?.isValidating,\n )\n\n const isFieldsValid = !fieldMetaValues.some((field) =>\n isNonEmptyArray(field?.errors),\n )\n\n const isTouched = fieldMetaValues.some((field) => field?.isTouched)\n\n const isValidating = isFieldsValidating || state.isFormValidating\n const isFormValid = !state.formError\n const isValid = isFieldsValid && isFormValid\n const canSubmit =\n (state.submissionAttempts === 0 && !isTouched) ||\n (!isValidating && !state.isSubmitting && isValid)\n\n state = {\n ...state,\n isFieldsValidating,\n isFieldsValid,\n isFormValid,\n isValid,\n canSubmit,\n isTouched,\n }\n\n this.store.state = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n update = (options?: FormOptions<TFormData>) => {\n if (!options) return\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== this.options.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== this.options.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateState ? options.defaultState : {},\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n\n this.options = options\n }\n\n reset = () =>\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n }),\n )\n\n validateAllFields = async (cause: ValidationCause) => {\n const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any\n this.store.batch(() => {\n void (Object.values(this.fieldInfo) as FieldInfo<any>[]).forEach(\n (field) => {\n Object.values(field.instances).forEach((instance) => {\n // If any fields are not touched\n if (!instance.state.meta.isTouched) {\n // Mark them as touched\n instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => instance.validate(cause)),\n )\n }\n })\n },\n )\n })\n\n return Promise.all(fieldValidationPromises)\n }\n\n handleSubmit = async () => {\n // Check to see that the form and all fields have been touched\n // If they have not, touch them all and run validation\n // Run form validation\n // Submit the form\n\n this.store.setState((old) => ({\n ...old,\n // Submission attempts mark the form as not submitted\n isSubmitted: false,\n // Count submission attempts\n submissionAttempts: old.submissionAttempts + 1,\n }))\n\n // Don't let invalid forms submit\n if (!this.state.canSubmit) return\n\n this.store.setState((d) => ({ ...d, isSubmitting: true }))\n\n const done = () => {\n this.store.setState((prev) => ({ ...prev, isSubmitting: false }))\n }\n\n // Validate all fields\n await this.validateAllFields('submit')\n\n // Fields are invalid, do not submit\n if (!this.state.isFieldsValid) {\n done()\n this.options.onSubmitInvalid?.(this.state.values, this)\n return\n }\n\n // Run validation for the form\n // await this.validateForm()\n\n if (!this.state.isValid) {\n done()\n this.options.onSubmitInvalid?.(this.state.values, this)\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.(this.state.values, this)\n\n this.store.batch(() => {\n this.store.setState((prev) => ({ ...prev, isSubmitted: true }))\n done()\n })\n } catch (err) {\n done()\n throw err\n }\n }\n\n getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instances: {},\n })\n }\n\n setFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<FieldMeta>,\n ) => {\n this.store.setState((prev) => {\n return {\n ...prev,\n fieldMeta: {\n ...prev.fieldMeta,\n [field]: functionalUpdate(updater, prev.fieldMeta[field]),\n },\n }\n })\n }\n\n setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: { touch?: boolean },\n ) => {\n const touch = opts?.touch\n\n this.store.batch(() => {\n if (touch) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: true,\n }))\n }\n\n this.store.setState((prev) => {\n return {\n ...prev,\n values: setBy(prev.values, field, updater),\n }\n })\n })\n }\n\n pushFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n value: DeepValue<TFormData, TField>[number],\n opts?: { touch?: boolean },\n ) => {\n return this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n }\n\n insertFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n value: DeepValue<TFormData, TField>[number],\n opts?: { touch?: boolean },\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>\n i === index ? value : d,\n ) as any\n },\n opts,\n )\n }\n\n removeFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: { touch?: boolean },\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).filter(\n (_d, i) => i !== index,\n ) as any\n },\n opts,\n )\n }\n\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n ) => {\n this.setFieldValue(field, (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\n })\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\nimport { functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils'\nimport type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'\nimport type { ValidationError, Validator } from './types'\n\ntype ValidateFn<TData, ValidatorType> = (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n) => ValidationError\n\ntype ValidateOrFn<TData, ValidatorType> = ValidatorType extends Validator<TData>\n ? Parameters<ReturnType<ValidatorType>['validate']>[1]\n : ValidateFn<TData, ValidatorType>\n\ntype ValidateAsyncFn<TData, ValidatorType> = (\n value: TData,\n fieldApi: FormApi<TData, ValidatorType>,\n) => ValidationError | Promise<ValidationError>\n\nexport type FormOptions<TData, ValidatorType> = {\n defaultValues?: TData\n defaultState?: Partial<FormState<TData>>\n asyncDebounceMs?: number\n validator?: ValidatorType\n onMount?: ValidateOrFn<TData, ValidatorType>\n onMountAsync?: ValidateAsyncFn<TData, ValidatorType>\n onMountAsyncDebounceMs?: number\n onChange?: ValidateOrFn<TData, ValidatorType>\n onChangeAsync?: ValidateAsyncFn<TData, ValidatorType>\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TData, ValidatorType>\n onBlurAsync?: ValidateAsyncFn<TData, ValidatorType>\n onBlurAsyncDebounceMs?: number\n onSubmit?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => any | Promise<any>\n onSubmitInvalid?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => void\n}\n\nexport type FieldInfo<TFormData, ValidatorType> = {\n instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>\n} & ValidationMeta\n\nexport type ValidationMeta = {\n validationCount?: number\n validationAsyncCount?: number\n validationPromise?: Promise<ValidationError[]>\n validationResolve?: (errors: ValidationError[]) => void\n validationReject?: (errors: unknown) => void\n}\n\nexport type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`\n\nexport type ValidationErrorMap = {\n [K in ValidationErrorMapKeys]?: ValidationError\n}\n\nexport type FormState<TData> = {\n values: TData\n // Form Validation\n isFormValidating: boolean\n formValidationCount: number\n isFormValid: boolean\n formError?: ValidationError\n // Fields\n fieldMeta: Record<DeepKeys<TData>, FieldMeta>\n isFieldsValidating: boolean\n isFieldsValid: boolean\n isSubmitting: boolean\n // General\n isTouched: boolean\n isSubmitted: boolean\n isValidating: boolean\n isValid: boolean\n canSubmit: boolean\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TData>(\n defaultState: Partial<FormState<TData>>,\n): FormState<TData> {\n return {\n values: defaultState.values ?? ({} as never),\n fieldMeta: defaultState.fieldMeta ?? ({} as never),\n canSubmit: defaultState.canSubmit ?? true,\n isFieldsValid: defaultState.isFieldsValid ?? false,\n isFieldsValidating: defaultState.isFieldsValidating ?? false,\n isFormValid: defaultState.isFormValid ?? false,\n isFormValidating: defaultState.isFormValidating ?? false,\n isSubmitted: defaultState.isSubmitted ?? false,\n isSubmitting: defaultState.isSubmitting ?? false,\n isTouched: defaultState.isTouched ?? false,\n isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n formValidationCount: defaultState.formValidationCount ?? 0,\n }\n}\n\nexport class FormApi<TFormData, ValidatorType> {\n // // This carries the context for nested fields\n options: FormOptions<TFormData, ValidatorType> = {}\n store!: Store<FormState<TFormData>>\n // Do not use __state directly, as it is not reactive.\n // Please use form.useStore() utility to subscribe to state\n state!: FormState<TFormData>\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>> =\n {} as any\n fieldName?: string\n validationMeta: ValidationMeta = {}\n\n constructor(opts?: FormOptions<TFormData, ValidatorType>) {\n this.store = new Store<FormState<TFormData>>(\n getDefaultFormState({\n ...(opts?.defaultState as any),\n values: opts?.defaultValues ?? opts?.defaultState?.values,\n isFormValid: true,\n }),\n {\n onUpdate: () => {\n let { state } = this.store\n // Computed state\n const fieldMetaValues = Object.values(state.fieldMeta) as (\n | FieldMeta\n | undefined\n )[]\n\n const isFieldsValidating = fieldMetaValues.some(\n (field) => field?.isValidating,\n )\n\n const isFieldsValid = !fieldMetaValues.some((field) =>\n isNonEmptyArray(field?.errors),\n )\n\n const isTouched = fieldMetaValues.some((field) => field?.isTouched)\n\n const isValidating = isFieldsValidating || state.isFormValidating\n const isFormValid = !state.formError\n const isValid = isFieldsValid && isFormValid\n const canSubmit =\n (state.submissionAttempts === 0 && !isTouched) ||\n (!isValidating && !state.isSubmitting && isValid)\n\n state = {\n ...state,\n isFieldsValidating,\n isFieldsValid,\n isFormValid,\n isValid,\n canSubmit,\n isTouched,\n }\n\n this.store.state = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n update = (options?: FormOptions<TFormData, ValidatorType>) => {\n if (!options) return\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== this.options.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== this.options.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateState ? options.defaultState : {},\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n\n this.options = options\n }\n\n reset = () =>\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n }),\n )\n\n validateAllFields = async (cause: ValidationCause) => {\n const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any\n this.store.batch(() => {\n void (\n Object.values(this.fieldInfo) as FieldInfo<any, ValidatorType>[]\n ).forEach((field) => {\n Object.values(field.instances).forEach((instance) => {\n // If any fields are not touched\n if (!instance.state.meta.isTouched) {\n // Mark them as touched\n instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => instance.validate(cause)),\n )\n }\n })\n })\n })\n\n return Promise.all(fieldValidationPromises)\n }\n\n handleSubmit = async () => {\n // Check to see that the form and all fields have been touched\n // If they have not, touch them all and run validation\n // Run form validation\n // Submit the form\n\n this.store.setState((old) => ({\n ...old,\n // Submission attempts mark the form as not submitted\n isSubmitted: false,\n // Count submission attempts\n submissionAttempts: old.submissionAttempts + 1,\n }))\n\n // Don't let invalid forms submit\n if (!this.state.canSubmit) return\n\n this.store.setState((d) => ({ ...d, isSubmitting: true }))\n\n const done = () => {\n this.store.setState((prev) => ({ ...prev, isSubmitting: false }))\n }\n\n // Validate all fields\n await this.validateAllFields('submit')\n\n // Fields are invalid, do not submit\n if (!this.state.isFieldsValid) {\n done()\n this.options.onSubmitInvalid?.(this.state.values, this)\n return\n }\n\n // Run validation for the form\n // await this.validateForm()\n\n if (!this.state.isValid) {\n done()\n this.options.onSubmitInvalid?.(this.state.values, this)\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.(this.state.values, this)\n\n this.store.batch(() => {\n this.store.setState((prev) => ({ ...prev, isSubmitted: true }))\n done()\n })\n } catch (err) {\n done()\n throw err\n }\n }\n\n getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, ValidatorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instances: {},\n })\n }\n\n setFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<FieldMeta>,\n ) => {\n this.store.setState((prev) => {\n return {\n ...prev,\n fieldMeta: {\n ...prev.fieldMeta,\n [field]: functionalUpdate(updater, prev.fieldMeta[field]),\n },\n }\n })\n }\n\n setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: { touch?: boolean },\n ) => {\n const touch = opts?.touch\n\n this.store.batch(() => {\n if (touch) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: true,\n }))\n }\n\n this.store.setState((prev) => {\n return {\n ...prev,\n values: setBy(prev.values, field, updater),\n }\n })\n })\n }\n\n pushFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: { touch?: boolean },\n ) => {\n return this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n }\n\n insertFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: { touch?: boolean },\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>\n i === index ? value : d,\n ) as any\n },\n opts,\n )\n }\n\n removeFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: { touch?: boolean },\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).filter(\n (_d, i) => i !== index,\n ) as any\n },\n opts,\n )\n }\n\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n ) => {\n this.setFieldValue(field, (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\n })\n }\n}\n"],"mappings":"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","names":[]}
@@ -20,10 +20,12 @@ module.exports = __toCommonJS(src_exports);
20
20
  __reExport(src_exports, require("./FormApi.cjs"), module.exports);
21
21
  __reExport(src_exports, require("./FieldApi.cjs"), module.exports);
22
22
  __reExport(src_exports, require("./utils.cjs"), module.exports);
23
+ __reExport(src_exports, require("./types.cjs"), module.exports);
23
24
  // Annotate the CommonJS export names for ESM import in node:
24
25
  0 && (module.exports = {
25
26
  ...require("./FormApi.cjs"),
26
27
  ...require("./FieldApi.cjs"),
27
- ...require("./utils.cjs")
28
+ ...require("./utils.cjs"),
29
+ ...require("./types.cjs")
28
30
  });
29
31
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './FormApi'\nexport * from './FieldApi'\nexport * from './utils'\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,wBAAc,0BAAd;AACA,wBAAc,2BADd;AAEA,wBAAc,wBAFd;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './FormApi'\nexport * from './FieldApi'\nexport * from './utils'\nexport * from './types'\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,wBAAc,0BAAd;AACA,wBAAc,2BADd;AAEA,wBAAc,wBAFd;AAGA,wBAAc,wBAHd;","names":[]}
@@ -1,25 +1,30 @@
1
1
  import { Store } from '@tanstack/store';
2
2
  import { DeepKeys, DeepValue, Updater } from './utils.cjs';
3
3
  export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.cjs';
4
+ import { ValidationError, Validator } from './types.cjs';
4
5
 
5
- type FormOptions<TData> = {
6
+ type ValidateFn$1<TData, ValidatorType> = (values: TData, formApi: FormApi<TData, ValidatorType>) => ValidationError;
7
+ type ValidateOrFn$1<TData, ValidatorType> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] : ValidateFn$1<TData, ValidatorType>;
8
+ type ValidateAsyncFn$1<TData, ValidatorType> = (value: TData, fieldApi: FormApi<TData, ValidatorType>) => ValidationError | Promise<ValidationError>;
9
+ type FormOptions<TData, ValidatorType> = {
6
10
  defaultValues?: TData;
7
11
  defaultState?: Partial<FormState<TData>>;
8
12
  asyncDebounceMs?: number;
9
- onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError;
10
- onMountAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
13
+ validator?: ValidatorType;
14
+ onMount?: ValidateOrFn$1<TData, ValidatorType>;
15
+ onMountAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
11
16
  onMountAsyncDebounceMs?: number;
12
- onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError;
13
- onChangeAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
17
+ onChange?: ValidateOrFn$1<TData, ValidatorType>;
18
+ onChangeAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
14
19
  onChangeAsyncDebounceMs?: number;
15
- onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError;
16
- onBlurAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
20
+ onBlur?: ValidateOrFn$1<TData, ValidatorType>;
21
+ onBlurAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
17
22
  onBlurAsyncDebounceMs?: number;
18
- onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>;
19
- onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void;
23
+ onSubmit?: (values: TData, formApi: FormApi<TData, ValidatorType>) => any | Promise<any>;
24
+ onSubmitInvalid?: (values: TData, formApi: FormApi<TData, ValidatorType>) => void;
20
25
  };
21
- type FieldInfo<TFormData> = {
22
- instances: Record<string, FieldApi<TFormData, any, any>>;
26
+ type FieldInfo<TFormData, ValidatorType> = {
27
+ instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>;
23
28
  } & ValidationMeta;
24
29
  type ValidationMeta = {
25
30
  validationCount?: number;
@@ -28,7 +33,6 @@ type ValidationMeta = {
28
33
  validationResolve?: (errors: ValidationError[]) => void;
29
34
  validationReject?: (errors: unknown) => void;
30
35
  };
31
- type ValidationError = undefined | false | null | string;
32
36
  type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`;
33
37
  type ValidationErrorMap = {
34
38
  [K in ValidationErrorMapKeys]?: ValidationError;
@@ -50,29 +54,29 @@ type FormState<TData> = {
50
54
  canSubmit: boolean;
51
55
  submissionAttempts: number;
52
56
  };
53
- declare class FormApi<TFormData> {
54
- options: FormOptions<TFormData>;
57
+ declare class FormApi<TFormData, ValidatorType> {
58
+ options: FormOptions<TFormData, ValidatorType>;
55
59
  store: Store<FormState<TFormData>>;
56
60
  state: FormState<TFormData>;
57
- fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
61
+ fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>>;
58
62
  fieldName?: string;
59
63
  validationMeta: ValidationMeta;
60
- constructor(opts?: FormOptions<TFormData>);
61
- update: (options?: FormOptions<TFormData>) => void;
64
+ constructor(opts?: FormOptions<TFormData, ValidatorType>);
65
+ update: (options?: FormOptions<TFormData, ValidatorType>) => void;
62
66
  reset: () => void;
63
67
  validateAllFields: (cause: ValidationCause) => Promise<ValidationError[][]>;
64
68
  handleSubmit: () => Promise<void>;
65
69
  getFieldValue: <TField extends DeepKeys<TFormData>>(field: TField) => DeepValue<TFormData, TField>;
66
70
  getFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField) => FieldMeta | undefined;
67
- getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData>;
71
+ getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData, ValidatorType>;
68
72
  setFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>) => void;
69
73
  setFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: {
70
74
  touch?: boolean;
71
75
  }) => void;
72
- pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>[number], opts?: {
76
+ pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
73
77
  touch?: boolean;
74
78
  }) => void;
75
- insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>[number], opts?: {
79
+ insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
76
80
  touch?: boolean;
77
81
  }) => void;
78
82
  removeFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, opts?: {
@@ -82,35 +86,29 @@ declare class FormApi<TFormData> {
82
86
  }
83
87
 
84
88
  type ValidationCause = 'change' | 'blur' | 'submit' | 'mount';
85
- type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError;
86
- type ValidateAsyncFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError | Promise<ValidationError>;
87
- interface FieldOptions<TParentData,
88
- /**
89
- * This allows us to restrict the name to only be a valid field name while
90
- * also assigning it to a generic
91
- */
92
- TName extends DeepKeys<TParentData>,
93
- /**
94
- * If TData is unknown, we can use the TName generic to determine the type
95
- */
96
- TData = DeepValue<TParentData, TName>> {
97
- name: DeepKeys<TParentData>;
89
+ 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;
90
+ 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>;
91
+ 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>;
92
+ 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>;
93
+ interface FieldOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
94
+ name: TName;
98
95
  index?: TData extends any[] ? number : never;
99
96
  defaultValue?: TData;
100
97
  asyncDebounceMs?: number;
101
98
  asyncAlways?: boolean;
102
- onMount?: (formApi: FieldApi<TParentData, TName>) => void;
103
- onChange?: ValidateFn<TParentData, TName, TData>;
104
- onChangeAsync?: ValidateAsyncFn<TParentData, TName, TData>;
99
+ validator?: ValidatorType;
100
+ onMount?: (formApi: FieldApi<TParentData, TName, ValidatorType, TData>) => void;
101
+ onChange?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
102
+ onChangeAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
105
103
  onChangeAsyncDebounceMs?: number;
106
- onBlur?: ValidateFn<TParentData, TName, TData>;
107
- onBlurAsync?: ValidateAsyncFn<TParentData, TName, TData>;
104
+ onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
105
+ onBlurAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
108
106
  onBlurAsyncDebounceMs?: number;
109
- onSubmitAsync?: ValidateAsyncFn<TParentData, TName, TData>;
107
+ onSubmitAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
110
108
  defaultMeta?: Partial<FieldMeta>;
111
109
  }
112
- interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, TData> {
113
- form: FormApi<TParentData>;
110
+ interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, ValidatorType, FormValidator, TData> {
111
+ form: FormApi<TParentData, FormValidator>;
114
112
  }
115
113
  type FieldMeta = {
116
114
  isTouched: boolean;
@@ -124,20 +122,17 @@ type FieldState<TData> = {
124
122
  meta: FieldMeta;
125
123
  };
126
124
  type ResolveName<TParentData> = unknown extends TParentData ? string : DeepKeys<TParentData>;
127
- declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> {
128
- #private;
125
+ declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
129
126
  uid: number;
130
- form: FieldApiOptions<TParentData, TName, TData>['form'];
127
+ form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form'];
131
128
  name: DeepKeys<TParentData>;
132
- options: FieldApiOptions<TParentData, TName>;
129
+ options: FieldApiOptions<TParentData, TName, ValidatorType, TData>;
133
130
  store: Store<FieldState<TData>>;
134
131
  state: FieldState<TData>;
135
132
  prevState: FieldState<TData>;
136
- constructor(opts: FieldApiOptions<TParentData, TName, TData> & {
137
- form: FormApi<TParentData>;
138
- });
133
+ constructor(opts: FieldApiOptions<TParentData, TName, ValidatorType, FormValidator, TData>);
139
134
  mount: () => () => void;
140
- update: (opts: FieldApiOptions<TParentData, TName, TData>) => void;
135
+ update: (opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>) => void;
141
136
  getValue: () => TData;
142
137
  setValue: (updater: Updater<TData>, options?: {
143
138
  touch?: boolean;
@@ -146,13 +141,14 @@ declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData =
146
141
  _getMeta: () => FieldMeta | undefined;
147
142
  getMeta: () => FieldMeta;
148
143
  setMeta: (updater: Updater<FieldMeta>) => void;
149
- getInfo: () => FieldInfo<TParentData>;
144
+ getInfo: () => FieldInfo<TParentData, TData>;
150
145
  pushValue: (value: TData extends any[] ? TData[number] : never) => void;
151
146
  insertValue: (index: number, value: TData extends any[] ? TData[number] : never) => void;
152
147
  removeValue: (index: number) => void;
153
148
  swapValues: (aIndex: number, bIndex: number) => void;
154
- getSubField: <TSubName extends DeepKeys<TData>, TSubData = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, TSubData>;
149
+ getSubField: <TSubName extends DeepKeys<TData>, TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, ValidatorType, TSubData, DeepValue<TData, TSubName>>;
155
150
  validateSync: (value: TData | undefined, cause: ValidationCause) => void;
151
+ __leaseValidateAsync: () => number;
156
152
  cancelValidateAsync: () => void;
157
153
  validateAsync: (value: TData | undefined, cause: ValidationCause) => Promise<ValidationError[]>;
158
154
  validate: (cause: ValidationCause, value?: TData) => ValidationError[] | Promise<ValidationError[]>;
@@ -160,4 +156,4 @@ declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData =
160
156
  handleBlur: () => void;
161
157
  }
162
158
 
163
- export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta };
159
+ export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta, Validator };
@@ -1,25 +1,30 @@
1
1
  import { Store } from '@tanstack/store';
2
2
  import { DeepKeys, DeepValue, Updater } from './utils.js';
3
3
  export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.js';
4
+ import { ValidationError, Validator } from './types.js';
4
5
 
5
- type FormOptions<TData> = {
6
+ type ValidateFn$1<TData, ValidatorType> = (values: TData, formApi: FormApi<TData, ValidatorType>) => ValidationError;
7
+ type ValidateOrFn$1<TData, ValidatorType> = ValidatorType extends Validator<TData> ? Parameters<ReturnType<ValidatorType>['validate']>[1] : ValidateFn$1<TData, ValidatorType>;
8
+ type ValidateAsyncFn$1<TData, ValidatorType> = (value: TData, fieldApi: FormApi<TData, ValidatorType>) => ValidationError | Promise<ValidationError>;
9
+ type FormOptions<TData, ValidatorType> = {
6
10
  defaultValues?: TData;
7
11
  defaultState?: Partial<FormState<TData>>;
8
12
  asyncDebounceMs?: number;
9
- onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError;
10
- onMountAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
13
+ validator?: ValidatorType;
14
+ onMount?: ValidateOrFn$1<TData, ValidatorType>;
15
+ onMountAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
11
16
  onMountAsyncDebounceMs?: number;
12
- onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError;
13
- onChangeAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
17
+ onChange?: ValidateOrFn$1<TData, ValidatorType>;
18
+ onChangeAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
14
19
  onChangeAsyncDebounceMs?: number;
15
- onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError;
16
- onBlurAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
20
+ onBlur?: ValidateOrFn$1<TData, ValidatorType>;
21
+ onBlurAsync?: ValidateAsyncFn$1<TData, ValidatorType>;
17
22
  onBlurAsyncDebounceMs?: number;
18
- onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>;
19
- onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void;
23
+ onSubmit?: (values: TData, formApi: FormApi<TData, ValidatorType>) => any | Promise<any>;
24
+ onSubmitInvalid?: (values: TData, formApi: FormApi<TData, ValidatorType>) => void;
20
25
  };
21
- type FieldInfo<TFormData> = {
22
- instances: Record<string, FieldApi<TFormData, any, any>>;
26
+ type FieldInfo<TFormData, ValidatorType> = {
27
+ instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>;
23
28
  } & ValidationMeta;
24
29
  type ValidationMeta = {
25
30
  validationCount?: number;
@@ -28,7 +33,6 @@ type ValidationMeta = {
28
33
  validationResolve?: (errors: ValidationError[]) => void;
29
34
  validationReject?: (errors: unknown) => void;
30
35
  };
31
- type ValidationError = undefined | false | null | string;
32
36
  type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`;
33
37
  type ValidationErrorMap = {
34
38
  [K in ValidationErrorMapKeys]?: ValidationError;
@@ -50,29 +54,29 @@ type FormState<TData> = {
50
54
  canSubmit: boolean;
51
55
  submissionAttempts: number;
52
56
  };
53
- declare class FormApi<TFormData> {
54
- options: FormOptions<TFormData>;
57
+ declare class FormApi<TFormData, ValidatorType> {
58
+ options: FormOptions<TFormData, ValidatorType>;
55
59
  store: Store<FormState<TFormData>>;
56
60
  state: FormState<TFormData>;
57
- fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
61
+ fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>>;
58
62
  fieldName?: string;
59
63
  validationMeta: ValidationMeta;
60
- constructor(opts?: FormOptions<TFormData>);
61
- update: (options?: FormOptions<TFormData>) => void;
64
+ constructor(opts?: FormOptions<TFormData, ValidatorType>);
65
+ update: (options?: FormOptions<TFormData, ValidatorType>) => void;
62
66
  reset: () => void;
63
67
  validateAllFields: (cause: ValidationCause) => Promise<ValidationError[][]>;
64
68
  handleSubmit: () => Promise<void>;
65
69
  getFieldValue: <TField extends DeepKeys<TFormData>>(field: TField) => DeepValue<TFormData, TField>;
66
70
  getFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField) => FieldMeta | undefined;
67
- getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData>;
71
+ getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => FieldInfo<TFormData, ValidatorType>;
68
72
  setFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>) => void;
69
73
  setFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: {
70
74
  touch?: boolean;
71
75
  }) => void;
72
- pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>[number], opts?: {
76
+ pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
73
77
  touch?: boolean;
74
78
  }) => void;
75
- insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>[number], opts?: {
79
+ insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField> extends any[] ? DeepValue<TFormData, TField>[number] : never, opts?: {
76
80
  touch?: boolean;
77
81
  }) => void;
78
82
  removeFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, opts?: {
@@ -82,35 +86,29 @@ declare class FormApi<TFormData> {
82
86
  }
83
87
 
84
88
  type ValidationCause = 'change' | 'blur' | 'submit' | 'mount';
85
- type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError;
86
- type ValidateAsyncFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (value: TData, fieldApi: FieldApi<TParentData, TName>) => ValidationError | Promise<ValidationError>;
87
- interface FieldOptions<TParentData,
88
- /**
89
- * This allows us to restrict the name to only be a valid field name while
90
- * also assigning it to a generic
91
- */
92
- TName extends DeepKeys<TParentData>,
93
- /**
94
- * If TData is unknown, we can use the TName generic to determine the type
95
- */
96
- TData = DeepValue<TParentData, TName>> {
97
- name: DeepKeys<TParentData>;
89
+ 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;
90
+ 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>;
91
+ 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>;
92
+ 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>;
93
+ interface FieldOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
94
+ name: TName;
98
95
  index?: TData extends any[] ? number : never;
99
96
  defaultValue?: TData;
100
97
  asyncDebounceMs?: number;
101
98
  asyncAlways?: boolean;
102
- onMount?: (formApi: FieldApi<TParentData, TName>) => void;
103
- onChange?: ValidateFn<TParentData, TName, TData>;
104
- onChangeAsync?: ValidateAsyncFn<TParentData, TName, TData>;
99
+ validator?: ValidatorType;
100
+ onMount?: (formApi: FieldApi<TParentData, TName, ValidatorType, TData>) => void;
101
+ onChange?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
102
+ onChangeAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
105
103
  onChangeAsyncDebounceMs?: number;
106
- onBlur?: ValidateFn<TParentData, TName, TData>;
107
- onBlurAsync?: ValidateAsyncFn<TParentData, TName, TData>;
104
+ onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
105
+ onBlurAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
108
106
  onBlurAsyncDebounceMs?: number;
109
- onSubmitAsync?: ValidateAsyncFn<TParentData, TName, TData>;
107
+ onSubmitAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
110
108
  defaultMeta?: Partial<FieldMeta>;
111
109
  }
112
- interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, TData> {
113
- form: FormApi<TParentData>;
110
+ interface FieldApiOptions<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> extends FieldOptions<TParentData, TName, ValidatorType, FormValidator, TData> {
111
+ form: FormApi<TParentData, FormValidator>;
114
112
  }
115
113
  type FieldMeta = {
116
114
  isTouched: boolean;
@@ -124,20 +122,17 @@ type FieldState<TData> = {
124
122
  meta: FieldMeta;
125
123
  };
126
124
  type ResolveName<TParentData> = unknown extends TParentData ? string : DeepKeys<TParentData>;
127
- declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> {
128
- #private;
125
+ declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
129
126
  uid: number;
130
- form: FieldApiOptions<TParentData, TName, TData>['form'];
127
+ form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form'];
131
128
  name: DeepKeys<TParentData>;
132
- options: FieldApiOptions<TParentData, TName>;
129
+ options: FieldApiOptions<TParentData, TName, ValidatorType, TData>;
133
130
  store: Store<FieldState<TData>>;
134
131
  state: FieldState<TData>;
135
132
  prevState: FieldState<TData>;
136
- constructor(opts: FieldApiOptions<TParentData, TName, TData> & {
137
- form: FormApi<TParentData>;
138
- });
133
+ constructor(opts: FieldApiOptions<TParentData, TName, ValidatorType, FormValidator, TData>);
139
134
  mount: () => () => void;
140
- update: (opts: FieldApiOptions<TParentData, TName, TData>) => void;
135
+ update: (opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>) => void;
141
136
  getValue: () => TData;
142
137
  setValue: (updater: Updater<TData>, options?: {
143
138
  touch?: boolean;
@@ -146,13 +141,14 @@ declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData =
146
141
  _getMeta: () => FieldMeta | undefined;
147
142
  getMeta: () => FieldMeta;
148
143
  setMeta: (updater: Updater<FieldMeta>) => void;
149
- getInfo: () => FieldInfo<TParentData>;
144
+ getInfo: () => FieldInfo<TParentData, TData>;
150
145
  pushValue: (value: TData extends any[] ? TData[number] : never) => void;
151
146
  insertValue: (index: number, value: TData extends any[] ? TData[number] : never) => void;
152
147
  removeValue: (index: number) => void;
153
148
  swapValues: (aIndex: number, bIndex: number) => void;
154
- getSubField: <TSubName extends DeepKeys<TData>, TSubData = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, TSubData>;
149
+ getSubField: <TSubName extends DeepKeys<TData>, TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>>(name: TSubName) => FieldApi<TData, TSubName, ValidatorType, TSubData, DeepValue<TData, TSubName>>;
155
150
  validateSync: (value: TData | undefined, cause: ValidationCause) => void;
151
+ __leaseValidateAsync: () => number;
156
152
  cancelValidateAsync: () => void;
157
153
  validateAsync: (value: TData | undefined, cause: ValidationCause) => Promise<ValidationError[]>;
158
154
  validate: (cause: ValidationCause, value?: TData) => ValidationError[] | Promise<ValidationError[]>;
@@ -160,4 +156,4 @@ declare class FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData =
160
156
  handleBlur: () => void;
161
157
  }
162
158
 
163
- export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta };
159
+ export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, ResolveName, Updater, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, ValidationMeta, Validator };
@@ -2,4 +2,5 @@
2
2
  export * from "./FormApi.js";
3
3
  export * from "./FieldApi.js";
4
4
  export * from "./utils.js";
5
+ export * from "./types.js";
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './FormApi'\nexport * from './FieldApi'\nexport * from './utils'\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './FormApi'\nexport * from './FieldApi'\nexport * from './utils'\nexport * from './types'\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/types.ts
17
+ var types_exports = {};
18
+ module.exports = __toCommonJS(types_exports);
19
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types.ts"],"sourcesContent":["export type ValidationError = undefined | false | null | string\n\n// If/when TypeScript supports higher-kinded types, this should not be `unknown` anymore\nexport type Validator<Type, Fn = unknown> = () => {\n validate(value: Type, fn: Fn): ValidationError\n validateAsync(value: Type, fn: Fn): Promise<ValidationError>\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,7 @@
1
+ type ValidationError = undefined | false | null | string;
2
+ type Validator<Type, Fn = unknown> = () => {
3
+ validate(value: Type, fn: Fn): ValidationError;
4
+ validateAsync(value: Type, fn: Fn): Promise<ValidationError>;
5
+ };
6
+
7
+ export { ValidationError, Validator };
@@ -0,0 +1,7 @@
1
+ type ValidationError = undefined | false | null | string;
2
+ type Validator<Type, Fn = unknown> = () => {
3
+ validate(value: Type, fn: Fn): ValidationError;
4
+ validateAsync(value: Type, fn: Fn): Promise<ValidationError>;
5
+ };
6
+
7
+ export { ValidationError, Validator };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -1,5 +1,3 @@
1
- import "./chunk-4QZDOMDG.js";
2
-
3
1
  // src/utils.ts
4
2
  function functionalUpdate(updater, input) {
5
3
  return typeof updater === "function" ? updater(input) : updater;