diff --git a/README.md b/README.md index 894f5fab..4f8f0d5f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ API | Form Builder | FAQs | - Examples + Examples

### Features @@ -58,10 +58,6 @@ function App() { } ``` - - - - ### Sponsors Thanks go to these kind and lovely sponsors! diff --git a/app/package.json b/app/package.json index d9d2ed15..1e0db29e 100644 --- a/app/package.json +++ b/app/package.json @@ -8,7 +8,7 @@ }, "license": "MIT", "dependencies": { - "@hookform/resolvers": "2.8.8", + "@hookform/resolvers": "3.4.2", "@material-ui/core": "^4.12.3", "joi": "^17.5.0", "react": "^17.0.1", diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index 940426f8..0ae860d5 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: dependencies: '@hookform/resolvers': - specifier: 2.8.8 - version: 2.8.8(react-hook-form@7.51.0) + specifier: 3.4.2 + version: 3.4.2(react-hook-form@7.51.4) '@material-ui/core': specifier: ^4.12.3 version: 4.12.4(@types/react@17.0.52)(react-dom@17.0.2)(react@17.0.2) @@ -401,7 +401,7 @@ packages: resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==} /@esbuild/android-arm@0.15.17: - resolution: {integrity: sha512-ay6Ken4u+JStjYmqIgh71jMT0bs/rXpCCDKaMfl78B20QYWJglT5P6Ejfm4hWf6Zi+uUWNe7ZmqakRs2BQYIeg==} + resolution: {integrity: sha512-ay6Ken4u+JStjYmqIgh71jMT0bs/rXpCCDKaMfl78B20QYWJglT5P6Ejfm4hWf6Zi+uUWNe7ZmqakRs2BQYIeg==, tarball: https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -410,7 +410,7 @@ packages: optional: true /@esbuild/linux-loong64@0.15.17: - resolution: {integrity: sha512-IA1O7f7qxw2DX8oqTpugHElr926phs7Rq8ULXleBMk4go5K05BU0mI8BfCkWcYAvcmVaMc13bv5W3LIUlU6Y9w==} + resolution: {integrity: sha512-IA1O7f7qxw2DX8oqTpugHElr926phs7Rq8ULXleBMk4go5K05BU0mI8BfCkWcYAvcmVaMc13bv5W3LIUlU6Y9w==, tarball: https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.17.tgz} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -436,8 +436,8 @@ packages: '@hapi/hoek': 9.3.0 dev: false - /@hookform/resolvers@2.8.8(react-hook-form@7.51.0): - resolution: {integrity: sha512-meAEDur1IJBfKyTo9yPYAuzjIfrxA7m9Ov+1nxaW/YupsqMeseWifoUjWK03+hz/RJizsVQAaUjVxFEkyu0GWg==} + /@hookform/resolvers@3.4.2(react-hook-form@7.51.4): + resolution: {integrity: sha512-1m9uAVIO8wVf7VCDAGsuGA0t6Z3m6jVGAN50HkV9vYLl0yixKK/Z1lr01vaRvYCkIKGoy1noVRxMzQYb4y/j1Q==, tarball: https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.4.2.tgz} peerDependencies: react-hook-form: ^7.0.0 dependencies: @@ -791,7 +791,7 @@ packages: is-arrayish: 0.2.1 /esbuild-android-64@0.15.17: - resolution: {integrity: sha512-sUs6cKMAuAyWnJ/66ezWVr9SMRGFSwoMagxzdhXYggSA12zF7krXSuc1Y9JwxHq56wtv/gFAVo97TFm7RBc1Ig==} + resolution: {integrity: sha512-sUs6cKMAuAyWnJ/66ezWVr9SMRGFSwoMagxzdhXYggSA12zF7krXSuc1Y9JwxHq56wtv/gFAVo97TFm7RBc1Ig==, tarball: https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -800,7 +800,7 @@ packages: optional: true /esbuild-android-arm64@0.15.17: - resolution: {integrity: sha512-RLZuCgIx1rexwxwsXTEW40ZiZzdBI1MBphwDRFyms/iiJGwLxqCH7v75iSJk5s6AF6oa80KC6r/RmzyaX/uJNg==} + resolution: {integrity: sha512-RLZuCgIx1rexwxwsXTEW40ZiZzdBI1MBphwDRFyms/iiJGwLxqCH7v75iSJk5s6AF6oa80KC6r/RmzyaX/uJNg==, tarball: https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -809,7 +809,7 @@ packages: optional: true /esbuild-darwin-64@0.15.17: - resolution: {integrity: sha512-+6RTCZ0hfAb+RqTNq1uVsBcP441yZOSi6CyV9BIBryGGVg8RM3Bc6L45e5b68jdRloddN92ekS50e4ElI+cHQA==} + resolution: {integrity: sha512-+6RTCZ0hfAb+RqTNq1uVsBcP441yZOSi6CyV9BIBryGGVg8RM3Bc6L45e5b68jdRloddN92ekS50e4ElI+cHQA==, tarball: https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -818,7 +818,7 @@ packages: optional: true /esbuild-darwin-arm64@0.15.17: - resolution: {integrity: sha512-ne4UWUHEKWLgYSE5SLr0/TBcID3k9LPnrzzRXzFLTfD+ygjnW1pMEgdMfmOKIe8jYBUYv8x/YoksriTdQb9r/Q==} + resolution: {integrity: sha512-ne4UWUHEKWLgYSE5SLr0/TBcID3k9LPnrzzRXzFLTfD+ygjnW1pMEgdMfmOKIe8jYBUYv8x/YoksriTdQb9r/Q==, tarball: https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -827,7 +827,7 @@ packages: optional: true /esbuild-freebsd-64@0.15.17: - resolution: {integrity: sha512-6my3DrwLOe1zhR8UzVRKeo9AFM9XkApJBcx0IE+qKaEbKKBxYAiDBtd2ZMtRA2agqIwRP0kuHofTiDEzpfA+ZA==} + resolution: {integrity: sha512-6my3DrwLOe1zhR8UzVRKeo9AFM9XkApJBcx0IE+qKaEbKKBxYAiDBtd2ZMtRA2agqIwRP0kuHofTiDEzpfA+ZA==, tarball: https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -836,7 +836,7 @@ packages: optional: true /esbuild-freebsd-arm64@0.15.17: - resolution: {integrity: sha512-LQL7+f+bz+xmAu1FcDBB304Wm2CjONUcOeF4f3TqG7wYXMxjjYQZBFv+0OVapNXyYrM2vy9JMDbps+SheuOnHg==} + resolution: {integrity: sha512-LQL7+f+bz+xmAu1FcDBB304Wm2CjONUcOeF4f3TqG7wYXMxjjYQZBFv+0OVapNXyYrM2vy9JMDbps+SheuOnHg==, tarball: https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -845,7 +845,7 @@ packages: optional: true /esbuild-linux-32@0.15.17: - resolution: {integrity: sha512-7E9vZXMZhINQ4/KcxBxioJ2ao5gbXJ6Pa4/LEUd102g3gadSalpg0LrityFgw7ao6qmjcNWwdEYrXaDnOzyyYA==} + resolution: {integrity: sha512-7E9vZXMZhINQ4/KcxBxioJ2ao5gbXJ6Pa4/LEUd102g3gadSalpg0LrityFgw7ao6qmjcNWwdEYrXaDnOzyyYA==, tarball: https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.17.tgz} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -854,7 +854,7 @@ packages: optional: true /esbuild-linux-64@0.15.17: - resolution: {integrity: sha512-TnedHtFQSUVlc0J0D4ZMMalYaQ0Zbt7HSwGy4sav7BlXVqDVc/rchJ/a9dathK51apzLgRyXQMseLf6bkloaSQ==} + resolution: {integrity: sha512-TnedHtFQSUVlc0J0D4ZMMalYaQ0Zbt7HSwGy4sav7BlXVqDVc/rchJ/a9dathK51apzLgRyXQMseLf6bkloaSQ==, tarball: https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -863,7 +863,7 @@ packages: optional: true /esbuild-linux-arm64@0.15.17: - resolution: {integrity: sha512-oupYfh0lTHg+F/2ZoTNrioB+KLd6x0Zlhjz2Oa1jhl8wCGkNvwe25RytR2/SGPYpoNVcvCeoayWQRwwRuWGgfQ==} + resolution: {integrity: sha512-oupYfh0lTHg+F/2ZoTNrioB+KLd6x0Zlhjz2Oa1jhl8wCGkNvwe25RytR2/SGPYpoNVcvCeoayWQRwwRuWGgfQ==, tarball: https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -872,7 +872,7 @@ packages: optional: true /esbuild-linux-arm@0.15.17: - resolution: {integrity: sha512-+ugCmBTTDIlh+UuC7E/GvyJqjGTX2pNOA+g3isG78aYcfgswrHjvstTtIfljaU95AS30qrVNLgI5h/8TsRWTrg==} + resolution: {integrity: sha512-+ugCmBTTDIlh+UuC7E/GvyJqjGTX2pNOA+g3isG78aYcfgswrHjvstTtIfljaU95AS30qrVNLgI5h/8TsRWTrg==, tarball: https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -881,7 +881,7 @@ packages: optional: true /esbuild-linux-mips64le@0.15.17: - resolution: {integrity: sha512-aUVyHwUXJF1hi9jsAT+At+cBxZh2yGICi/e757N6d/zzOD+eVK3PKQj68tAvIflx6/ZpnuCTKol1GpgGYrzERg==} + resolution: {integrity: sha512-aUVyHwUXJF1hi9jsAT+At+cBxZh2yGICi/e757N6d/zzOD+eVK3PKQj68tAvIflx6/ZpnuCTKol1GpgGYrzERg==, tarball: https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.17.tgz} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -890,7 +890,7 @@ packages: optional: true /esbuild-linux-ppc64le@0.15.17: - resolution: {integrity: sha512-i7789iFTLfLccHPNADCbaZPx9CuQblsBqv2j4XqIBN1jKIJbpQ8iqCkWoHep4PLqqKLtBLtTWh919GsrFGdeJA==} + resolution: {integrity: sha512-i7789iFTLfLccHPNADCbaZPx9CuQblsBqv2j4XqIBN1jKIJbpQ8iqCkWoHep4PLqqKLtBLtTWh919GsrFGdeJA==, tarball: https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.17.tgz} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -899,7 +899,7 @@ packages: optional: true /esbuild-linux-riscv64@0.15.17: - resolution: {integrity: sha512-fEQ/8tnZ2sDniBlPfTXEdg+0OP1olps96HvYdwl8ywJdAlD7AK761EL3lRbRdfMHNOId2N6+CVca43/Fiu/0AQ==} + resolution: {integrity: sha512-fEQ/8tnZ2sDniBlPfTXEdg+0OP1olps96HvYdwl8ywJdAlD7AK761EL3lRbRdfMHNOId2N6+CVca43/Fiu/0AQ==, tarball: https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.17.tgz} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -908,7 +908,7 @@ packages: optional: true /esbuild-linux-s390x@0.15.17: - resolution: {integrity: sha512-ZBQekST4gYgTKHAvUJtR1kFFulHTDlRZSE8T0wRQCmQqydNkC1teWxlR31xS6MZevjZGfa7OMVJD24bBhei/2Q==} + resolution: {integrity: sha512-ZBQekST4gYgTKHAvUJtR1kFFulHTDlRZSE8T0wRQCmQqydNkC1teWxlR31xS6MZevjZGfa7OMVJD24bBhei/2Q==, tarball: https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.17.tgz} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -917,7 +917,7 @@ packages: optional: true /esbuild-netbsd-64@0.15.17: - resolution: {integrity: sha512-onNBFaZVN9GzGJMm3aZJJv74n/Q8FjW20G9OfSDhHjvamqJ5vbd42hNk6igQX4lgBCHTZvvBlWDJAMy+tbJAAw==} + resolution: {integrity: sha512-onNBFaZVN9GzGJMm3aZJJv74n/Q8FjW20G9OfSDhHjvamqJ5vbd42hNk6igQX4lgBCHTZvvBlWDJAMy+tbJAAw==, tarball: https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -926,7 +926,7 @@ packages: optional: true /esbuild-openbsd-64@0.15.17: - resolution: {integrity: sha512-QFxHmvjaRrmTCvH/A3EmzqKUSZHRQ7/pbrJeATsb/Q6qckCeL9e7zg/1A3HiZqDXeBUV3yNeBeV1GJBjY6yVyA==} + resolution: {integrity: sha512-QFxHmvjaRrmTCvH/A3EmzqKUSZHRQ7/pbrJeATsb/Q6qckCeL9e7zg/1A3HiZqDXeBUV3yNeBeV1GJBjY6yVyA==, tarball: https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -935,7 +935,7 @@ packages: optional: true /esbuild-sunos-64@0.15.17: - resolution: {integrity: sha512-7dHZA8Kc6U8rBTKojJatXtzHTUKJ3CRYimvOGIQQ1yUDOqGx/zZkCH/HkEi3Zg5SWyDj/57E5e1YJPo4ySSw/w==} + resolution: {integrity: sha512-7dHZA8Kc6U8rBTKojJatXtzHTUKJ3CRYimvOGIQQ1yUDOqGx/zZkCH/HkEi3Zg5SWyDj/57E5e1YJPo4ySSw/w==, tarball: https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -944,7 +944,7 @@ packages: optional: true /esbuild-windows-32@0.15.17: - resolution: {integrity: sha512-yDrNrwQ/0k4N3OZItZ6k6YnBUch8+of06YRYc3hFI8VDm7X1rkNZwhttZNAzF6+TtbnK4cIz7H2/EwdSoaGZ3g==} + resolution: {integrity: sha512-yDrNrwQ/0k4N3OZItZ6k6YnBUch8+of06YRYc3hFI8VDm7X1rkNZwhttZNAzF6+TtbnK4cIz7H2/EwdSoaGZ3g==, tarball: https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.17.tgz} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -953,7 +953,7 @@ packages: optional: true /esbuild-windows-64@0.15.17: - resolution: {integrity: sha512-jPnXvB4zMMToNPpCBdt+OEQiYFVs9wlQ5G8vMoJkrYJBp1aEt070MRpBFa6pfBFrgXquqgUiNAohMcTdy+JVFg==} + resolution: {integrity: sha512-jPnXvB4zMMToNPpCBdt+OEQiYFVs9wlQ5G8vMoJkrYJBp1aEt070MRpBFa6pfBFrgXquqgUiNAohMcTdy+JVFg==, tarball: https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.17.tgz} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -962,7 +962,7 @@ packages: optional: true /esbuild-windows-arm64@0.15.17: - resolution: {integrity: sha512-I5QeSsz0X66V8rxVhmw03Wzn8Tz63H3L9GrsA7C5wvBXMk3qahLWuEL+l7SZ2DleKkFeZZMu1dPxOak9f1TZ4A==} + resolution: {integrity: sha512-I5QeSsz0X66V8rxVhmw03Wzn8Tz63H3L9GrsA7C5wvBXMk3qahLWuEL+l7SZ2DleKkFeZZMu1dPxOak9f1TZ4A==, tarball: https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.17.tgz} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -1016,7 +1016,7 @@ packages: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true diff --git a/package.json b/package.json index e006af6d..96399d10 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-hook-form", "description": "Performant, flexible and extensible forms library for React Hooks", - "version": "7.51.2", + "version": "7.51.5", "main": "dist/index.cjs.js", "module": "dist/index.esm.mjs", "umd:main": "dist/index.umd.js", @@ -118,12 +118,12 @@ "files": [ { "path": "./dist/index.cjs.js", - "maxSize": "10.1 kB" + "maxSize": "10.2 kB" } ] }, "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18" + "react": "^16.8.0 || ^17 || ^18 || ^19" }, "lint-staged": { "*.{js,ts,tsx}": [ diff --git a/reports/api-extractor.md b/reports/api-extractor.md index e47bcefe..0106d52d 100644 --- a/reports/api-extractor.md +++ b/reports/api-extractor.md @@ -486,7 +486,7 @@ export type RegisterOptions void; onBlur?: (event: any) => void; disabled: boolean; - deps: InternalFieldName | InternalFieldName[]; + deps: FieldPath | FieldPath[]; }> & ({ pattern?: ValidationRule; valueAsNumber?: false; @@ -532,7 +532,7 @@ export type ResolverSuccess = { }; // @public (undocumented) -export const set: (object: FieldValues, path: string, value?: unknown) => FieldValues; +export const set: (object: FieldValues, path: string, value?: unknown) => FieldValues | undefined; // @public (undocumented) export type SetFieldValue = FieldValue; @@ -867,6 +867,7 @@ export type WatchInternal = (fieldNames?: InternalFieldName | Inte export type WatchObserver = (value: DeepPartial, info: { name?: FieldPath; type?: EventType; + values?: unknown; }) => void; // Warnings were encountered during analysis: diff --git a/src/__tests__/logic/iterateFieldsByAction.test.ts b/src/__tests__/logic/iterateFieldsByAction.test.ts index 7ede3c90..74803598 100644 --- a/src/__tests__/logic/iterateFieldsByAction.test.ts +++ b/src/__tests__/logic/iterateFieldsByAction.test.ts @@ -1,6 +1,6 @@ import iterateFieldsByAction from '../../logic/iterateFieldsByAction'; -describe('focusFieldBy', () => { +describe('iterateFieldsByAction', () => { it('should focus on the first error it encounter', () => { const focus = jest.fn(); iterateFieldsByAction( diff --git a/src/__tests__/useForm/setError.test.tsx b/src/__tests__/useForm/setError.test.tsx index 8486c13b..656f3c14 100644 --- a/src/__tests__/useForm/setError.test.tsx +++ b/src/__tests__/useForm/setError.test.tsx @@ -164,4 +164,91 @@ describe('setError', () => { screen.findByText('not found'); }); }); + + it('should allow sequential calls to set with child after ancestor', async () => { + const { result } = renderHook(() => + useForm<{ input: { first: string; last: string } }>(), + ); + result.current.formState.errors; + + act(() => { + result.current.setError('input', { + type: 'test', + message: 'Some error that depends on both fields', + }); + }); + + expect(result.current.formState.errors).toEqual({ + input: { + type: 'test', + message: 'Some error that depends on both fields', + ref: undefined, + }, + }); + + act(() => { + result.current.setError('input.first', { + type: 'test', + message: 'Name must be capitalized', + }); + }); + + expect(result.current.formState.errors).toEqual({ + input: { + type: 'test', + message: 'Some error that depends on both fields', + ref: undefined, + first: { + type: 'test', + message: 'Name must be capitalized', + ref: undefined, + }, + }, + }); + }); + + it('should allow sequential calls to set with ancestor after child', async () => { + const { result } = renderHook(() => + useForm<{ input: { first: string; last: string } }>(), + ); + + result.current.formState.errors; + + act(() => { + result.current.setError('input.first', { + type: 'test', + message: 'Name must be capitalized', + }); + }); + + expect(result.current.formState.errors).toEqual({ + input: { + first: { + type: 'test', + message: 'Name must be capitalized', + ref: undefined, + }, + }, + }); + + act(() => { + result.current.setError('input', { + type: 'test', + message: 'Some error that depends on both fields', + }); + }); + + expect(result.current.formState.errors).toEqual({ + input: { + type: 'test', + message: 'Some error that depends on both fields', + ref: undefined, + first: { + type: 'test', + message: 'Name must be capitalized', + ref: undefined, + }, + }, + }); + }); }); diff --git a/src/__tests__/utils/set.test.ts b/src/__tests__/utils/set.test.ts index d89e06c1..7f83cfcf 100644 --- a/src/__tests__/utils/set.test.ts +++ b/src/__tests__/utils/set.test.ts @@ -57,4 +57,9 @@ describe('set', () => { }, }); }); + + it('should not populate prototype', () => { + set({}, '__proto__[test2]', '456'); + expect(Object.prototype).toEqual({}); + }); }); diff --git a/src/logic/createFormControl.ts b/src/logic/createFormControl.ts index 4528dbe3..ac259f55 100644 --- a/src/logic/createFormControl.ts +++ b/src/logic/createFormControl.ts @@ -310,7 +310,9 @@ export function createFormControl< name, }; const disabledField = !!( - get(_fields, name) && get(_fields, name)._f.disabled + get(_fields, name) && + get(_fields, name)._f && + get(_fields, name)._f.disabled ); if (!isBlurEvent || shouldDirty) { @@ -680,6 +682,7 @@ export function createFormControl< }; const onChange: ChangeHandler = async (event) => { + _state.mount = true; const target = event.target; let name = target.name as string; let isFieldValueUpdated = true; @@ -869,8 +872,7 @@ export function createFormControl< | ReadonlyArray>, ) => { const values = { - ..._defaultValues, - ...(_state.mount ? _formValues : {}), + ...(_state.mount ? _formValues : _defaultValues), }; return isUndefined(fieldNames) @@ -886,9 +888,9 @@ export function createFormControl< ) => ({ invalid: !!get((formState || _formState).errors, name), isDirty: !!get((formState || _formState).dirtyFields, name), - isTouched: !!get((formState || _formState).touchedFields, name), - isValidating: !!get((formState || _formState).validatingFields, name), error: get((formState || _formState).errors, name), + isValidating: !!get(_formState.validatingFields, name), + isTouched: !!get((formState || _formState).touchedFields, name), }); const clearErrors: UseFormClearErrors = (name) => { @@ -904,8 +906,13 @@ export function createFormControl< const setError: UseFormSetError = (name, error, options) => { const ref = (get(_fields, name, { _f: {} })._f || {}).ref; + const currentError = get(_formState.errors, name) || {}; + + // Don't override existing error messages elsewhere in the object tree. + const { ref: currentRef, message, type, ...restOfErrorTree } = currentError; set(_formState.errors, name, { + ...restOfErrorTree, ...error, ref, }); @@ -983,7 +990,7 @@ export function createFormControl< fields, value, }) => { - if (isBoolean(disabled)) { + if ((isBoolean(disabled) && _state.mount) || !!disabled) { const inputValue = disabled ? undefined : isUndefined(value) @@ -1098,13 +1105,16 @@ export function createFormControl< iterateFieldsByAction( _fields, (ref, name) => { - let requiredDisabledState = disabled; - const currentField = get(_fields, name); - if (currentField && isBoolean(currentField._f.disabled)) { - requiredDisabledState ||= currentField._f.disabled; + const currentField: Field = get(_fields, name); + if (currentField) { + ref.disabled = currentField._f.disabled || disabled; + + if (Array.isArray(currentField._f.refs)) { + currentField._f.refs.forEach((inputRef) => { + inputRef.disabled = currentField._f.disabled || disabled; + }); + } } - - ref.disabled = requiredDisabledState; }, 0, false, @@ -1299,6 +1309,8 @@ export function createFormControl< : _formState.dirtyFields : keepStateOptions.keepDefaultValues && formValues ? getDirtyFields(_defaultValues, formValues) + : keepStateOptions.keepDirty + ? _formState.dirtyFields : {}, touchedFields: keepStateOptions.keepTouched ? _formState.touchedFields diff --git a/src/types/form.ts b/src/types/form.ts index ba3b7e0c..d4933c8f 100644 --- a/src/types/form.ts +++ b/src/types/form.ts @@ -825,6 +825,7 @@ export type WatchObserver = ( info: { name?: FieldPath; type?: EventType; + values?: unknown; }, ) => void; diff --git a/src/types/validator.ts b/src/types/validator.ts index 211a45c9..6c4f744b 100644 --- a/src/types/validator.ts +++ b/src/types/validator.ts @@ -1,7 +1,7 @@ import { INPUT_VALIDATION_RULES } from '../constants'; import { Message } from './errors'; -import { FieldValues, InternalFieldName } from './fields'; +import { FieldValues } from './fields'; import { FieldPath, FieldPathValue } from './path'; export type ValidationValue = boolean | number | string | RegExp; @@ -45,7 +45,7 @@ export type RegisterOptions< onChange?: (event: any) => void; onBlur?: (event: any) => void; disabled: boolean; - deps: InternalFieldName | InternalFieldName[]; + deps: FieldPath | FieldPath[]; }> & ( | { diff --git a/src/useController.ts b/src/useController.ts index 9f81698a..10021d25 100644 --- a/src/useController.ts +++ b/src/useController.ts @@ -6,6 +6,7 @@ import cloneObject from './utils/cloneObject'; import get from './utils/get'; import isBoolean from './utils/isBoolean'; import isUndefined from './utils/isUndefined'; +import set from './utils/set'; import { EVENTS } from './constants'; import { ControllerFieldState, @@ -20,7 +21,6 @@ import { import { useFormContext } from './useFormContext'; import { useFormState } from './useFormState'; import { useWatch } from './useWatch'; -import { set } from './utils'; /** * Custom hook to work with controlled component, this function provide you with both form and field level state. Re-render is isolated at the hook level. @@ -85,7 +85,7 @@ export function useController< const updateMounted = (name: InternalFieldName, value: boolean) => { const field: Field = get(control._fields, name); - if (field) { + if (field && field._f) { field._f.mount = value; } }; diff --git a/src/utils/set.ts b/src/utils/set.ts index f26e3c19..d99b3b08 100644 --- a/src/utils/set.ts +++ b/src/utils/set.ts @@ -23,6 +23,11 @@ export default (object: FieldValues, path: string, value?: unknown) => { ? [] : {}; } + + if (key === '__proto__') { + return; + } + object[key] = newValue; object = object[key]; }