diff --git a/CHANGELOG.md b/CHANGELOG.md index dacc621..fada5a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ - Add `dirtyFields` field to `formState` - Add `valueAsNumber` field to the option argument of `register` +- Add new methods to useFormReturn: `clearErrors`, `resetField`, `setError`, `setFocus`, `trigger`, `unregister` +- Expand validation options in `register`: `maxLength`, `minLength`, `max`, `min`, `pattern` +- Add `useFormContext` hook and `FormProvider` module # v0.0.8 diff --git a/doc/transformation.md b/doc/transformation.md index cb76a23..25d79a9 100644 --- a/doc/transformation.md +++ b/doc/transformation.md @@ -46,6 +46,7 @@ type fieldDirtyOfInputs = { } type rec useFormReturnOfInputs<'setValueAs> = { + clearErrors: variantOfInputs => unit control: controlOfInputs, register: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => JsxDOM.domProps, handleSubmit: (inputs => unit) => JsxEvent.Form.t => unit, @@ -54,11 +55,25 @@ type rec useFormReturnOfInputs<'setValueAs> = { formState: formStateOfInputs, getFieldState: (variantOfInputs, formStateOfInputs) => fieldStateOfInputs, setValue: (variantOfInputs, ReactHookForm.value, ~options: setValueConfigOfInputs=?) => unit, - reset: (~options:defaultValues=?) => unit -} + reset: (~options:defaultValues=?) => unit, + resetField: (variantOfInputs, ~options: defaultValues=?) => unit, + setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit, + setFocus: variantOfInputs => unit, + trigger: variantOfInputs => unit, + unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit, +} and controlOfInputs and variantOfInputs = | @as("example") Example | @as("exampleRequired") ExampleRequired | @as("cart") Cart -and registerOptionsOfInputs<'setValueAs> = {required?: bool, setValueAs?: 'setValueAs, valueAsNumber?: bool} +and registerOptionsOfInputs<'setValueAs> = { + required?: bool, + setValueAs?: 'setValueAs, + valueAsNumber?: bool, + maxLength?: int, + minLength?: int, + max?: float, + min?: float, + pattern?: RegExp.t +} and formStateOfInputs = { isDirty: bool, isValid: bool, @@ -80,12 +95,18 @@ and setValueConfigOfInputs = { shouldDirty: bool, shouldTouch: bool, } +and setErrorConfigOfInputs = { + shouldFocus?: bool +} @module("react-hook-form") external useFormOfInputs: ( ~options: useFormParamsOfInputs<'resolver>=? ) => useFormReturnOfInputs<'setValueAs> = "useForm" +@module("react-hook-form") +external useFormContextOfInputs: unit => useFormReturnOfInputs<'setValueAs> = "useFormContext" + module ControllerOfInputs = { type controllerRulesOfInputs = {required?: bool} type controllerFieldsOfInputs = {field: JsxDOM.domProps} @@ -99,6 +120,12 @@ module ControllerOfInputs = { ) => React.element = "Controller" } +module FormProviderOfInputs = { + type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element} + @module("react-hook-form") + external make: props<'setValueAs> => React.element = "FormProvider" +} + //useWatch type useWatchParamsOfInputs = { name: variantOfInputs, diff --git a/src/ppx/signature.ml b/src/ppx/signature.ml index 6551a9d..870a75a 100644 --- a/src/ppx/signature.ml +++ b/src/ppx/signature.ml @@ -218,14 +218,22 @@ let map_type_decl Sig.type_ Recursive [ (* type useFormReturnOfInputs<'setValueAs> = { + clearErrors: variantOfInputs => unit, control: controlOfInputs, register: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => JsxDOM.domProps, handleSubmit: (inputs => unit) => JsxEvent.Form.t => unit, watch: variantOfInputs => valuesOfInputs, getValues: variantOfInputs => option, - reset: (~options: defaultValuesOfInputs=?) => unit, formState: formStateOfInputs, - } *) + getFieldState: (variantOfInputs, formStateOfInputs) => fieldStateOfInputs, + setValue: (variantOfInputs, ReactHookForm.value, ~options: setValueConfigOfInputs=?) => unit, + reset: (~options: defaultValuesOfInputs=?) => unit, + resetField: (variantOfInputs, ~options: defaultValuesOfInputs=?) => unit, + setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit, + setFocus: variantOfInputs => unit, + trigger: variantOfInputs => unit, + unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit, + } *) Type.mk (mkloc ("useFormReturnOf" ^ capitalize record_name) ptype_loc) ~params:[ (Typ.var "setValueAs", (NoVariance, NoInjectivity)) ] @@ -233,6 +241,16 @@ let map_type_decl ~kind: (Ptype_record [ + (* clearErrors: variantOfInputs => unit, *) + Type.field ~mut:Immutable (mknoloc "clearErrors") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); (* control: controlOfInputs *) Type.field ~mut:Immutable (mknoloc "control") (Typ.constr @@ -313,17 +331,6 @@ let map_type_decl []; ]); ]); - (* reset: (~options: defaultValuesOfInputs=?) => unit, *) - Type.field ~mut:Immutable (mknoloc "reset") - (uncurried_core_type_arrow ~arity:1 - [ - Typ.arrow (Optional "options") - (Typ.constr ~attrs:[ attr_named_arg ] - (lid @@ "defaultValuesOf" - ^ capitalize record_name) - []) - (Typ.constr (lid "unit") []); - ]); (* formState: formStateOfInputs, *) Type.field ~mut:Immutable (mknoloc "formState") (Typ.constr @@ -368,6 +375,87 @@ let map_type_decl []) (Typ.constr (lid "unit") []))); ]); + (* reset: (~options: defaultValuesOfInputs=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "reset") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow (Optional "options") + (Typ.constr ~attrs:[ attr_named_arg ] + (lid @@ "defaultValuesOf" + ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); + (* resetField: (variantOfInputs, ~options: defaultValuesOfInputs=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "resetField") + (uncurried_core_type_arrow ~arity:2 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.arrow (Optional "options") + (Typ.constr ~attrs:[ attr_named_arg ] + (lid @@ "defaultValuesOf" + ^ capitalize record_name) + []) + (Typ.constr (lid "unit") [])); + ]); + (* setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "setError") + (uncurried_core_type_arrow ~arity:3 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.arrow Nolabel + (Typ.constr + (lid @@ "fieldErrorOf" + ^ capitalize record_name) + []) + (Typ.arrow (Optional "options") + (Typ.constr + (lid @@ "setErrorConfigOf" + ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []))); + ]); + (* setFocus: variantOfInputs => unit, *) + Type.field ~mut:Immutable (mknoloc "setFocus") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); + (* trigger: variantOfInputs => unit, *) + Type.field ~mut:Immutable (mknoloc "trigger") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); + (* unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "unregister") + (uncurried_core_type_arrow ~arity:2 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.arrow (Optional "options") + (Typ.constr ~attrs:[ attr_named_arg ] + (lid @@ "registerOptionsOf" + ^ capitalize record_name) + [ Typ.var "setValueAs" ]) + (Typ.constr (lid "unit") [])); + ]); ]); (* type controlOfInputs *) Type.mk @@ -378,7 +466,16 @@ let map_type_decl (mkloc ("variantOf" ^ capitalize record_name) ptype_loc) ~priv:Public ~kind:(Ptype_variant (make_const_decls fields ptype_loc)); - (* type registerOptionsOfInputs<'setValueAs> = {required?: bool, setValueAs?: 'setValueAs, valueAsNumber?: bool} *) + (* type registerOptionsOfInputs<'setValueAs> = { + required?: bool, + setValueAs?: 'setValueAs, + valueAsNumber?: bool, + maxLength?: int, + minLength?: int, + max?: float, + min?: float, + pattern?: RegExp.t + } *) Type.mk (mkloc ("registerOptionsOf" ^ capitalize record_name) ptype_loc) ~params:[ (Typ.var "setValueAs", (NoVariance, NoInjectivity)) ] @@ -394,6 +491,21 @@ let map_type_decl Type.field ~attrs:[ attr_optional ] ~mut:Immutable (mknoloc "valueAsNumber") (Typ.constr (lid "bool") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "maxLength") + (Typ.constr (lid "int") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "minLength") + (Typ.constr (lid "int") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "max") + (Typ.constr (lid "float") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "min") + (Typ.constr (lid "float") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "pattern") + (Typ.constr (lid "RegExp.t") []); ]); (* type formStateOfInputs = { isDirty: bool, @@ -512,6 +624,16 @@ let map_type_decl (mknoloc "shouldTouch") (Typ.constr (lid "bool") []); ]); + Type.mk + (mkloc ("setErrorConfigOf" ^ capitalize record_name) ptype_loc) + ~priv:Public + ~kind: + (Ptype_record + [ + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "shouldFocus") + (Typ.constr (lid "bool") []); + ]); ] in @@ -542,6 +664,31 @@ let map_type_decl [ Typ.var "setValueAs" ]); ])) in + (* @module("react-hook-form") + external useFormContextOfInputs: unit => useFormReturnOfInputs<'setValueAs> = "useFormContext" *) + let primitive_use_form_context = + Sig.value + (Val.mk + ~attrs: + [ + Attr.mk (mknoloc "module") + (PStr + [ + Str.eval + @@ Exp.constant (Const.string "react-hook-form"); + ]); + ] + ~prim:[ "useFormContext" ] + (mknoloc @@ "useFormContextOf" ^ capitalize record_name) + (uncurried_core_type_arrow ~arity:0 + [ + Typ.arrow Nolabel + (Typ.constr (lid "unit") []) + (Typ.constr + (lid @@ "useFormReturnOf" ^ capitalize record_name) + [ Typ.var "setValueAs" ]); + ])) + in (* module ControllerOfInputs = { type controllerRulesOfInputs = {required?: bool} type controllerFieldsOfInputs = {field: JsxDOM.domProps} @@ -657,6 +804,62 @@ let map_type_decl ])) in + (* module FormProviderOfInputs = { + type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element} + @module("react-hook-form") + external make: props<'setValueAs> => React.element = "FormProvider" + } *) + let module_form_provider = + Sig.module_ + (Md.mk + (mknoloc @@ Some ("FormProviderOf" ^ capitalize record_name)) + (Mty.signature + [ + Sig.type_ Recursive + [ + (* type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element} *) + Type.mk (mkloc "props" ptype_loc) ~priv:Public + ~params: + [ + (Typ.var "setValueAs", (NoVariance, NoInjectivity)); + ] + ~kind: + (Ptype_record + [ + Type.field ~mut:Immutable (mknoloc "...") + (Typ.constr + (lid @@ "useFormReturnOf" + ^ capitalize record_name) + [ Typ.var "setValueAs" ]); + Type.field ~mut:Immutable (mknoloc "children") + (Typ.constr (lid "React.element") []); + ]); + ]; + (* @module("react-hook-form") + external make: props<'setValueAs> => React.element = "FormProvider" *) + Sig.value + (Val.mk + ~attrs: + [ + Attr.mk (mknoloc "module") + (PStr + [ + Str.eval + @@ Exp.constant + (Const.string "react-hook-form"); + ]); + ] + ~prim:[ "FormProvider" ] (mknoloc "make") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr (lid "props") + [ Typ.var "setValueAs" ]) + (Typ.constr (lid "React.element") []); + ])); + ])) + in + (* type useWatchParamsOfInputs = { name: variantOfInputs, control: controlOfInputs=?, @@ -928,7 +1131,9 @@ let map_type_decl type_decls3; type_decls4; primitive_use_form; + primitive_use_form_context; module_controller; + module_form_provider; type_decls5; primitive_use_watch; ] diff --git a/src/ppx/structure.ml b/src/ppx/structure.ml index 4ba5617..f388362 100644 --- a/src/ppx/structure.ml +++ b/src/ppx/structure.ml @@ -217,14 +217,22 @@ let map_type_decl Str.type_ Recursive [ (* type useFormReturnOfInputs<'setValueAs> = { + clearErrors: variantOfInputs => unit, control: controlOfInputs, register: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => JsxDOM.domProps, handleSubmit: (inputs => unit) => JsxEvent.Form.t => unit, watch: variantOfInputs => valuesOfInputs, getValues: variantOfInputs => option, - reset: (~options: defaultValuesOfInputs=?) => unit, formState: formStateOfInputs, - } *) + getFieldState: (variantOfInputs, formStateOfInputs) => fieldStateOfInputs, + setValue: (variantOfInputs, ReactHookForm.value, ~options: setValueConfigOfInputs=?) => unit, + reset: (~options: defaultValuesOfInputs=?) => unit, + resetField: (variantOfInputs, ~options: resetFieldConfigOfInputs=?) => unit, + setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit, + setFocus: variantOfInputs => unit, + trigger: variantOfInputs => unit, + unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit, + } *) Type.mk (mkloc ("useFormReturnOf" ^ capitalize record_name) ptype_loc) ~params:[ (Typ.var "setValueAs", (NoVariance, NoInjectivity)) ] @@ -232,6 +240,16 @@ let map_type_decl ~kind: (Ptype_record [ + (* clearErrors: variantOfInputs => unit, *) + Type.field ~mut:Immutable (mknoloc "clearErrors") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); (* control: controlOfInputs *) Type.field ~mut:Immutable (mknoloc "control") (Typ.constr @@ -312,17 +330,6 @@ let map_type_decl []; ]); ]); - (* reset: (~options: defaultValuesOfInputs=?) => unit, *) - Type.field ~mut:Immutable (mknoloc "reset") - (uncurried_core_type_arrow ~arity:1 - [ - Typ.arrow (Optional "options") - (Typ.constr ~attrs:[ attr_named_arg ] - (lid @@ "defaultValuesOf" - ^ capitalize record_name) - []) - (Typ.constr (lid "unit") []); - ]); (* formState: formStateOfInputs, *) Type.field ~mut:Immutable (mknoloc "formState") (Typ.constr @@ -367,6 +374,87 @@ let map_type_decl []) (Typ.constr (lid "unit") []))); ]); + (* reset: (~options: defaultValuesOfInputs=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "reset") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow (Optional "options") + (Typ.constr ~attrs:[ attr_named_arg ] + (lid @@ "defaultValuesOf" + ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); + (* resetField: (variantOfInputs, ~options: defaultValuesOfInputs=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "resetField") + (uncurried_core_type_arrow ~arity:2 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.arrow (Optional "options") + (Typ.constr ~attrs:[ attr_named_arg ] + (lid @@ "defaultValuesOf" + ^ capitalize record_name) + []) + (Typ.constr (lid "unit") [])); + ]); + (* setError: (variantOfInputs, fieldErrorOfInputs, ~options: setErrorConfigOfInputs=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "setError") + (uncurried_core_type_arrow ~arity:3 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.arrow Nolabel + (Typ.constr + (lid @@ "fieldErrorOf" + ^ capitalize record_name) + []) + (Typ.arrow (Optional "options") + (Typ.constr + (lid @@ "setErrorConfigOf" + ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []))); + ]); + (* setFocus: variantOfInputs => unit, *) + Type.field ~mut:Immutable (mknoloc "setFocus") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); + (* trigger: variantOfInputs => unit, *) + Type.field ~mut:Immutable (mknoloc "trigger") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.constr (lid "unit") []); + ]); + (* unregister: (variantOfInputs, ~options: registerOptionsOfInputs<'setValueAs>=?) => unit, *) + Type.field ~mut:Immutable (mknoloc "unregister") + (uncurried_core_type_arrow ~arity:2 + [ + Typ.arrow Nolabel + (Typ.constr + (lid @@ "variantOf" ^ capitalize record_name) + []) + (Typ.arrow (Optional "options") + (Typ.constr ~attrs:[ attr_named_arg ] + (lid @@ "registerOptionsOf" + ^ capitalize record_name) + [ Typ.var "setValueAs" ]) + (Typ.constr (lid "unit") [])); + ]); ]); (* type controlOfInputs *) Type.mk @@ -377,7 +465,16 @@ let map_type_decl (mkloc ("variantOf" ^ capitalize record_name) ptype_loc) ~priv:Public ~kind:(Ptype_variant (make_const_decls fields ptype_loc)); - (* type registerOptionsOfInputs<'setValueAs> = {required?: bool, setValueAs?: 'setValueAs, valueAsNumber?: bool} *) + (* type registerOptionsOfInputs<'setValueAs> = { + required?: bool, + setValueAs?: 'setValueAs, + valueAsNumber?: bool, + maxLength?: int, + minLength?: int, + max?: float, + min?: float, + pattern?: RegExp.t + } *) Type.mk (mkloc ("registerOptionsOf" ^ capitalize record_name) ptype_loc) ~params:[ (Typ.var "setValueAs", (NoVariance, NoInjectivity)) ] @@ -393,6 +490,21 @@ let map_type_decl Type.field ~attrs:[ attr_optional ] ~mut:Immutable (mknoloc "valueAsNumber") (Typ.constr (lid "bool") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "maxLength") + (Typ.constr (lid "int") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "minLength") + (Typ.constr (lid "int") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "max") + (Typ.constr (lid "float") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "min") + (Typ.constr (lid "float") []); + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "pattern") + (Typ.constr (lid "RegExp.t") []); ]); (* type formStateOfInputs = { isDirty: bool, @@ -511,6 +623,16 @@ let map_type_decl (mknoloc "shouldTouch") (Typ.constr (lid "bool") []); ]); + Type.mk + (mkloc ("setErrorConfigOf" ^ capitalize record_name) ptype_loc) + ~priv:Public + ~kind: + (Ptype_record + [ + Type.field ~attrs:[ attr_optional ] ~mut:Immutable + (mknoloc "shouldFocus") + (Typ.constr (lid "bool") []); + ]); ] in @@ -541,6 +663,31 @@ let map_type_decl [ Typ.var "setValueAs" ]); ])) in + (* @module("react-hook-form") + external useFormContextOfInputs: unit => useFormReturnOfInputs<'setValueAs> = "useFormContext" *) + let primitive_use_form_context = + Str.primitive + (Val.mk + ~attrs: + [ + Attr.mk (mknoloc "module") + (PStr + [ + Str.eval + @@ Exp.constant (Const.string "react-hook-form"); + ]); + ] + ~prim:[ "useFormContext" ] + (mknoloc @@ "useFormContextOf" ^ capitalize record_name) + (uncurried_core_type_arrow ~arity:0 + [ + Typ.arrow Nolabel + (Typ.constr (lid "unit") []) + (Typ.constr + (lid @@ "useFormReturnOf" ^ capitalize record_name) + [ Typ.var "setValueAs" ]); + ])) + in (* module ControllerOfInputs = { type controllerRulesOfInputs = {required?: bool} type controllerFieldsOfInputs = {field: JsxDOM.domProps} @@ -656,6 +803,62 @@ let map_type_decl ])) in + (* module FormProviderOfInputs = { + type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element} + @module("react-hook-form") + external make: props<'setValueAs> => React.element = "FormProvider" + } *) + let module_form_provider = + Str.module_ + (Mb.mk + (mknoloc @@ Some ("FormProviderOf" ^ capitalize record_name)) + (Mod.structure + [ + Str.type_ Recursive + [ + (* type props<'setValueAs> = {...useFormReturnOfInputs<'setValueAs>, children: React.element} *) + Type.mk (mkloc "props" ptype_loc) ~priv:Public + ~params: + [ + (Typ.var "setValueAs", (NoVariance, NoInjectivity)); + ] + ~kind: + (Ptype_record + [ + Type.field ~mut:Immutable (mknoloc "...") + (Typ.constr + (lid @@ "useFormReturnOf" + ^ capitalize record_name) + [ Typ.var "setValueAs" ]); + Type.field ~mut:Immutable (mknoloc "children") + (Typ.constr (lid "React.element") []); + ]); + ]; + (* @module("react-hook-form") + external make: props<'setValueAs> => React.element = "FormProvider" *) + Str.primitive + (Val.mk + ~attrs: + [ + Attr.mk (mknoloc "module") + (PStr + [ + Str.eval + @@ Exp.constant + (Const.string "react-hook-form"); + ]); + ] + ~prim:[ "FormProvider" ] (mknoloc "make") + (uncurried_core_type_arrow ~arity:1 + [ + Typ.arrow Nolabel + (Typ.constr (lid "props") + [ Typ.var "setValueAs" ]) + (Typ.constr (lid "React.element") []); + ])); + ])) + in + (* type useWatchParamsOfInputs = { name: variantOfInputs, control: controlOfInputs=?, @@ -1116,7 +1319,9 @@ let map_type_decl type_decls3; type_decls4; primitive_use_form; + primitive_use_form_context; module_controller; + module_form_provider; type_decls5; primitive_use_watch; ] diff --git a/test/src/pages/form_context/FormContext.tsx b/test/src/pages/form_context/FormContext.tsx new file mode 100644 index 0000000..feae021 --- /dev/null +++ b/test/src/pages/form_context/FormContext.tsx @@ -0,0 +1,98 @@ +import { useForm, FormProvider, useFormContext, SubmitHandler } from 'react-hook-form'; + +interface FormInputs { + firstName: string; + lastName: string; + email: string; + age: number; +} + +const FormContextExample = () => { + const methods = useForm({ + defaultValues: { + firstName: '', + lastName: '', + email: '', + age: 0 + } + }); + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + alert(JSON.stringify(data, null, 2)); + }; + + return ( + +
+

Profile Information

+ + + + +
+ ); +}; + +const PersonalInfo = () => { + const { register, formState: { errors } } = useFormContext(); + + return ( +
+

Personal Information

+
+ + + {errors.firstName &&

Please enter your first name

} +
+ +
+ + + {errors.lastName &&

Please enter your last name

} +
+ +
+ + + {errors.age &&

Please enter your age, it must be greater than 0

} +
+
+ ); +}; + +const ContactInfo = () => { + const { register, formState: { errors } } = useFormContext(); + + return ( +
+

Contact Information

+
+ + + {errors.email &&

Please enter your email

} +
+
+ ); +}; + +export default FormContextExample; diff --git a/test/src/pages/form_context_res/FormContext.res b/test/src/pages/form_context_res/FormContext.res new file mode 100644 index 0000000..5bffeb9 --- /dev/null +++ b/test/src/pages/form_context_res/FormContext.res @@ -0,0 +1,122 @@ +@rhf +type inputs = { + firstName: string, + lastName: string, + email: string, + age: float, +} + +module PersonalInfo = { + @react.component + let make = () => { + let {register, formState: {errors}} = useFormContextOfInputs() + +
+

{"Personal Information"->React.string}

+
+ + + {switch errors.firstName { + | Some(_) =>

{"Please enter your first name"->React.string}

+ | _ => React.null + }} +
+
+ + + {switch errors.lastName { + | Some(_) =>

{"Please enter your last name"->React.string}

+ | _ => React.null + }} +
+
+ + + {switch errors.age { + | Some(_) =>

{"Please enter your age, it must be greater than 0"->React.string}

+ | _ => React.null + }} +
+
+ } +} + +// 연락처 정보 입력 컴포넌트 +module ContactInfo = { + @react.component + let make = () => { + let {register, formState: {errors}} = useFormContextOfInputs() + +
+

{"Contact Information"->React.string}

+
+ + + {switch errors.email { + | Some(_) =>

{"Please enter your email"->React.string}

+ | _ => React.null + }} +
+
+ } +} + +@react.component @genType +let default = () => { + let methods = useFormOfInputs( + ~options={ + defaultValues: { + firstName: "", + lastName: "", + email: "", + age: 0., + }, + }, + ) + + let onSubmit = (data: inputs) => Js.log(data) + + +
+

{"Profile Information"->React.string}

+ + + + +
+} diff --git a/test/src/router/index.tsx b/test/src/router/index.tsx index 3c095a2..215ba1e 100644 --- a/test/src/router/index.tsx +++ b/test/src/router/index.tsx @@ -12,6 +12,9 @@ import FieldArray from "../pages/field_array/FieldArray"; import FieldArrayRes from "../pages/field_array_res/FieldArray.gen"; import UseWatch from "../pages/use_watch/UseWatch"; import UseWatchRes from "../pages/use_watch_res/UseWatch.gen"; +import FormContext from "../pages/form_context/FormContext"; +import FormContextRes from "../pages/form_context_res/FormContext.gen"; + const router = createBrowserRouter([ { path: "/", @@ -57,6 +60,14 @@ const router = createBrowserRouter([ path: "/use_watch_res", element: }, + { + path: "/form_context", + element: + }, + { + path: "/form_context_res", + element: + } ]) export default router \ No newline at end of file