[High] Add `children` handling to support specification of layouts

A “layout” in this context is effectively just a container which accepts some children. We talked about this and you argued that it would be best to go all the way and allow users to simply point out where the children should go in the tree. Ultimately this is low cost-benefit ratio for a first implementation, and taking children in some form (even if heavily compromised) is important to getting this production-ready.

My recommendation is to simply mark components as layouts, which would be a setting in the configuration view that is effectively just a checkbox. A layout component simply loses its children and passes along its { children } prop as immediate children.

When the TestComponent is marked a layout:

const TestComponent = (props: Props) => {
  return (
    <Container>
      - <Rectangle1 />
     + {props?.children}
    </Container>
  );
};

There are two reasons for this approach:

  1. It lets us support children as soon as possible.
  2. It lets us design layouts with content in them (you need content in your flex layout to preview changes), yet export them without content in them (laying out instead the children you pass to it).

This will only happen to components you ask to become layouts. I highly recommend this approach to start.

Comparison with Amplify Studio

Amplify Studio’s UI Library does allow for layout specification (creating components that take children) via what they call Collections, however they are cumbersome and do not allow the configuration that simply marking a component as a layout does.

Recommended implementation

I am going to tweak the implementation described here, which would allow you to mock up a layout of columns with a given set of styles and just take children that are passed to it (runtime children override).

Let’s think about how this TestColumnLayout should behave if marked as a layout:

My original suggestion was to simply render <Container>{children}</Container>, and discard the children entirely; but a better jumping off point for developers who import these components is to actually just render the demo content if no children are passed, i.e. <><Row1 /><Row2 ><Row3 /></> here, or else render the children passed to it. The container could still be forced to render nothing with <TestColumnLayout>{null}</TestColumnLayout>.

  • This makes the implementation simpler, i.e. no need to remove the const Row1 = styled.div definiitions.
  • This makes the DX upon loading a new component smoother by rendering the demo content until children are provided.

This looks like a reasonable feature and it’s not expensive implementation-wise to simply allow passing props to frame elements as you already can do with text elements. I’m actually working on this one as we speak, will have more to share pretty soon.