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

Odd behavior when styled(x.{element}) #359

Closed quantizor closed 2 years ago

quantizor commented 2 years ago

🐛 Bug Report

When using styled(x.input) for example, the provided styles win against any prop-driven styles also supplied. I think it should be the reverse, that prop-driven styles should have higher specificity or appear later in the generated CSS so the proper rule cascade is maintained.

To Reproduce

Sample code:

const BaseInput = styled(x.input)`
  color: red;
`;

// color in browser is red
<BaseInput color="blue" />

Expected behavior

The apparent input color should be blue, since it's the last style applied on top of the base styles.

Notes

I also tried styled.input but prop styles don't seem to be available when using that syntax...

agriffis commented 2 years ago

@probablyup This is a dup of #340. Does the explanation in that issue help?

agriffis commented 2 years ago

Also the explanation at https://github.com/gregberge/xstyled/issues/287#issuecomment-870496934

quantizor commented 2 years ago

@agriffis Ah ok, I see. The naming of the escape hatch isn't intuitive to me. Could we possibly have them be something like styled.xinput? "box" doesn't scream xstyled

agriffis commented 2 years ago

The really short explanation is: Wrappers always win. Your color prop is being handled by the inner component, but the color is overridden by the outer component.

agriffis commented 2 years ago

Hmm, escape hatch? I'm not following

agriffis commented 2 years ago

I also tried styled.input but prop styles don't seem to be available when using that syntax...

I think this is what you're looking for:

const BaseInput = styled.input`
  color: red;
  ${system}
`

I know I'm answering fast-n-furious, we can slow down if it's not clicking.

agriffis commented 2 years ago

I think styled.x* would make a lot of sense, now that it clicked for me. It hadn't occurred to me before, but styled(x.*) is an anti-pattern that will rarely do what people expect. For good reasons, but nonetheless...

agriffis commented 2 years ago

@probablyup Yeah, here's the bit in the code:

  styled.box = xstyled('div')
  Object.keys(scStyled).forEach((key) => {
    // @ts-ignore
    styled[key] = styled(key)
    // @ts-ignore
    styled[`${key}Box`] = xstyled(key)
  })

I suppose for compat we'd keep the Box ones, but add

styled[`x${key}`] = xstyled(key)

There's a very slight chance of future name collision, but at the moment the only HTML element starting with x is <xmp> and there's no <mp> so we're good.

gregberge commented 2 years ago

I think everything is said here. The box convention is weird with xstyled, we could reconsider it for a next major. In previous version, the x.div was Box, that's why you have aBox.