Created
July 28, 2020 13:55
-
-
Save fakenickels/600b60c1cae159e6abdd3d980fe048b2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// FormMaker experiment | |
module type Config = { | |
type field('a); | |
type state; | |
let set: (state, field('a), 'a) => state; | |
let get: (state, field('a)) => 'a; | |
}; | |
module Make = (Config: Config) => { | |
module Form = BsReform.ReForm.Make(Config); | |
module GeneratorTypes = { | |
type field('inputType) = { | |
validator: Form.Validation.t, | |
field: Form.field, | |
inputType: 'inputType, | |
label: string, | |
}; | |
let field = (~validator, ~inputType, ~label, field) => { | |
inputType, | |
label, | |
field: Field(field), | |
validator, | |
}; | |
}; | |
type fieldInterface('value) = { | |
handleChange: 'value => unit, | |
error: option(string), | |
state: BsReform.ReForm.fieldState, | |
validate: unit => unit, | |
value: 'value, | |
}; | |
let useField = (field: Form.field) => { | |
let interface = Form.useFormContext(); | |
interface->Belt.Option.map( | |
({handleChange, getFieldError, getFieldState, validateField, state}) => { | |
let unpack: type a. Form.field => fieldInterface(a) = | |
field => { | |
switch (field) { | |
| Form.ReSchema.Field(field) => | |
// im dumb | |
let fieldUnpacked = Obj.magic(field); | |
{ | |
handleChange: handleChange(fieldUnpacked), | |
error: getFieldError(Field(field)), | |
state: getFieldState(Field(field)), | |
validate: () => validateField(Field(field)), | |
value: state.values->Config.get(fieldUnpacked), | |
}; | |
}; | |
}; | |
unpack(field); | |
}); | |
}; | |
module Field = { | |
[@react.component] | |
let make = | |
( | |
~field: Form.field, | |
~render: fieldInterface('a) => React.element, | |
~renderOnMissingContext=React.null, | |
(), | |
) => { | |
let fieldInterface = useField(field); | |
React.useMemo3( | |
() => | |
fieldInterface | |
->Belt.Option.map(render) | |
->Belt.Option.getWithDefault(renderOnMissingContext), | |
( | |
Belt.Option.( | |
fieldInterface->flatMap(({error}) => error)->getWithDefault("") | |
), | |
Belt.Option.(fieldInterface->map(({value}) => value)), | |
Belt.Option.(fieldInterface->map(({state}) => state)), | |
), | |
); | |
}; | |
}; | |
module type GeneratorConfig = { | |
type inputType; | |
let renderer: | |
( | |
~props: fieldInterface('value), | |
~spec: GeneratorTypes.field(inputType) | |
) => | |
'a; | |
module Wrapper: { | |
let makeProps: | |
(~key: string=?, ~reform: Form.api, ~children: React.element, unit) => | |
{. "reform": 'a}; | |
let make: 'props => React.element; | |
}; | |
}; | |
module Make = (Config: GeneratorConfig) => { | |
type field = GeneratorTypes.field(Config.inputType); | |
type fields = array(field); | |
module Wrapper = Config.Wrapper; | |
[@react.component] | |
let make = (~fields: fields, ~initialState, ~onSubmit) => { | |
let schema = | |
Form.Validation.Schema( | |
fields->Belt.Array.map(({validator}) => validator), | |
); | |
let reform = Form.use(~initialState, ~schema, ~onSubmit, ()); | |
<Form.Provider value=reform> | |
<Wrapper reform> | |
{fields | |
->Belt.Array.map(spec => { | |
<Field | |
field={spec.field} | |
render={props => {Config.renderer(~props, ~spec)}} | |
/> | |
}) | |
->React.array} | |
</Wrapper> | |
</Form.Provider>; | |
}; | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment