css-to-react-native-transform icon indicating copy to clipboard operation
css-to-react-native-transform copied to clipboard

feat: add support for parsing the ::part() selectors

Open cray0000 opened this issue 3 years ago • 4 comments

Parse ::part() selectors when parsePartSelectors: true option is passed.

cray0000 avatar Aug 17 '20 13:08 cray0000

Pull Request Test Coverage Report for Build 370

  • 1 of 1 (100.0%) changed or added relevant line in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.04%) to 98.925%

Totals Coverage Status
Change from base Build 237: 0.04%
Covered Lines: 102
Relevant Lines: 102

💛 - Coveralls

coveralls avatar Aug 17 '20 13:08 coveralls

Sorry @cray0000 , I have totally not noticed this one.

What is the use case for the ::part() selectors? This parser is meant for React Native, not Web.

kristerkari avatar Jul 18 '21 13:07 kristerkari

hi @kristerkari , it's something which is supposed to be working together with the styleName functionality. I've made a framework with your css libraries playing a big role in it: https://github.com/startupjs/startupjs

Regarding the ::part() specifically:

I forked some of your stuff related to classnames/stylenames and extended it with the emulation of styling parts of components following the ::part() css standard but using the foobarStyle naming convention to represent the parts and automatically pass them into JSX elements.

So when you write the following in css file:

// index.styl
.card
  background: red
  padding: 8px
  &:part(title)
    color: blue
  &:part(footer)
    padding: green

this will get compiled into passing not just the style object into the JSX element with styleName='card', but it will actually transform JSX to pass multiple style properties through the splat:

<Card styleName='card' />

will get transformed to:

<Card {...styles.card} />

where styles.card would have:

{
  style: { ... },
  titleStyle: { ... },
  footerStyle: { ... }
}

it's actually not just a simple styles.card, but a result of a function call, where it also dynamically merges any existing properties in the right order.

And then from the JSX side I also added support for the part attribute, which does a following transform:

<View part='root'>
  <View part='title'>

will be transformed to (root is a magic name which gets transformed to just style):

<View style={style}>
  <View style={titleStyle}>

and again it's a bit more complex than that, supporting merging in styles from the styleName and reusing style attribute if it exists. And it will also automatically destructure style and titleStyle from the component props.

If you are interested in looking at the test cases and implementation, you can find it here:

https://github.com/startupjs/startupjs/tree/master/packages/babel-plugin-rn-stylename-to-style#part-selector

Tests for the JSX transformation are in __test__ and the tests for the dynamic CSS selectors matching (done in runtime, similar to how you match @media) are in test.

And regarding this PR -- I'm not actually sure if it makes sense to merge it, since ::part() is supposed to work together with that enhanced fork of handling the styleName from my startupjs monorepo (@startupjs/babel-plugin-rn-stylename-to-style).

Let me know what you think.

cray0000 avatar Jul 20 '21 11:07 cray0000

@cray0000 Thank you for the detailed explanation!

i’m not home at the moment, but I’m happy to add the change if you have libraries that are using the parser. It should be safe to add since it’s behind a flag.

kristerkari avatar Jul 20 '21 14:07 kristerkari