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

fix: styled.box with rule ordering instead of specificity #244

Closed agriffis closed 3 years ago

agriffis commented 3 years ago

Summary

Fixes #240 with rule ordering instead of specificity.

INPUTOLD OUTPUTNEW OUTPUT
```js const Foo = styled.box` color: green; ` ``` ```css .foo.foo { color: red; /* ${system} */ } .foo { color: green; } ``` ```css .foo { color: green; color: red; /* ${system} */ } ```

It works like this:

styled.box = styledWithGenerator('div', system).withConfig({shouldForwardProp})

which applies the generator at the conclusion of the given styles, so that props can override styles:

styled.box`
  color: green;
`

// is exactly the same as
styled.div.withConfig({shouldForwardProp})`
  color: green;
  ${system};
`

Notes

My first attempt at this PR changed the signature of the styled function to add optional generators, so for styled-components it became styled(component, ...generators) and for emotion it became styled(component, options, ...generators). But for now I think it's better to refrain from changing the signature, so instead we have a new internal API: styledWithGenerator so the existing styled export remains unmodified.

That also means we don't have to monkey with types.

Test plan

Existing tests pass, and I added a couple new tests to make sure that props overriding works as expected.

I've also been using a local implementation of this same setup for a production app, and it's working well.

agriffis commented 3 years ago

@gregberge After a couple rounds of reworking, this is ready. Want to take a look?

agriffis commented 3 years ago

@gregberge Note there is a refactoring commit before the functional commit. It's a little easier to review as two separate commits, instead of the full set of changes at once.

gregberge commented 3 years ago

Thanks @agriffis it is awesome! For API change, yeah it is better to keep it separated.