styled-components / xstyled

A utility-first CSS-in-JS framework built for React. 💅👩‍🎤⚡️
https://xstyled.dev
MIT License
2.28k stars 105 forks source link

Merging props in xStyled v3 #356

Closed Makskow closed 2 years ago

Makskow commented 2 years ago

Hi!

I've been successfully using xStyled in my projects and have built a component library using it. I'm still on v2, which has a considerable difference with v3 in terms of how CSS states are represented in props.

v2
<Button color="#f00" hoverColor="#0f0" activeColor="#00f" bg="#eee">Click</Button>

v3
<Button color={{ _: '#f00', hover: '#0f0', active: '#00f' }} bg="#eee">Click</Button>

What has stopped me from migrating to v3 is how in a component I would merge internal style props with external props provided by a consumer of the component. Merging internal and external props is important to have styled, reusable components, but also allow easy style overwriting. Here's more or less what I do today with v2:

function Button(props) {
  const styles = { color: '#f00', hoverColor: '#0f0', activeColor: '#00f', bg: '#eee' } 

  // Shallow merging styles and props objects
  return <x.button {...styles} {...props} />
}

// Consumer using a Button
<Button color="#ff0"  bgHover="#ddd" }>Click</Button>

In v2, shallow merging objects works well when I'm dealing with 1-level objects (not taking breakpoints into account). However, in v3 it's most likely that objects will be nested and will require deep merging. This might have performance implications and even break when some props might be nested objects and some are strings.

Do you have any recommendation on how to deal with a following scenario in v3?

function Button(props) {
  const styles = { color: { _: '#f00', hover: '#0f0', active: '#00f' },  bg: '#eee' }

  // Here the props should be deep merged somehow, keeping in mind that some values are objects and some are strings
  return <x.button {...styles} {...props} />
}

// Consumer using a Button
<Button color="#ff0"  bg={ hover: '#ddd' }>Click</Button>
gregberge commented 2 years ago

Hello @Makskow, my recommendation is to use a custom merging strategy. If you detect a string, you put it in _ key, and your merge other props. It should only take a few lines of code to handle it correctly.