treat icon indicating copy to clipboard operation
treat copied to clipboard

RTL support?

Open lencioni opened this issue 5 years ago • 12 comments

I am considering adopting Treat for a project where having good automatic right-to-left support is important. I didn't see anything in the docs about this, or how Treat might be able to be extended to support this, so I'm opening this issue to kick off the conversation.

Do you see a good way to use/extend Treat to support auto RTL flipping, or to build that feature into Treat directly?

This is similar to @jpnelson's question over on Linaria:

Describe the feature

It would be nice to have some form of RTL support for the library. For example, you can see how react native web handles this – the requirement is that there are different static styles compiled that can be switched between at runtime, particularly the LTR and RTL styles. https://github.com/kentcdodds/rtl-css-js is a library that does the actual "style flipping" logic.

Motivation

We'd like to be able to support languages that have a RTL flow.

Related Issues

I couldn't find any but let me know if this has been talked about before!

As a side note, I'm interested in whether this is something that you'd be open to PR's for. Thanks!

lencioni avatar Feb 11 '20 22:02 lencioni

Hey 👋

This is an interesting one. We had a chat internally about this and we're thinking we could add a simple (to start with) plugin API to treat for these kinds of issues. That way you could run something like rtl-css-js over your styles at build-time. Potentially this could be theme specific as well, would have to think this through further though.

e.g.

new TreatPlugin({
  plugins: [rtl-plugin]
})

Thoughts?

mattcompiles avatar Feb 12 '20 03:02 mattcompiles

I think that could work.

However, I'm wondering if Treat could be composed with PostCSS in some way today e.g. via postcss-loader? If so, then I think it would work to handle the RTL and whatever other processing we need to do (e.g. autoprefixing) in PostCSS. Looking at the webpack example in the docs, it seems like this could be passed in to the outputLoaders option, something like this, right?

const TreatPlugin = require('treat/webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PostCSSLoader = require('postcss-loader');

module.exports = {
  plugins: [
    new TreatPlugin({
      outputLoaders: [MiniCssExtractPlugin.loader, PostCSSLoader]
    }),
    new MiniCssExtractPlugin()
  ]
};

lencioni avatar Feb 12 '20 11:02 lencioni

We actually use PostCSS internally for minification and autoprefixing. We chose not to expose this functionality though as we can't guarantee the CSS output from treat will be correct when passed through various plugins.

Also PostCSSLoader won't work as an outputLoader as it needs to run before css-loader. Is there any other use-cases you were thinking of?

Btw does your project require theming? And do you need to apply the RTL stuff differently per theme?

mattcompiles avatar Feb 12 '20 11:02 mattcompiles

We actually use PostCSS internally for minification and autoprefixing.

Gotcha, that makes sense.

Also PostCSSLoader won't work as an outputLoader as it needs to run before css-loader. Is there any other use-cases you were thinking of?

I could imagine that some PostCSS plugins could be useful for adding more fallbacks for older browsers than what autoprefixer would, but I don't have any plugins specifically in mind at the moment.

Btw does your project require theming? And do you need to apply the RTL stuff differently per theme?

Yes, this project needs theming. I don't think the RTL needs to be applied differently per theme.

lencioni avatar Feb 12 '20 11:02 lencioni

Right. I'm open to exposing more hooks into the output CSS to allow customisations but I'm wary of being coupled to PostCSS long term. Atm its more of an implementation detail.

I'm surprised the RTL requirements are not theme specific. Is your plan to compile the app multiple times with different settings?

mattcompiles avatar Feb 12 '20 12:02 mattcompiles

I'm surprised the RTL requirements are not theme specific. Is your plan to compile the app multiple times with different settings?

It's all about the selectors. Check out the postcss-rtl readme.

With this input:

.foo {
    float: right;
    margin-left: 13px;
    text-align: right;
    font-size: 13px;
    border-color: lightgray;
    border-width: 2px 0 2px 2px;
    border-style: solid dashed solid solid
}

.foo {
    text-align: center;
}

it will be compiled into this output:

.foo {
    font-size: 13px
}

[dir] .foo {
    border-color: lightgray
}

[dir="ltr"] .foo {
    float: right;
    margin-left: 13px;
    text-align: right;
    border-width: 2px 0 2px 2px;
    border-style: solid dashed solid solid
}

[dir="rtl"] .foo {
    float: left;
    margin-right: 13px;
    text-align: left;
    border-width: 2px 2px 2px 0;
    border-style: solid solid solid dashed
}

[dir] .foo {
    text-align: center
}

This allows you to control the direction at the HTML level by using <div dir="rtl">...</div> or whatever. So I think this should be able to run on everything and it will just work.

lencioni avatar Feb 12 '20 21:02 lencioni

Interesting 🤔. The trade-off here is that you're shipping a lot more CSS than you need to. Tying the directional properties to the theme would allow you to only send the CSS needed for the current setting.

mattcompiles avatar Feb 12 '20 22:02 mattcompiles

That's right. The main issue is when there is mixed content on the page, e.g. one section in Hebrew and another in English.

lencioni avatar Feb 13 '20 14:02 lencioni

Hi @mattsjones, my use case is more inline of what you had in mind. I need to develop my components to work in RTL / LTR depending on the theme.

guy-kdm avatar Apr 13 '20 08:04 guy-kdm

Just to give more context, I'm building a white-label product to be localized and embedded in a specific segment of big sites around the world. Treat is perfect because I have strong backwards compatibility reqs. So that's where my theming and RTL requirements come from and why I need RTL on a per theme basis. Also, thanks for sharing treat! Logical properties are not an option for backward compatibility, so I do think I'll need some post processing. How would you recommend I do it for now?

guy-kdm avatar Apr 15 '20 10:04 guy-kdm

@guy-kdm I've talked with @mattsjones about this offline, and there are some challenges here with introducing a plugin system where styles are manipulated based on the theme. Since not every style is themed, does that mean we'd then have to automatically convert everything to themed styles? If we do this, we have to keep in mind that themed styles are higher precedence than non-themed styles, and this may break your UI if you were to introduce this plugin later.

If you'd like a short term fix for this, remember that treat files are just JavaScript, so you don't technically need a plugin system to perform complex transformations on your styles. This is actually a good example of why I like this architecture so much.

For example, you could write a utility function that accepts a theme and a style object and returns a new style object with the RTL transformations applied. Even if we had a plugin system, you'd need to write this transformation code anyway—it'll just be more awkward to consume for now because you'll have to manually execute it in your treat files. Does that make sense?

markdalgleish avatar Apr 16 '20 12:04 markdalgleish

Cool, I'll write the code and see.

guy-kdm avatar Apr 19 '20 08:04 guy-kdm