iway1 / react-ts-form

https://react-ts-form.com
MIT License
2.01k stars 35 forks source link

Container around multiple sections of your form #54

Closed mulyoved closed 1 year ago

mulyoved commented 1 year ago

From the limitations section:

@ts-react/form allows you to pass props to your components and render elements in between your components, which is good for almost all form designs out there. Some designs may not be easily achievable. For example, if you need a container around multiple sections of your form, this library doesn't allow splitting child components into containers at the moment. (Though if it's a common-enough use case and you'd like to see it added, open an issue!)

Not sure what will be the right approach but I like to be declarative as possible

For now, I experimented with this approach, not sure I like the DX, too much magic?

Passing some components to beforeElement, like section header GridColumnHeader image

before layout the childrens, do some Children.toArray(children) tricks to split them based on the beforeElement and plot each part as separate section

image

Not sure I like this approach but it seem to do the work

iway1 commented 1 year ago

Yeah I'd agree it's probably a little too magical, but I like the idea of expanding the use case coverage to support at least simple containers.

One approach I've thought of is potentially some special container fields that can be used in the schema or something?

const MyContainer = createContainer('id', ContainerComponent);

const MyFormSchema = z.object({
  containedFields: MyContainer({
    textField: z.string(),
    numberField: z.number()
  })
})

Or:

const MyFormSchema = z.object({
  ...MyContainer({
    textField: z.string(),
    numberField: z.number()
  })
})

Would render the components for textField and numberField as a children of ContainerComponent.

And then use some hardcore typescript magic to make the form type be treated as:

{
  textField: string,
  numberField: number,
}

Could export a few default one's for simple use cases like Rows and stuff.

What about that? Would it enable the same stuff you're doing with your current approach?

mulyoved commented 1 year ago

To be honest, I don't like the idea of pushing this information to the zod object, already too much TypeScript magic around it and this is the place to do validation if I have complex validation like refine at the object/form level this will get in the way

MathisBarre commented 1 year ago

I think not having container around multiple form section it's actually the only reason I can't use this library right know. The fact that you just can't place two inputs with unrelated type side-by-side is a no-go for me.

It's a shame because I realize that I'm hardly trying to do what this library do by myself. And it take time, has a lot of boilerplate and it's not working great.

scamden commented 1 year ago

we have this use case too. here's an idea a co-worker @gpeal came up with: the loose idea would be to pass the rendered form field components in a named map to the CustomFormComponent given to react-ts-form. Then we could build the following, which gives us ultra layout flexibility without sacrificing any of the benefits of generating the components:

function MyForm() {

  return (
    <ZodForm schema={z.object({title : z.string(), description: z.string()})}>

      {({childMap}) => (
        <Box>
          {childMap['title']}
          <Typography>Some text</Typography>
          {childMap['description']}
        </Box>
      )}
    </ZodForm>
  )
}
scamden commented 1 year ago

seems like this method could solve https://github.com/iway1/react-ts-form/issues/34 as well if we also pass the formstate per field as props here?

scamden commented 1 year ago

fyi the above approach is published at zod-form if you want to try it out