Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

πŸ‘―β€β™‚οΈ support async defaultValues and form values update #9261

Merged
merged 67 commits into from Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
ee674ee
auto reset form values with reactive values prop
bluebill1049 Oct 24, 2022
da0e195
Merge branch 'master' into useForm-values-prop
bluebill1049 Oct 24, 2022
8240e67
remove redundant set
bluebill1049 Oct 24, 2022
a523c0d
update API
bluebill1049 Oct 24, 2022
a13420a
check for object instead of null/undefined
bluebill1049 Oct 24, 2022
8a2f078
remove redundant Object.is and isObject check
bluebill1049 Oct 24, 2022
c00964f
😞increase bundle check size
bluebill1049 Oct 24, 2022
d7d71ed
rename from `resetValuesOptions` to `resetOptions`
bluebill1049 Oct 24, 2022
6426d87
update API extrator
bluebill1049 Oct 24, 2022
2530463
update with test cases
bluebill1049 Oct 24, 2022
0a0c0e7
remove extra sleep function
bluebill1049 Oct 24, 2022
ccc6554
remove useCallback
bluebill1049 Oct 24, 2022
bcbb120
deps package update
bluebill1049 Oct 24, 2022
a3e78d0
fix build
bluebill1049 Oct 25, 2022
64768f4
Merge branch 'master' into useForm-values-prop
bluebill1049 Oct 25, 2022
2c50c14
Revert "fix build"
bluebill1049 Oct 25, 2022
10f43e4
Revert "deps package update"
bluebill1049 Oct 25, 2022
d2b0bb4
Merge branch 'master' into useForm-values-prop
bluebill1049 Oct 26, 2022
f03a2db
support async defaultValues
bluebill1049 Oct 27, 2022
c6deb58
fix defaultValues as default state
bluebill1049 Oct 27, 2022
29bd296
fix type
bluebill1049 Oct 27, 2022
d34df9b
update API extrator
bluebill1049 Oct 27, 2022
c70eec7
Merge branch 'master' into useForm-values-prop
bluebill1049 Oct 29, 2022
c820e23
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 1, 2022
dd626c1
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 2, 2022
3c69221
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 8, 2022
d1f3535
add missing type test
bluebill1049 Nov 8, 2022
fc499dd
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 10, 2022
a462ddd
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 10, 2022
abad4b2
save bytes
bluebill1049 Nov 11, 2022
3bf0db5
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 14, 2022
0502cb0
brought change from main
bluebill1049 Nov 14, 2022
1ad7561
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 16, 2022
28cf885
7.40.0-next.0
bluebill1049 Nov 17, 2022
a5fe237
improve resetOptions with keepDirtyValues without subscription to for…
bluebill1049 Nov 17, 2022
01c8ff7
keep update dirty fields internally without subscription
bluebill1049 Nov 17, 2022
f0ec5f9
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 17, 2022
6e64ce9
update type for AsyncDefaultValues
bluebill1049 Nov 18, 2022
2737cb6
update api extrator
bluebill1049 Nov 18, 2022
9795e43
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 19, 2022
4d92e0e
update packages
bluebill1049 Nov 19, 2022
ae827fd
infer type from async defaultValues (#9387)
bluebill1049 Nov 20, 2022
cdc3886
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 21, 2022
2dad2e4
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 22, 2022
3ac36d8
7.40.0-next.1
bluebill1049 Nov 23, 2022
362f369
fix UnPackDefaultValues at path level and rename tsd to test:type
bluebill1049 Nov 24, 2022
309ee8a
Revert "fix UnPackDefaultValues at path level and rename tsd to test:…
bluebill1049 Nov 24, 2022
06e6839
fix array field path
bluebill1049 Nov 24, 2022
2a23468
fix api extrator
bluebill1049 Nov 24, 2022
82be978
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 25, 2022
824c806
- fix touched, dirty field state promise infer
bluebill1049 Nov 26, 2022
b0b885e
- rename to UnPackAsyncDefaultValues
bluebill1049 Nov 26, 2022
73576f9
- fix test script for workflow
bluebill1049 Nov 26, 2022
69014f9
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 26, 2022
b86f8ce
update packages
bluebill1049 Nov 26, 2022
411f375
type test coverage for each hooks
bluebill1049 Nov 26, 2022
95e00f8
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 27, 2022
968182d
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 29, 2022
73ca3d7
Merge branch 'master' into useForm-values-prop
bluebill1049 Nov 29, 2022
a42adf0
resolve conflict from master branch
bluebill1049 Nov 29, 2022
d1f3de9
- fix test case
bluebill1049 Nov 30, 2022
6302558
move getValidationModes to logic folder
bluebill1049 Nov 30, 2022
77b792c
fix import
bluebill1049 Nov 30, 2022
54f55b0
revert change on useWatch
bluebill1049 Nov 30, 2022
5e3d381
Merge branch 'master' into useForm-values-prop
bluebill1049 Dec 1, 2022
c74fed1
- update test case to include controlled component
bluebill1049 Dec 2, 2022
5108c46
Merge branch 'master' into useForm-values-prop
bluebill1049 Dec 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Test
run: |
yarn test --ci
yarn tsd
yarn test:type

- name: Bundle watch
run: |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -42,7 +42,7 @@
"test:web": "TEST_ENV=web yarn test",
"test:server": "TEST_ENV=server yarn test",
"test:native": "TEST_ENV=native yarn test",
"tsd": "tsd src/__typetest__",
"test:type": "tsd src/__typetest__",
"e2e": "cypress run",
"e2e:watch": "cypress open",
"api-extractor": "api-extractor run --local",
Expand Down
31 changes: 19 additions & 12 deletions reports/api-extractor.md
Expand Up @@ -54,6 +54,7 @@ export type Control<TFieldValues extends FieldValues = FieldValues, TContext = a
action: boolean;
watch: boolean;
};
_reset: UseFormReset<TFieldValues>;
_options: UseFormProps<TFieldValues, TContext>;
_getDirty: GetIsDirty;
_formState: FormState<TFieldValues>;
Expand All @@ -74,7 +75,7 @@ export type Control<TFieldValues extends FieldValues = FieldValues, TContext = a
};

// @public
export const Controller: <TFieldValues extends FieldValues = FieldValues, TName extends Path<TFieldValues> = Path<TFieldValues>>(props: ControllerProps<TFieldValues, TName>) => ReactElement<any, string | JSXElementConstructor<any>>;
export const Controller: <TFieldValues extends FieldValues = FieldValues, TName extends Path<UnPackAsyncDefaultValues<TFieldValues>> = Path<UnPackAsyncDefaultValues<TFieldValues>>>(props: ControllerProps<TFieldValues, TName>) => ReactElement<any, string | JSXElementConstructor<any>>;

// @public (undocumented)
export type ControllerFieldState = {
Expand Down Expand Up @@ -181,10 +182,10 @@ export type FieldArrayMethodProps = {
};

// @public
export type FieldArrayPath<TFieldValues extends FieldValues> = ArrayPath<TFieldValues>;
export type FieldArrayPath<TFieldValues extends FieldValues> = ArrayPath<UnPackAsyncDefaultValues<TFieldValues>>;

// @public
export type FieldArrayPathValue<TFieldValues extends FieldValues, TFieldArrayPath extends FieldArrayPath<TFieldValues>> = PathValue<TFieldValues, TFieldArrayPath>;
export type FieldArrayPathValue<TFieldValues extends FieldValues, TFieldArrayPath extends FieldArrayPath<TFieldValues>> = PathValue<UnPackAsyncDefaultValues<TFieldValues>, TFieldArrayPath>;

// @public
export type FieldArrayWithId<TFieldValues extends FieldValues = FieldValues, TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>, TKeyName extends string = 'id'> = FieldArray<TFieldValues, TFieldArrayName> & Record<TKeyName, string>;
Expand All @@ -202,7 +203,7 @@ export type FieldError = {
};

// @public (undocumented)
export type FieldErrors<T extends FieldValues = FieldValues> = Partial<FieldValues extends IsAny<FieldValues> ? any : FieldErrorsImpl<DeepRequired<T>>>;
export type FieldErrors<T extends FieldValues = FieldValues> = Partial<FieldValues extends IsAny<FieldValues> ? any : FieldErrorsImpl<DeepRequired<UnPackAsyncDefaultValues<T>>>>;

// @public (undocumented)
export type FieldErrorsImpl<T extends FieldValues = FieldValues> = {
Expand All @@ -216,15 +217,15 @@ export type FieldName<TFieldValues extends FieldValues> = IsFlatObject<TFieldVal
export type FieldNamesMarkedBoolean<TFieldValues extends FieldValues> = DeepMap<DeepPartial<TFieldValues>, boolean>;

// @public
export type FieldPath<TFieldValues extends FieldValues> = Path<TFieldValues>;
export type FieldPath<TFieldValues extends FieldValues> = Path<UnPackAsyncDefaultValues<TFieldValues>>;

// @public
export type FieldPathByValue<TFieldValues extends FieldValues, TValue> = {
[Key in FieldPath<TFieldValues>]: FieldPathValue<TFieldValues, Key> extends TValue ? Key : never;
}[FieldPath<TFieldValues>];

// @public
export type FieldPathValue<TFieldValues extends FieldValues, TFieldPath extends FieldPath<TFieldValues>> = PathValue<TFieldValues, TFieldPath>;
export type FieldPathValue<TFieldValues extends FieldValues, TFieldPath extends FieldPath<TFieldValues>> = PathValue<UnPackAsyncDefaultValues<TFieldValues>, TFieldPath>;

// @public
export type FieldPathValues<TFieldValues extends FieldValues, TPath extends FieldPath<TFieldValues>[] | readonly FieldPath<TFieldValues>[]> = {} & {
Expand Down Expand Up @@ -257,9 +258,9 @@ export type FormState<TFieldValues extends FieldValues> = {
isValidating: boolean;
isValid: boolean;
submitCount: number;
defaultValues?: Readonly<DeepPartial<TFieldValues>> | TFieldValues;
dirtyFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>;
touchedFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>;
defaultValues?: UnPackAsyncDefaultValues<TFieldValues> | undefined | Readonly<DeepPartial<TFieldValues>>;
dirtyFields: Partial<Readonly<FieldNamesMarkedBoolean<UnPackAsyncDefaultValues<TFieldValues>>>>;
touchedFields: Partial<Readonly<FieldNamesMarkedBoolean<UnPackAsyncDefaultValues<TFieldValues>>>>;
errors: FieldErrors<TFieldValues>;
};

Expand Down Expand Up @@ -486,6 +487,9 @@ export type TriggerConfig = Partial<{
shouldFocus: boolean;
}>;

// @public (undocumented)
export type UnPackAsyncDefaultValues<TFieldValues> = TFieldValues extends () => Promise<infer U> ? U : TFieldValues;

// @public @deprecated (undocumented)
export type UnpackNestedValue<T> = T extends NestedValue<infer U> ? U : T extends Date | FileList | File | Blob ? T : T extends object ? {
[K in keyof T]: UnpackNestedValue<T[K]>;
Expand Down Expand Up @@ -589,10 +593,12 @@ export type UseFormGetValues<TFieldValues extends FieldValues> = {
export type UseFormHandleSubmit<TFieldValues extends FieldValues> = (onValid: SubmitHandler<TFieldValues>, onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: React_2.BaseSyntheticEvent) => Promise<void>;

// @public (undocumented)
export type UseFormProps<TFieldValues extends FieldValues = FieldValues, TContext = any> = Partial<{
export type UseFormProps<TFieldValues extends UnPackAsyncDefaultValues<FieldValues> = UnPackAsyncDefaultValues<FieldValues>, TContext = any> = Partial<{
mode: Mode;
reValidateMode: Exclude<Mode, 'onTouched' | 'all'>;
defaultValues: DefaultValues<TFieldValues>;
defaultValues: DefaultValues<TFieldValues> | AsyncDefaultValues<TFieldValues>;
values: TFieldValues;
resetOptions: Parameters<UseFormReset<TFieldValues>>[1];
resolver: Resolver<TFieldValues, TContext>;
context: TContext;
shouldFocusError: boolean;
Expand Down Expand Up @@ -771,7 +777,8 @@ export type WatchObserver<TFieldValues extends FieldValues> = (value: DeepPartia

// Warnings were encountered during analysis:
//
// src/types/form.ts:418:3 - (ae-forgotten-export) The symbol "Subscription" needs to be exported by the entry point index.d.ts
// src/types/form.ts:97:3 - (ae-forgotten-export) The symbol "AsyncDefaultValues" needs to be exported by the entry point index.d.ts
// src/types/form.ts:431:3 - (ae-forgotten-export) The symbol "Subscription" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
@@ -1,4 +1,4 @@
import isPlainObject from './isPlainObject';
import isPlainObject from '../utils/isPlainObject';

describe('isPlainObject', function () {
it('should identify plan object or not', function () {
Expand All @@ -12,11 +12,11 @@ describe('isPlainObject', function () {
expect(isPlainObject(Object.create(Object.prototype))).toBeTruthy();
expect(isPlainObject({ foo: 'bar' })).toBeTruthy();
expect(isPlainObject({})).toBeTruthy();
expect(isPlainObject(Object.create(null))).toBeTruthy();
expect(!isPlainObject(/foo/)).toBeFalsy();
expect(!isPlainObject(function () {})).toBeFalsy();
expect(!isPlainObject(['foo', 'bar'])).toBeFalsy();
expect(!isPlainObject([])).toBeFalsy();
expect(!isPlainObject(test)).toBeFalsy();
expect(isPlainObject(Object.create(null))).toBeFalsy();
expect(!isPlainObject(/foo/)).toBeTruthy();
expect(!isPlainObject(function () {})).toBeTruthy();
expect(!isPlainObject(['foo', 'bar'])).toBeTruthy();
expect(!isPlainObject([])).toBeTruthy();
expect(!isPlainObject(test)).toBeTruthy();
});
});
128 changes: 128 additions & 0 deletions src/__tests__/type.test.tsx
Expand Up @@ -6,10 +6,13 @@ import {
FieldPath,
FieldValues,
Path,
PathValue,
UseFormRegister,
} from '../types';
import { useController } from '../useController';
import { useFieldArray } from '../useFieldArray';
import { useForm } from '../useForm';
import { useFormState } from '../useFormState';
import { useWatch } from '../useWatch';

test('should not throw type error with path name', () => {
Expand Down Expand Up @@ -265,13 +268,127 @@ test('should support nullable field errors', () => {
errors;
});

test('should work with generic component path assertion', () => {
function App<T extends FieldValues>() {
const { register } = useForm<T>();
const FIELD_DATA_EXTENSION = '__data';
const item = {
value: 'data',
};

register(`FieldName${FIELD_DATA_EXTENSION}` as FieldPath<T>, {
value: item as PathValue<T, Path<T>>,
});

return null;
}

App;
});

test('should infer async default values', () => {
function App() {
const {
register,
control,
formState,
setValue,
reset,
watch,
getValues,
getFieldState,
clearErrors,
unregister,
setFocus,
trigger,
setError,
} = useForm({
defaultValues: async () => {
return {
test: 'test',
test1: {
nested: 'test',
},
fieldArray: [{ test: '' }],
};
},
});
useFieldArray({
name: 'fieldArray' as const,
control,
});
useController({
name: 'test1.nested',
control,
});
useWatch({
name: 'test1',
control,
});
useFormState({
name: 'fieldArray',
control,
});

setValue('test', 'data');
setValue('test1.nested', 'data');
reset({
test: 'test',
test1: 'test1',
});

watch('test');
watch('test1.nested');

getValues('test');
getValues('test1.nested');

getFieldState('test');
getFieldState('test1.nested');

clearErrors('test');
clearErrors('test1.nested');

unregister('test');
unregister('test1.nested');

setFocus('test');
setFocus('test1.nested');

trigger('test');
trigger('test1.nested');

setError('test', { type: 'test ' });
setError('test1.nested', { type: 'test ' });

return (
<form>
<input {...register('test')} />
<Controller render={() => <input />} name={'test1'} control={control} />
<p>{formState.errors?.test?.message}</p>
<p>{formState.errors?.test1?.message}</p>
<p>{formState.touchedFields.test}</p>
<p>{formState.touchedFields.test1?.nested}</p>
<p>{formState.dirtyFields.test}</p>
<p>{formState.dirtyFields.test1?.nested}</p>
</form>
);
}

App;
});

test('should provide correct type for validate function with useFieldArray', () => {
const App = () => {
const { control } = useForm<{
test: {
first: string;
last: string;
}[];
test1: {
first: string;
last: string;
}[];
}>({
defaultValues: {
test: [
Expand All @@ -291,6 +408,17 @@ test('should provide correct type for validate function with useFieldArray', ()
},
},
});
useFieldArray({
control,
name: 'test1',
rules: {
validate: {
test: (data) => {
return !!data.find((test) => test.first && test.last);
},
},
},
});

return null;
};
Expand Down