Skip to content

Instantly share code, notes, and snippets.

@RussMax783
Last active August 18, 2017 21:52
Show Gist options
  • Save RussMax783/916cf9a0a5e85446666751b85c2f915b to your computer and use it in GitHub Desktop.
Save RussMax783/916cf9a0a5e85446666751b85c2f915b to your computer and use it in GitHub Desktop.
basecomponent-expansion.md

I want to create a way that is easy to define the layout of components in the markup so that it will work on Web and React Native. Even if we don't go down the React Native route there is still so much to learn from how they structured their APIs and how they implemented certain aspects of how you interact with the DOM. I also think it would be super cool for Jane to have an open source project that works on React and React Native that is based on our base components. Utilizing styled components and themes we can do some really cool things. We can do a lot of what Leland Richardson talked about and create our components in such a way that they are easily shareable between web and native devices. To accomplish this with what we have currently built in Jane components, we need a couple more things, and i want to get your feed back on these components API/prop types.

Space

The space component is used to add gutter in-between items. it only takes and x, y, top, bottom, left, and right. The current gutter prop will only work on web and if we consider React Native we need an easy way to define spacing. Here is a couple options:

Specifically add space whenever needed

Using a component that looks like this:

<Space y={14} /> // has a height of 14
<Space x={14} /> // has a width of 14
<Space top={14} /> // has a margin-top of 14
<Space bottom={14} /> // has a margin-bottom of 14
<Space left={14} right={14} /> // has a margin-left and margin-right of 14

instead of this (which is what we currently have

<Col gutter={16} paddingBottom={24} paddingLeft={16}>
	<Col gutter={4}>
		<Text fontSize={16} color="gray20" weight="300">Title</Text>
		<Text fontSize={14} color="gray40" weight="300">Description</Text>
	</Col>
	<Text>some other text</Text>
</Col>

we would change a little bit and do this

<Col paddingBottom={24} paddingLeft={16}>
	<Col>
		<Text fontSize={16} color="gray20" weight="300">Title</Text>
		<Space y={4} />
		<Text fontSize={14} color="gray40" weight="300">Description</Text>
	</Col>
	<Space y={16} />
	<Text>some other text</Text>
</Col>

In the cases where we map over an array and create a list of elements which usually looks like this:

{someList.map((x) => (
    <Item ... />
))}

we do a tiny bit extra and do

{someList.map((x, idx) => (
  <Space top={idx ? 12 : 0} key={item.id}>
    <Item ... />
  </Space>
))}

this will wrap the child and add margin top of 12 on all elements except the first one, spacing out all the elements with 12

I lean towards this way as there are instances where a design has spacing between elements that varies more then just 12px between each item. This easily allows us to explicitly add margins to space things as needed and if the spacing changes between responsive points, we simply wrap the space in a media components.

Iteration

We could keep Web the same and let css do its thing with selectors, but In React Native we map over children add add<Space y={gutter} /> in between items. As long as our layouts are pure I don't see this being a performance issue. This would be somewhat similar to what react native does to create lists, such as List and FlatList

Media Component

we can create a simple component that will choose to render its children based of two simple props, from and to.

<Media to="small">
  ... content rendered up to small
</Media>

<Media from="small" to="large">
  ... content rendered from small breakpoint to large
</Media>

<Media from="medium">
  ... content rendered from medium breakpoint and up
</Media>

The most often thing i've seen when needing something to be responsive is simply switching between flex-directions at a certain point.

const Header = styled.div`
  display: flex;
  flex-direction: column;
  ${({ theme }) => theme.media.smallMin`
    flex-direction: row;
    justify-content: center;
  `}
`

We can abstract this ab it and create a RowCol components or a ColRow. This will take a breakpoint and switch between a Row or Col at the breakpoint respectively. It also will take responsiveProps which will be an array of two objects that will be put onto the respective Row or Col.

This will render a row up too small and from small up, it will be a Col with justifyContent: 'center'

<RowCol {/* or ColRow */}
  breakpoint="small" 
  responsiveProps={[
   { },  
   { justifyContent: 'center' }  
  ]}
/>

This will render a row up too small with justifyContent: 'center' but from small up, it will be a Col and no longer be centered

<RowCol {/* or ColRow */}
  breakpoint="small" 
  responsiveProps={[
   { justifyContent: 'center' },  
   { }  
  ]}
/>

This will render a row up too medium with justifyContent: 'center' and from small up, it will be a Col and will still have justify center

<RowCol {/* or ColRow */}
  breakpoint="medium"
  justifyContent="center"
/>

Touchable

we'll need a touchable that willl basically standardize the onClick vs the onPress between React and React Natve

Link

This one will be tricky. How do we route within the app where web is url driven and native is stack driven... One option i've thought about is based on the navigators we use where ReactRouter is used on web and has a Link, and on native would probably be ReactNavigation, is to create an abstraction of the two and route based on the device we are on.

@megamaddu
Copy link

megamaddu commented Aug 17, 2017

And I do like this for some cases:

<Text>Some text</Text>
<Space vertical={14} />
<Text>Some other Text</Text>

Would vertical always be 14px in this case? Half above and half below? Or would Space behave differently when there are children. It might be easier to make the component if we have one for "being" space and one for "adding" space.
Space and Pad maybe.

The other example usage I'm comparing to:

<Space all={5} vertical={2} top={20}>
  <Item ... />
</Space>

@RussMax783
Copy link
Author

To is exclusive and from is inclusive. Because we want to display something "up to medium" at that point when we hit medium we are passed the medium breakpoint. so for a medium breakpoint, from would be from the medium break point and on. Hence From would be inclusive. Could change to to be something like uptoor something more specific?

@RussMax783
Copy link
Author

Trotter, i like your idea of Space and Pad. The Api becomes a little more clear. Space is strictly horizontal or vertical space, and Pad takes children and will add margin to any direction. I think it looks pretty clean too

<Row>
  <Pad after={12}><Text fontSize={12}>1...</Text></Pad>
  <Pad after={12}><Text fontSize={12}>2...</Text></Pad>
  <Text fontSize={12}>3...</Text>
</Row>

or

<Row>
  <Text fontSize={12}>1...</Text>
  <Space horizontal={12} />
  <Text fontSize={12}>2...</Text>
  <Space horizontal={12} />
  <Text fontSize={12}>3...</Text>
</Row>

With this, yes there are more dom nodes, but remember that components try and keep themselves internalized. So we should be using the padding on a Row or Col more the space. Space should be used more for layout only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment