Skip to content

Commit 188cfe4

Browse files
authored
Introduce useFormContext and FormProvider (#18)
* enhance form utility types and components - Add new methods to useFormReturn - Expand validation options in registerOptions: pattern, etc. - Add useFormContext and FormProvider * change log * clean up
1 parent 80370eb commit 188cfe4

File tree

7 files changed

+702
-31
lines changed

7 files changed

+702
-31
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
- Add `dirtyFields` field to `formState`
44
- Add `valueAsNumber` field to the option argument of `register`
5+
- Add new methods to useFormReturn: `clearErrors`, `resetField`, `setError`, `setFocus`, `trigger`, `unregister`
6+
- Expand validation options in `register`: `maxLength`, `minLength`, `max`, `min`, `pattern`
7+
- Add `useFormContext` hook and `FormProvider` module
58

69
# v0.0.8
710

doc/transformation.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type fieldDirtyOfInputs = {
4646
}
4747
4848
type rec useFormReturnOfInputs<'setValueAs> = {
49+
clearErrors: variantOfInputs => unit
4950
control: controlOfInputs,
5051
register: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => JsxDOM.domProps,
5152
handleSubmit: (inputs => unit) => JsxEvent.Form.t => unit,
@@ -54,11 +55,25 @@ type rec useFormReturnOfInputs<'setValueAs> = {
5455
formState: formStateOfInputs,
5556
getFieldState: (variantOfInputs, formStateOfInputs) => fieldStateOfInputs,
5657
setValue: (variantOfInputs, ReactHookForm.value, ~options: setValueConfigOfInputs=?) => unit,
57-
reset: (~options:defaultValues=?) => unit
58-
}
58+
reset: (~options:defaultValues=?) => unit,
59+
resetField: (variantOfInputs, ~options: defaultValues=?) => unit,
60+
setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit,
61+
setFocus: variantOfInputs => unit,
62+
trigger: variantOfInputs => unit,
63+
unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit,
64+
}
5965
and controlOfInputs
6066
and variantOfInputs = | @as("example") Example | @as("exampleRequired") ExampleRequired | @as("cart") Cart
61-
and registerOptionsOfInputs<'setValueAs> = {required?: bool, setValueAs?: 'setValueAs, valueAsNumber?: bool}
67+
and registerOptionsOfInputs<'setValueAs> = {
68+
required?: bool,
69+
setValueAs?: 'setValueAs,
70+
valueAsNumber?: bool,
71+
maxLength?: int,
72+
minLength?: int,
73+
max?: float,
74+
min?: float,
75+
pattern?: RegExp.t
76+
}
6277
and formStateOfInputs = {
6378
isDirty: bool,
6479
isValid: bool,
@@ -80,12 +95,18 @@ and setValueConfigOfInputs = {
8095
shouldDirty: bool,
8196
shouldTouch: bool,
8297
}
98+
and setErrorConfigOfInputs = {
99+
shouldFocus?: bool
100+
}
83101
84102
@module("react-hook-form")
85103
external useFormOfInputs: (
86104
~options: useFormParamsOfInputs<'resolver>=?
87105
) => useFormReturnOfInputs<'setValueAs> = "useForm"
88106
107+
@module("react-hook-form")
108+
external useFormContextOfInputs: unit => useFormReturnOfInputs<'setValueAs> = "useFormContext"
109+
89110
module ControllerOfInputs = {
90111
type controllerRulesOfInputs = {required?: bool}
91112
type controllerFieldsOfInputs = {field: JsxDOM.domProps}
@@ -99,6 +120,12 @@ module ControllerOfInputs = {
99120
) => React.element = "Controller"
100121
}
101122
123+
module FormProviderOfInputs = {
124+
type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element}
125+
@module("react-hook-form")
126+
external make: props<'setValueAs> => React.element = "FormProvider"
127+
}
128+
102129
//useWatch
103130
type useWatchParamsOfInputs = {
104131
name: variantOfInputs,

src/ppx/signature.ml

Lines changed: 219 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,21 +218,39 @@ let map_type_decl
218218
Sig.type_ Recursive
219219
[
220220
(* type useFormReturnOfInputs<'setValueAs> = {
221+
clearErrors: variantOfInputs => unit,
221222
control: controlOfInputs,
222223
register: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => JsxDOM.domProps,
223224
handleSubmit: (inputs => unit) => JsxEvent.Form.t => unit,
224225
watch: variantOfInputs => valuesOfInputs,
225226
getValues: variantOfInputs => option<valuesOfInputs>,
226-
reset: (~options: defaultValuesOfInputs=?) => unit,
227227
formState: formStateOfInputs,
228-
} *)
228+
getFieldState: (variantOfInputs, formStateOfInputs) => fieldStateOfInputs,
229+
setValue: (variantOfInputs, ReactHookForm.value, ~options: setValueConfigOfInputs=?) => unit,
230+
reset: (~options: defaultValuesOfInputs=?) => unit,
231+
resetField: (variantOfInputs, ~options: defaultValuesOfInputs=?) => unit,
232+
setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit,
233+
setFocus: variantOfInputs => unit,
234+
trigger: variantOfInputs => unit,
235+
unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit,
236+
} *)
229237
Type.mk
230238
(mkloc ("useFormReturnOf" ^ capitalize record_name) ptype_loc)
231239
~params:[ (Typ.var "setValueAs", (NoVariance, NoInjectivity)) ]
232240
~priv:Public
233241
~kind:
234242
(Ptype_record
235243
[
244+
(* clearErrors: variantOfInputs => unit, *)
245+
Type.field ~mut:Immutable (mknoloc "clearErrors")
246+
(uncurried_core_type_arrow ~arity:1
247+
[
248+
Typ.arrow Nolabel
249+
(Typ.constr
250+
(lid @@ "variantOf" ^ capitalize record_name)
251+
[])
252+
(Typ.constr (lid "unit") []);
253+
]);
236254
(* control: controlOfInputs *)
237255
Type.field ~mut:Immutable (mknoloc "control")
238256
(Typ.constr
@@ -313,17 +331,6 @@ let map_type_decl
313331
[];
314332
]);
315333
]);
316-
(* reset: (~options: defaultValuesOfInputs=?) => unit, *)
317-
Type.field ~mut:Immutable (mknoloc "reset")
318-
(uncurried_core_type_arrow ~arity:1
319-
[
320-
Typ.arrow (Optional "options")
321-
(Typ.constr ~attrs:[ attr_named_arg ]
322-
(lid @@ "defaultValuesOf"
323-
^ capitalize record_name)
324-
[])
325-
(Typ.constr (lid "unit") []);
326-
]);
327334
(* formState: formStateOfInputs, *)
328335
Type.field ~mut:Immutable (mknoloc "formState")
329336
(Typ.constr
@@ -368,6 +375,87 @@ let map_type_decl
368375
[])
369376
(Typ.constr (lid "unit") [])));
370377
]);
378+
(* reset: (~options: defaultValuesOfInputs=?) => unit, *)
379+
Type.field ~mut:Immutable (mknoloc "reset")
380+
(uncurried_core_type_arrow ~arity:1
381+
[
382+
Typ.arrow (Optional "options")
383+
(Typ.constr ~attrs:[ attr_named_arg ]
384+
(lid @@ "defaultValuesOf"
385+
^ capitalize record_name)
386+
[])
387+
(Typ.constr (lid "unit") []);
388+
]);
389+
(* resetField: (variantOfInputs, ~options: defaultValuesOfInputs=?) => unit, *)
390+
Type.field ~mut:Immutable (mknoloc "resetField")
391+
(uncurried_core_type_arrow ~arity:2
392+
[
393+
Typ.arrow Nolabel
394+
(Typ.constr
395+
(lid @@ "variantOf" ^ capitalize record_name)
396+
[])
397+
(Typ.arrow (Optional "options")
398+
(Typ.constr ~attrs:[ attr_named_arg ]
399+
(lid @@ "defaultValuesOf"
400+
^ capitalize record_name)
401+
[])
402+
(Typ.constr (lid "unit") []));
403+
]);
404+
(* setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit, *)
405+
Type.field ~mut:Immutable (mknoloc "setError")
406+
(uncurried_core_type_arrow ~arity:3
407+
[
408+
Typ.arrow Nolabel
409+
(Typ.constr
410+
(lid @@ "variantOf" ^ capitalize record_name)
411+
[])
412+
(Typ.arrow Nolabel
413+
(Typ.constr
414+
(lid @@ "fieldErrorOf"
415+
^ capitalize record_name)
416+
[])
417+
(Typ.arrow (Optional "options")
418+
(Typ.constr
419+
(lid @@ "setErrorConfigOf"
420+
^ capitalize record_name)
421+
[])
422+
(Typ.constr (lid "unit") [])));
423+
]);
424+
(* setFocus: variantOfInputs => unit, *)
425+
Type.field ~mut:Immutable (mknoloc "setFocus")
426+
(uncurried_core_type_arrow ~arity:1
427+
[
428+
Typ.arrow Nolabel
429+
(Typ.constr
430+
(lid @@ "variantOf" ^ capitalize record_name)
431+
[])
432+
(Typ.constr (lid "unit") []);
433+
]);
434+
(* trigger: variantOfInputs => unit, *)
435+
Type.field ~mut:Immutable (mknoloc "trigger")
436+
(uncurried_core_type_arrow ~arity:1
437+
[
438+
Typ.arrow Nolabel
439+
(Typ.constr
440+
(lid @@ "variantOf" ^ capitalize record_name)
441+
[])
442+
(Typ.constr (lid "unit") []);
443+
]);
444+
(* unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit, *)
445+
Type.field ~mut:Immutable (mknoloc "unregister")
446+
(uncurried_core_type_arrow ~arity:2
447+
[
448+
Typ.arrow Nolabel
449+
(Typ.constr
450+
(lid @@ "variantOf" ^ capitalize record_name)
451+
[])
452+
(Typ.arrow (Optional "options")
453+
(Typ.constr ~attrs:[ attr_named_arg ]
454+
(lid @@ "registerOptionsOf"
455+
^ capitalize record_name)
456+
[ Typ.var "setValueAs" ])
457+
(Typ.constr (lid "unit") []));
458+
]);
371459
]);
372460
(* type controlOfInputs *)
373461
Type.mk
@@ -378,7 +466,16 @@ let map_type_decl
378466
(mkloc ("variantOf" ^ capitalize record_name) ptype_loc)
379467
~priv:Public
380468
~kind:(Ptype_variant (make_const_decls fields ptype_loc));
381-
(* type registerOptionsOfInputs<'setValueAs> = {required?: bool, setValueAs?: 'setValueAs, valueAsNumber?: bool} *)
469+
(* type registerOptionsOfInputs<'setValueAs> = {
470+
required?: bool,
471+
setValueAs?: 'setValueAs,
472+
valueAsNumber?: bool,
473+
maxLength?: int,
474+
minLength?: int,
475+
max?: float,
476+
min?: float,
477+
pattern?: RegExp.t
478+
} *)
382479
Type.mk
383480
(mkloc ("registerOptionsOf" ^ capitalize record_name) ptype_loc)
384481
~params:[ (Typ.var "setValueAs", (NoVariance, NoInjectivity)) ]
@@ -394,6 +491,21 @@ let map_type_decl
394491
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
395492
(mknoloc "valueAsNumber")
396493
(Typ.constr (lid "bool") []);
494+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
495+
(mknoloc "maxLength")
496+
(Typ.constr (lid "int") []);
497+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
498+
(mknoloc "minLength")
499+
(Typ.constr (lid "int") []);
500+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
501+
(mknoloc "max")
502+
(Typ.constr (lid "float") []);
503+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
504+
(mknoloc "min")
505+
(Typ.constr (lid "float") []);
506+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
507+
(mknoloc "pattern")
508+
(Typ.constr (lid "RegExp.t") []);
397509
]);
398510
(* type formStateOfInputs = {
399511
isDirty: bool,
@@ -512,6 +624,16 @@ let map_type_decl
512624
(mknoloc "shouldTouch")
513625
(Typ.constr (lid "bool") []);
514626
]);
627+
Type.mk
628+
(mkloc ("setErrorConfigOf" ^ capitalize record_name) ptype_loc)
629+
~priv:Public
630+
~kind:
631+
(Ptype_record
632+
[
633+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
634+
(mknoloc "shouldFocus")
635+
(Typ.constr (lid "bool") []);
636+
]);
515637
]
516638
in
517639

@@ -542,6 +664,31 @@ let map_type_decl
542664
[ Typ.var "setValueAs" ]);
543665
]))
544666
in
667+
(* @module("react-hook-form")
668+
external useFormContextOfInputs: unit => useFormReturnOfInputs<'setValueAs> = "useFormContext" *)
669+
let primitive_use_form_context =
670+
Sig.value
671+
(Val.mk
672+
~attrs:
673+
[
674+
Attr.mk (mknoloc "module")
675+
(PStr
676+
[
677+
Str.eval
678+
@@ Exp.constant (Const.string "react-hook-form");
679+
]);
680+
]
681+
~prim:[ "useFormContext" ]
682+
(mknoloc @@ "useFormContextOf" ^ capitalize record_name)
683+
(uncurried_core_type_arrow ~arity:0
684+
[
685+
Typ.arrow Nolabel
686+
(Typ.constr (lid "unit") [])
687+
(Typ.constr
688+
(lid @@ "useFormReturnOf" ^ capitalize record_name)
689+
[ Typ.var "setValueAs" ]);
690+
]))
691+
in
545692
(* module ControllerOfInputs = {
546693
type controllerRulesOfInputs = {required?: bool}
547694
type controllerFieldsOfInputs = {field: JsxDOM.domProps}
@@ -657,6 +804,62 @@ let map_type_decl
657804
]))
658805
in
659806

807+
(* module FormProviderOfInputs = {
808+
type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element}
809+
@module("react-hook-form")
810+
external make: props<'setValueAs> => React.element = "FormProvider"
811+
} *)
812+
let module_form_provider =
813+
Sig.module_
814+
(Md.mk
815+
(mknoloc @@ Some ("FormProviderOf" ^ capitalize record_name))
816+
(Mty.signature
817+
[
818+
Sig.type_ Recursive
819+
[
820+
(* type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element} *)
821+
Type.mk (mkloc "props" ptype_loc) ~priv:Public
822+
~params:
823+
[
824+
(Typ.var "setValueAs", (NoVariance, NoInjectivity));
825+
]
826+
~kind:
827+
(Ptype_record
828+
[
829+
Type.field ~mut:Immutable (mknoloc "...")
830+
(Typ.constr
831+
(lid @@ "useFormReturnOf"
832+
^ capitalize record_name)
833+
[ Typ.var "setValueAs" ]);
834+
Type.field ~mut:Immutable (mknoloc "children")
835+
(Typ.constr (lid "React.element") []);
836+
]);
837+
];
838+
(* @module("react-hook-form")
839+
external make: props<'setValueAs> => React.element = "FormProvider" *)
840+
Sig.value
841+
(Val.mk
842+
~attrs:
843+
[
844+
Attr.mk (mknoloc "module")
845+
(PStr
846+
[
847+
Str.eval
848+
@@ Exp.constant
849+
(Const.string "react-hook-form");
850+
]);
851+
]
852+
~prim:[ "FormProvider" ] (mknoloc "make")
853+
(uncurried_core_type_arrow ~arity:1
854+
[
855+
Typ.arrow Nolabel
856+
(Typ.constr (lid "props")
857+
[ Typ.var "setValueAs" ])
858+
(Typ.constr (lid "React.element") []);
859+
]));
860+
]))
861+
in
862+
660863
(* type useWatchParamsOfInputs = {
661864
name: variantOfInputs,
662865
control: controlOfInputs=?,
@@ -928,7 +1131,9 @@ let map_type_decl
9281131
type_decls3;
9291132
type_decls4;
9301133
primitive_use_form;
1134+
primitive_use_form_context;
9311135
module_controller;
1136+
module_form_provider;
9321137
type_decls5;
9331138
primitive_use_watch;
9341139
]

0 commit comments

Comments
 (0)