From 5cac9c629b6fbd6433b58eea327e89081617a688 Mon Sep 17 00:00:00 2001 From: Grant Hobbs Date: Thu, 23 Jun 2022 09:08:33 -0500 Subject: [PATCH 1/5] Add hook in getInputProps config for manually updating form data based on new value --- src/types.ts | 1 + src/useReactoForm.ts | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/types.ts b/src/types.ts index ef11193..c033866 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,6 +19,7 @@ export interface GetInputPropsOptions { nullValue?: any onChangeGetValue?: (...args: any[]) => any onChangingGetValue?: (...args: any[]) => any + onApplyChangeToForm?: (formData: FormData, fieldValue: any, fieldPath: string) => FormData, propNames?: Partial } diff --git a/src/useReactoForm.ts b/src/useReactoForm.ts index ad66d6f..b72b3df 100644 --- a/src/useReactoForm.ts +++ b/src/useReactoForm.ts @@ -195,7 +195,8 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm isForm = false, nullValue, onChangeGetValue, - onChangingGetValue + onChangingGetValue, + onApplyChangeToForm, } = getInputPropsOptions const propNames: InputPropNameMap = { ...DEFAULT_PROP_NAMES } @@ -230,7 +231,9 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm ? onChangeGetValue(...onChangeArgs) : onChangeArgs[0] - const updatedFormData = setFieldValueInFormData(fieldPath, inputValue) + const updatedFormData = (onApplyChangeToForm != null) + ? onApplyChangeToForm(clone(formData), inputValue, fieldPath) + : setFieldValueInFormData(fieldPath, inputValue) // Now bubble up the `onChange`, possibly validating first if ( From 97686b29b7389b955f0ffd4b9b5a115b4ff93606 Mon Sep 17 00:00:00 2001 From: Grant Hobbs Date: Thu, 23 Jun 2022 09:22:00 -0500 Subject: [PATCH 2/5] Add .idea to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3597cb4..effd64a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ build/ # Misc .DS_Store + +.idea From 27dee3b93e41e33ee0e3c5e8d9c6cb6e097e913d Mon Sep 17 00:00:00 2001 From: Grant Hobbs Date: Thu, 23 Jun 2022 09:22:57 -0500 Subject: [PATCH 3/5] Pass updateFormData function alongside form state for manually updating data --- src/types.ts | 1 + src/useReactoForm.ts | 58 +++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/types.ts b/src/types.ts index c033866..675799c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -58,6 +58,7 @@ export interface UseReactoFormState { getErrors: (fieldPaths: string[], options?: ErrorOptions) => ValidationError[] getFirstError: (fieldPaths: string[], options?: ErrorOptions) => ValidationError | null getFirstErrorMessage: (fieldPaths: string[], options?: ErrorOptions) => string | null + updateFormData: (formData: FormData) => void getInputProps: (fieldPath: string, options?: GetInputPropsOptions) => Record hasBeenValidated: boolean hasErrors: (fieldPaths: string[], options?: ErrorOptions) => boolean diff --git a/src/useReactoForm.ts b/src/useReactoForm.ts index b72b3df..45f79c8 100644 --- a/src/useReactoForm.ts +++ b/src/useReactoForm.ts @@ -188,8 +188,33 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm return fieldErrors[0] } + function applyValueChange (updatedFormData: FormData, isValidationRequired = false) { + // Bubble up the `onChange`, possibly validating first + if (isValidationRequired) { + validateForm() + .then((updatedErrors) => { + onChange(updatedFormData, updatedErrors.length === 0) + return null + }) + .catch((error) => { + console.error(error) + }) + } else { + onChange(updatedFormData, errors.length === 0) + } + } + const formState: UseReactoFormState = { formData, + updateFormData (formData) { + const isValidationRequired = + validateOn === 'changed' || + validateOn === 'changing' || + (hasBeenValidated && + (revalidateOn === 'changed' || revalidateOn === 'changing')) + + applyValueChange(formData, isValidationRequired); + }, getInputProps (fieldPath, getInputPropsOptions = {}) { const { isForm = false, @@ -235,24 +260,13 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm ? onApplyChangeToForm(clone(formData), inputValue, fieldPath) : setFieldValueInFormData(fieldPath, inputValue) - // Now bubble up the `onChange`, possibly validating first - if ( + const isValidationRequired = validateOn === 'changed' || validateOn === 'changing' || (hasBeenValidated && (revalidateOn === 'changed' || revalidateOn === 'changing')) - ) { - validateForm() - .then((updatedErrors) => { - onChange(updatedFormData, updatedErrors.length === 0) - return null - }) - .catch((error) => { - console.error(error) - }) - } else { - onChange(updatedFormData, errors.length === 0) - } + + applyValueChange(updatedFormData, isValidationRequired) } function onInputValueChanging (...onChangingArgs: any[]): void { @@ -266,21 +280,11 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm const updatedFormData = setFieldValueInFormData(fieldPath, inputValue) - if ( + const isValidationRequired = validateOn === 'changing' || (hasBeenValidated && revalidateOn === 'changing') - ) { - validateForm() - .then((updatedErrors) => { - onChanging(updatedFormData, updatedErrors.length === 0) - return null - }) - .catch((error) => { - console.error(error) - }) - } else { - onChanging(updatedFormData, errors.length === 0) - } + + applyValueChange(updatedFormData, isValidationRequired) } // Some input components (MUI) do not accept a `null` value. From 711575e5bd6a84e20b9a7b1fc1614afaa9db49d6 Mon Sep 17 00:00:00 2001 From: Grant Hobbs Date: Sat, 25 Jun 2022 13:01:38 -0500 Subject: [PATCH 4/5] Add method to update form data manually --- package.json | 8 ++++---- src/useReactoForm.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 380aaa9..0866401 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "reacto-form", - "version": "0.0.0-development", + "name": "@gwhobbs/reacto-form", + "version": "0.0.3-development", "description": "A React form state manager hook designed to work with many popular form UI frameworks", "main": "./build/index.js", "types": "./build/index.d.ts", @@ -28,7 +28,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/longshotlabs/reacto-form.git" + "url": "git+https://github.com/gwhobbs/reacto-form.git" }, "keywords": [], "author": "Long Shot Labs (longshotlabs.co)", @@ -88,7 +88,7 @@ "typescript": "^4.6.4" }, "peerDependencies": { - "react": ">=17 | >=18" + "react": "^17.0.0 || ^18.0.0" }, "dependencies": { "lodash": "^4.17.21", diff --git a/src/useReactoForm.ts b/src/useReactoForm.ts index 45f79c8..97b4719 100644 --- a/src/useReactoForm.ts +++ b/src/useReactoForm.ts @@ -213,7 +213,8 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm (hasBeenValidated && (revalidateOn === 'changed' || revalidateOn === 'changing')) - applyValueChange(formData, isValidationRequired); + setFormData(formData) + applyValueChange(formData, isValidationRequired) }, getInputProps (fieldPath, getInputPropsOptions = {}) { const { From e033e8dd8aeff75de7aec7bfb86195da2f555790 Mon Sep 17 00:00:00 2001 From: Grant Hobbs Date: Sat, 25 Jun 2022 14:38:26 -0500 Subject: [PATCH 5/5] Fix broken onApplyChangeToForm --- package.json | 2 +- src/useReactoForm.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0866401..6ce4939 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gwhobbs/reacto-form", - "version": "0.0.3-development", + "version": "0.0.4-development", "description": "A React form state manager hook designed to work with many popular form UI frameworks", "main": "./build/index.js", "types": "./build/index.d.ts", diff --git a/src/useReactoForm.ts b/src/useReactoForm.ts index 97b4719..321a049 100644 --- a/src/useReactoForm.ts +++ b/src/useReactoForm.ts @@ -253,12 +253,20 @@ export default function useReactoForm (props: UseReactoFormProps): UseReactoForm // directly as the first arg. Many popular libraries pass // an Event as the first arg, and `onChangeGetValue` can be // used to determine and return the new value. + const handleApplyChangeToForm = (formData: FormData, newValue: any, fieldPath: string) => { + if (typeof onApplyChangeToForm !== 'function') { + return formData + } + const nextFormData = onApplyChangeToForm(formData, newValue, fieldPath) + setFormData(nextFormData) + return nextFormData + } const inputValue = (onChangeGetValue != null) ? onChangeGetValue(...onChangeArgs) : onChangeArgs[0] const updatedFormData = (onApplyChangeToForm != null) - ? onApplyChangeToForm(clone(formData), inputValue, fieldPath) + ? handleApplyChangeToForm(clone(formData), inputValue, fieldPath) : setFieldValueInFormData(fieldPath, inputValue) const isValidationRequired =