Poimen / stencil-tailwind-plugin

Plugin for using tailwindcss with StencilJS
https://www.npmjs.com/package/stencil-tailwind-plugin
MIT License
51 stars 5 forks source link

Adding TW utilities classes to the component `<Host>` on JSX is not applying the classes as expected #15

Open Poimen opened 2 years ago

Poimen commented 2 years ago

Doing:

<Host class="flex items-center justify-center fixed left-0 top-0 h-screen w-full">

doesn't compile/build the classes.

But if the classes are moved to CSS, then work just fine:

:host {
  @apply flex items-center justify-center fixed left-0 top-0 h-screen w-full;
}
ohkimur commented 2 years ago

@Poimen Any ideas why this happens? Do you know the root of the problem?

Poimen commented 2 years ago

Because the :host is used to select the host component. So the TW classes need to be put into the correct selector, not just in the CSS.

Normally what would happen is the TW processor would look/extract all the classes. That content is then used to update the CSS in the component (as if you wrote that in the CSS file itself - this is done by the plugin). However, for Host, it doesn't work as you expect because Host is more of a pseudo element than a real element, and the CSS in the CSS file is applied internally to the component. The Host CSS needs to be applied "externally" to the component because the Host is not internal...

It's a little complicated to explain ... but the Host TW styles need to be applied outside of the component, but the CSS defined is internal elements only ... so anything in <Host class="flex ..."> needs to be in the :host selector so it applies correctly.

Hope that makes sense 😵‍💫

ohkimur commented 2 years ago

@Poimen It does make sense. I played with what you said and it works. I am wondering if it's possible to make the plugin handle this kind of thing automatically for the Host element. What do you think?

Poimen commented 2 years ago

Yeah, it's just not as simple as it sounds unfortunately 😸 it's not like you can rely directly on what is written, some pre-work is required.

My current idea is to be able to find the <Host class=" <some classes> " in the file, then take all the classes in that and do something like:

:host {
  @apply // <-- put <some classes> here
}

I am not sure how stable that is, but could get the classes into a spot where the TW processor can just put the classes into the :host selector rather trying to patch the :host selector after the fact or something similar.

Is it do-able? Absolutely, just wondering on how stable the regex could be.

I don't want to process the JSX, but it could come down to that as there are a number of permutations of how people could write the Host:

<Host class="..."

or

<Host
  class="..."

etc.

We could be assuming that the class always comes after the Host tag, but is that a stable assumption or a good caveat to having the functionality 🤷‍♂️

Poimen commented 2 years ago

And forgot that this stencil as well, so would have to cater for stuff like:

      <Host
        disabled={isDisabled}
        class="..."
      >

or:

<Host
  class={{ ... }} //<-- optional styles
ohkimur commented 2 years ago

@Poimen I agree.

Building on top of what you said, I would propose using a general regExp pattern to easily capture the class attribute for the Host element. Something like this should be a good starting point <Host.*?(class=)["|{{?](.[\S\s]*?)("|}}?).*?>. The 2nd captured group contains the most common situations. From there it's possible to build a simple parser function that converts the 2nd captured group into plain class names.

NOTE: The only concern that I have with this approach is if the conditional classes will still be working.

Also, do you know if we can access the css-parser functions from the compiler? It seems they are exported, but I don't know if they are exposed outside. Maybe we can simply select the Host element and let the css-parser (or something similar from the compiler) provide the required CSS. But I don't know from the plugin land at which steps in the compiler we have access.

Poimen commented 2 years ago

It's an interesting thought ... and your regex-fu is impressive 😃

The CSS parsing is done by postcss and the processing is embedded into the walker - not much can be influenced there.

Which css-parser function were you looking at?

ohkimur commented 2 years ago

@Poimen I wasn't looking at something in particular. I was trying to see if there aren't already parts of the css-parser that we can use. After looking through there, it doesn't seem there is much utility for solving this issue.

I would propose to go with the CSS regExp approach. I don't know if it's possible to support the conditional classes this way, but at least it's a solution. Partial, but a solution. What do you think?

Poimen commented 2 years ago

Yes, the regex could be a start, with a mention of limitations in the readme. I'm up for that.

I always forget how postcss and TW convert/process the tsx files. At the end you pass pure CSS to it, but the starting phase will need so refresher.