Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
Feat(useForm): new setFocus API
Browse files Browse the repository at this point in the history
  • Loading branch information
wellyshen committed Mar 28, 2021
1 parent a799d3c commit 5539448
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 25 deletions.
5 changes: 0 additions & 5 deletions .changeset/blue-books-warn.md

This file was deleted.

5 changes: 5 additions & 0 deletions .changeset/brave-doors-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-cool-form": patch
---

Feat(useForm): new `setFocus` API
5 changes: 0 additions & 5 deletions .changeset/hungry-pants-play.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/tasty-shrimps-lick.md

This file was deleted.

10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# react-cool-form

## 0.0.153

### Patch Changes

- [`7de1f62`](https:/wellyshen/react-cool-form/commit/7de1f62fb3b03d1aef8a5fe7041fedf1a48931fe) Thanks [@wellyshen](https:/wellyshen)! - Docs(readme): add arrays-and-lists feature

* [#518](https:/wellyshen/react-cool-form/pull/518) [`cf7980f`](https:/wellyshen/react-cool-form/commit/cf7980f72790bc6f5a95192fff629ec909ab38ad) Thanks [@wellyshen](https:/wellyshen)! - Fix(useForm): when running field validation with nested field(s), error results will be overrided by the last field

- [`c2459ee`](https:/wellyshen/react-cool-form/commit/c2459eebbd18fd2cdbf58aa3552d51cbc650c5c0) Thanks [@wellyshen](https:/wellyshen)! - Refactor(types): rename `Map` to `ObjMap`

## 0.0.152

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-cool-form",
"version": "0.0.152",
"version": "0.0.153",
"description": "React hooks for forms state and validation, less code more performant.",
"license": "MIT",
"homepage": "https://react-cool-form.netlify.app",
Expand Down
9 changes: 8 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,10 @@ export type FieldArray = ObjMap<{ fields: ObjMap; reset: () => void }>;
interface EventOptions<V> {
getState: GetState;
setValue: SetValue;
setError: SetError;
setTouched: SetTouched;
setDirty: SetDirty;
setError: SetError;
setFocus: SetFocus;
clearErrors: ClearErrors;
runValidation: RunValidation;
reset: Reset<V>;
Expand Down Expand Up @@ -232,6 +233,10 @@ export interface SetDirty {
(name: string, isDirty?: boolean): void;
}

export interface SetFocus {
(name: string | string[] | ((names: string[]) => string[])): void;
}

export interface SetError {
(name: string, error?: any | ((previousError?: any) => any)): void;
}
Expand Down Expand Up @@ -271,6 +276,7 @@ export type FormConfig<V = any> = Partial<{
validate: FormValidator<V>;
validateOnChange: boolean;
validateOnBlur: boolean;
focusOnError: boolean;
builtInValidationMode: "message" | "state" | false;
shouldRemoveField: boolean;
excludeFields: string[];
Expand All @@ -288,6 +294,7 @@ export interface FormMethods<V = any> {
setValue: SetValue;
setTouched: SetTouched;
setDirty: SetDirty;
setFocus: SetFocus;
setError: SetError;
clearErrors: ClearErrors;
runValidation: RunValidation;
Expand Down
11 changes: 11 additions & 0 deletions src/types/react-cool-form.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ declare module "react-cool-form" {
setValue: SetValue;
setTouched: SetTouched;
setDirty: SetDirty;
setFocus: SetFocus;
setError: SetError;
clearErrors: ClearErrors;
runValidation: RunValidation;
Expand Down Expand Up @@ -50,6 +51,10 @@ declare module "react-cool-form" {
(name: string, isDirty?: boolean): void;
}

interface SetFocus {
(name: string | string[] | FieldNamesFn): void;
}

interface SetError {
(name: string, error: any | PreviousErrorFn): void;
}
Expand Down Expand Up @@ -113,6 +118,10 @@ declare module "react-cool-form" {
submitCount: number;
}>;

export interface FieldNamesFn<N extends string[] = string[]> {
(names: N): N;
}

export interface PreviousValuesFn<V extends FormValues = FormValues> {
(previousValues: V): V;
}
Expand Down Expand Up @@ -171,6 +180,7 @@ declare module "react-cool-form" {
validate: FormValidator<V>;
validateOnChange: boolean;
validateOnBlur: boolean;
focusOnError: boolean;
builtInValidationMode: "message" | "state" | false;
shouldRemoveField: boolean;
excludeFields: string[];
Expand All @@ -188,6 +198,7 @@ declare module "react-cool-form" {
setValue: SetValue;
setTouched: SetTouched;
setDirty: SetDirty;
setFocus: SetFocus;
setError: SetError;
clearErrors: ClearErrors;
runValidation: RunValidation;
Expand Down
64 changes: 56 additions & 8 deletions src/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
SetDefaultValue,
SetDirty,
SetError,
SetFocus,
SetNodesOrValues,
SetTouched,
SetTouchedMaybeValidate,
Expand Down Expand Up @@ -60,6 +61,7 @@ import {
isRangeInput,
isSelectMultiple,
isSelectOne,
isString,
isUndefined,
parseState,
runWithLowPriority,
Expand All @@ -74,6 +76,7 @@ export default <V extends FormValues = FormValues>({
validate,
validateOnChange = true,
validateOnBlur = true,
focusOnError = true,
builtInValidationMode = "message",
shouldRemoveField = true,
excludeFields = [],
Expand Down Expand Up @@ -598,6 +601,8 @@ export default <V extends FormValues = FormValues>({
handleUnset(`touched.${name}`);
}

fieldsRef.current.forEach(({ field }) => field.blur());

if (shouldValidate) validateFieldWithLowPriority(name);
},
[handleUnset, setStateRef, validateFieldWithLowPriority, validateOnBlur]
Expand Down Expand Up @@ -657,13 +662,13 @@ export default <V extends FormValues = FormValues>({
}
setNodeValue(name, value);

if (shouldTouched) setTouched(name, true, false);
if (shouldDirty) setDirtyIfNeeded(name);
if (shouldValidate) validateFieldWithLowPriority(name);

isFieldArray(fieldArrayRef.current, name, (key) =>
fieldArrayRef.current[key].reset()
);

if (shouldTouched) setTouched(name, true, false);
if (shouldDirty) setDirtyIfNeeded(name);
if (shouldValidate) validateFieldWithLowPriority(name);
},
[
handleUnset,
Expand All @@ -677,12 +682,42 @@ export default <V extends FormValues = FormValues>({
]
);

const setFocus = useCallback<SetFocus>(
(name) => {
const fieldNames = Array.from(fieldsRef.current.keys());

if (isString(name)) {
const field =
fieldsRef.current.get(name)?.field ||
fieldsRef.current.get(
fieldNames.find((fieldName) =>
fieldName.startsWith(name as string)
) || ""
)?.field;

if (field) field.focus();

return;
}

name = isFunction(name) ? name(fieldNames) : name;

for (const n of name)
if (get(stateRef.current.errors, n)) {
setFocus(n);
break;
}
},
[stateRef]
);

const getOptions = useCallback(
() => ({
getState,
setValue,
setTouched,
setDirty,
setFocus,
setError,
clearErrors,
runValidation,
Expand Down Expand Up @@ -758,6 +793,8 @@ export default <V extends FormValues = FormValues>({
if (!isEmptyObject(errors)) {
onErrorRef.current(errors, getOptions(), e);

if (focusOnError) setFocus(Array.from(fieldsRef.current.keys()));

return { errors };
}

Expand All @@ -772,7 +809,16 @@ export default <V extends FormValues = FormValues>({
setStateRef("isSubmitting", false);
}
},
[getOptions, onErrorRef, onSubmitRef, setStateRef, stateRef, validateForm]
[
getOptions,
onErrorRef,
onSubmitRef,
setFocus,
setStateRef,
focusOnError,
stateRef,
validateForm,
]
);

const handleChangeEvent = useCallback<HandleChangeEvent>(
Expand Down Expand Up @@ -870,15 +916,15 @@ export default <V extends FormValues = FormValues>({
const fields = getFields(form);

if (shouldRemoveField)
Array.from(fieldsRef.current.keys()).forEach((name) => {
fieldsRef.current.forEach((_, name) => {
if (controlsRef.current[name]) return;

if (!fields.has(name)) {
removeField(name);
return;
}

const currOptions = fieldsRef.current.get(name)!.options
const currOptions = fieldsRef.current.get(name)?.options
?.length as number;
const nextOptions = fields.get(name).options?.length as number;

Expand All @@ -898,7 +944,7 @@ export default <V extends FormValues = FormValues>({
let values = defaultValuesRef.current;
const addedNodes: string[] = [];

Array.from(fields.keys()).forEach((name) => {
fields.forEach((_, name) => {
if (fieldsRef.current.has(name) || controlsRef.current[name]) return;

const value = get(stateRef.current.values, name);
Expand Down Expand Up @@ -977,6 +1023,7 @@ export default <V extends FormValues = FormValues>({
setValue,
setTouched,
setDirty,
setFocus,
setError,
clearErrors,
runValidation,
Expand Down Expand Up @@ -1009,6 +1056,7 @@ export default <V extends FormValues = FormValues>({
setValue,
setTouched,
setDirty,
setFocus,
setError,
clearErrors,
runValidation,
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { default as isRadioInput } from "./isRadioInput";
export { default as isRangeInput } from "./isRangeInput";
export { default as isSelectMultiple } from "./isSelectMultiple";
export { default as isSelectOne } from "./isSelectOne";
export { default as isString } from "./isString";
export { default as isUndefined } from "./isUndefined";
export { default as parseState } from "./parseState";
export { default as runWithLowPriority } from "./runWithLowPriority";
Expand Down

0 comments on commit 5539448

Please sign in to comment.