diff --git a/examples/simple/package.json b/examples/simple/package.json index 73add2fa5f7..d576b6903cc 100644 --- a/examples/simple/package.json +++ b/examples/simple/package.json @@ -26,7 +26,7 @@ "react": "^18.3.1", "react-admin": "^5.1.2", "react-dom": "^18.3.1", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "react-router": "^6.22.0", "react-router-dom": "^6.22.0" }, diff --git a/packages/ra-core/package.json b/packages/ra-core/package.json index 72556c3dfbc..1dc2b7caa56 100644 --- a/packages/ra-core/package.json +++ b/packages/ra-core/package.json @@ -40,7 +40,7 @@ "jscodeshift": "^0.15.2", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "react-router": "^6.25.1", "react-router-dom": "^6.25.1", "react-test-renderer": "^18.2.0", @@ -53,7 +53,7 @@ "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "react-router": "^6.22.0", "react-router-dom": "^6.22.0" }, diff --git a/packages/ra-core/src/form/useInput.spec.tsx b/packages/ra-core/src/form/useInput.spec.tsx index 8fef8d4a666..78ea8262969 100644 --- a/packages/ra-core/src/form/useInput.spec.tsx +++ b/packages/ra-core/src/form/useInput.spec.tsx @@ -5,7 +5,7 @@ import { useFormContext, useWatch } from 'react-hook-form'; import { CoreAdminContext, SourceContextProvider } from '../core'; import { testDataProvider } from '../dataProvider'; import { Form } from './Form'; -import { useInput, InputProps } from './useInput'; +import { useInput, InputProps, UseInputValue } from './useInput'; import { required } from './validate'; const Input: FunctionComponent< @@ -566,5 +566,93 @@ describe('useInput', () => { ); }); }); + + it('should validate and be dirty for inputs that were disabled and re-enabled', async () => { + let inputProps: UseInputValue | undefined; + + const DisabledEnableInput = () => { + const [disabled, setDisabled] = React.useState(false); + + return ( + <> + + + {props => { + inputProps = props; // Capture the latest props + return ( + + ); + }} + + + ); + }; + + render( + +
+ + +
+ ); + + // Initial state assertions + expect(inputProps?.fieldState.isDirty).toBe(false); + expect(inputProps?.field.disabled).toBe(false); + + // Disable the input + fireEvent.click(screen.getByText('Toggle')); + + await waitFor(() => { + expect(inputProps?.fieldState.isDirty).toBe(false); + expect(inputProps?.field.disabled).toBe(true); + }); + + // Re-enable the input + fireEvent.click(screen.getByText('Toggle')); + + await waitFor(() => { + expect(inputProps?.fieldState.isDirty).toBe(false); + expect(inputProps?.field.disabled).toBe(false); + }); + + // Type in the input + fireEvent.change(screen.getByLabelText('Title'), { + target: { value: 'A title' }, + }); + + // Assert that the field is now dirty + await waitFor(() => { + expect(inputProps?.fieldState.isDirty).toBe(true); // Now the input should be dirty + expect(inputProps?.field.value).toBe('A title'); + }); + + // Clear the input + fireEvent.change(screen.getByLabelText('Title'), { + target: { value: '' }, + }); + + // Assert that the field is now dirty and invalid because it is required + await waitFor(() => { + expect(inputProps?.fieldState.isDirty).toBe(true); // Now the input should be dirty + expect(inputProps?.field.value).toBe(''); + expect(inputProps?.fieldState.invalid).toBe(true); + }); + }); }); }); diff --git a/packages/ra-core/src/form/useInput.ts b/packages/ra-core/src/form/useInput.ts index 3f1de19fdb3..30cef57a6c0 100644 --- a/packages/ra-core/src/form/useInput.ts +++ b/packages/ra-core/src/form/useInput.ts @@ -104,10 +104,6 @@ export const useInput = ( }, }, ...options, - // Workaround for https://github.com/react-hook-form/react-hook-form/issues/10907 - // FIXME - remove when fixed - // @ts-ignore - only exists since react-hook-form 7.46.0 - disabled: options.disabled || undefined, }); // Because our forms may receive an asynchronously loaded record for instance, diff --git a/packages/ra-input-rich-text/package.json b/packages/ra-input-rich-text/package.json index 48952004903..d14ff5c27d8 100644 --- a/packages/ra-input-rich-text/package.json +++ b/packages/ra-input-rich-text/package.json @@ -57,7 +57,7 @@ "ra-ui-materialui": "^5.1.2", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "rimraf": "^3.0.2", "tippy.js": "^6.3.7", "typescript": "^5.1.3" diff --git a/packages/ra-ui-materialui/package.json b/packages/ra-ui-materialui/package.json index 197e3895767..30bf06d5755 100644 --- a/packages/ra-ui-materialui/package.json +++ b/packages/ra-ui-materialui/package.json @@ -43,7 +43,7 @@ "ra-language-english": "^5.1.2", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "react-is": "^18.2.0", "react-router": "^6.25.1", "react-router-dom": "^6.25.1", diff --git a/packages/react-admin/package.json b/packages/react-admin/package.json index 378158c82e7..c8240da1a5f 100644 --- a/packages/react-admin/package.json +++ b/packages/react-admin/package.json @@ -44,7 +44,7 @@ "ra-i18n-polyglot": "^5.1.2", "ra-language-english": "^5.1.2", "ra-ui-materialui": "^5.1.2", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "react-router": "^6.22.0", "react-router-dom": "^6.22.0" }, diff --git a/yarn.lock b/yarn.lock index 682b3f150c3..3e2e7b44d64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17715,7 +17715,7 @@ __metadata: react: "npm:^18.3.1" react-dom: "npm:^18.3.1" react-error-boundary: "npm:^4.0.13" - react-hook-form: "npm:^7.52.0" + react-hook-form: "npm:^7.53.0" react-is: "npm:^18.2.0" react-router: "npm:^6.25.1" react-router-dom: "npm:^6.25.1" @@ -17728,7 +17728,7 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - react-hook-form: ^7.52.0 + react-hook-form: ^7.53.0 react-router: ^6.22.0 react-router-dom: ^6.22.0 languageName: unknown @@ -17895,7 +17895,7 @@ __metadata: ra-ui-materialui: "npm:^5.1.2" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" - react-hook-form: "npm:^7.52.0" + react-hook-form: "npm:^7.53.0" rimraf: "npm:^3.0.2" tippy.js: "npm:^6.3.7" typescript: "npm:^5.1.3" @@ -17992,7 +17992,7 @@ __metadata: react-dom: "npm:^18.3.1" react-dropzone: "npm:^14.2.3" react-error-boundary: "npm:^4.0.13" - react-hook-form: "npm:^7.52.0" + react-hook-form: "npm:^7.53.0" react-is: "npm:^18.2.0" react-router: "npm:^6.25.1" react-router-dom: "npm:^6.25.1" @@ -18181,7 +18181,7 @@ __metadata: ra-i18n-polyglot: "npm:^5.1.2" ra-language-english: "npm:^5.1.2" ra-ui-materialui: "npm:^5.1.2" - react-hook-form: "npm:^7.52.0" + react-hook-form: "npm:^7.53.0" react-router: "npm:^6.22.0" react-router-dom: "npm:^6.22.0" rimraf: "npm:^3.0.2" @@ -18290,12 +18290,12 @@ __metadata: languageName: node linkType: hard -"react-hook-form@npm:^7.52.0": - version: 7.52.0 - resolution: "react-hook-form@npm:7.52.0" +"react-hook-form@npm:^7.53.0": + version: 7.53.0 + resolution: "react-hook-form@npm:7.53.0" peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - checksum: 058bf5596f314c071863bb133979deb56d0a7817d5bf1908a569c003fe03a15736402b040d3e18aeb259723c6e15c243fe75d2d887ea47ff4be87fc472f31ad5 + checksum: 6d62b150618a833c17d59e669b707661499e2bb516a8d340ca37699f99eb448bbba7b5b78324938c8948014e21efaa32e3510c2ba246fd5e97a96fca0cfa7c98 languageName: node linkType: hard @@ -19671,7 +19671,7 @@ __metadata: react: "npm:^18.3.1" react-admin: "npm:^5.1.2" react-dom: "npm:^18.3.1" - react-hook-form: "npm:^7.52.0" + react-hook-form: "npm:^7.53.0" react-router: "npm:^6.22.0" react-router-dom: "npm:^6.22.0" typescript: "npm:^5.1.3"