Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Theme UI to Custom properties utility transformer #235

Merged
merged 8 commits into from
Jul 31, 2019
Merged

Implement Theme UI to Custom properties utility transformer #235

merged 8 commits into from
Jul 31, 2019

Conversation

alex-page
Copy link
Contributor

@alex-page alex-page commented Jul 28, 2019

@jxnblk had some time to dig into #128. Let me know if this should be a package in this project or split a part. Some things I would like feedback on or would like to investigate further my self before merging:

  1. Is there a possibility of having more then two levels of depth in a theme object? Is there a collection of theme object examples?
  2. Do the generated CSS variable names feel right?
  3. Should there be different options for kebabcase, camelcase etc?
  4. I could provide a map for the variable names or try to stay aligned to theme specification? A good example might be mapping plural to singular --colors-text -> --color-text.
  5. Should variable names that are generated from arrays append a numeric value or something else? If yes, should they always start at zero?
  6. I added an optional prefix for the variable name. Should themeui provide a default prefix or is no prefix preferred by default? Happy to add a test for an optional prefix.
  7. Should the function return a string of CSS or an object that could be applied with JS element.style.setProperty(key, value);? I personally don't mind but would love to know how other people want to use this.
  8. What happens when a user doesn't add a unit like in spacing below? Should we just output the value based on what is provided, always add a unit or give an option to provide one?

Here is an example of how the following theme object turns into css:

{
  colors: {
    text: '#000',
    background: '#fff',
    primary: '#07c',
    secondary: '#05a',
    accent: '#609',
    muted: '#f6f6f6',
  },
  fonts: {
    body: 'system-ui, sans-serif',
    heading: 'system-ui, sans-serif',
    monospace: 'Menlo, monospace',
  },
  fontWeights: {
    body: 400,
    heading: 700,
    bold: 700,
  },
  lineHeights: [1.5, 1.125],
  space: [0, 2, 3, 4, 5, 6],
  size: ['10em', '20em', '30em', '40em'],
}

Example of css variables generated:

--colors-text: #000;
--colors-background: #fff;
--colors-primary: #07c;
--colors-secondary: #05a;
--colors-accent: #609;
--colors-muted: #f6f6f6;
--fonts-body: system-ui, sans-serif;
--fonts-heading: system-ui, sans-serif;
--fonts-monospace: Menlo, monospace;
--fontweights-body: 400;
--fontweights-heading: 700;
--fontweights-bold: 700;
--lineheights-0: 1.5;
--lineheights-1: 1.125;
--space-0: 0;
--space-1: 2;
--space-2: 3;
--space-3: 4;
--space-4: 5;
--space-5: 6;
--size-0: 10em;
--size-1: 20em;
--size-2: 30em;
--size-3: 40em;

@jxnblk
Copy link
Member

jxnblk commented Jul 29, 2019

Awesome, thanks for working on this! I'll try to address some of your questions below, but generally this is looking great!

Is there a possibility of having more then two levels of depth in a theme object? Is there a collection of theme object examples?

The theme object itself isn't intended to include child theme objects, but something working above the level of what's currently going on in Theme UI could. I think for the implementations in Theme UI itself, this can generally be ignored for now – if we stick to a flat object convention across the board, then it'll be easier to handle stuff like that in the future with separate components without making the initial code base more complex.

As for individual scales within the theme object, e.g. colors, they can be deeply nested, but the naming convention is up to the user.

Should there be different options for kebabcase, camelcase etc?

CSS custom properties are case sensitive, so using the same convention should be okay. For dot-notation, I think keys could be separated by hyphens, e.g. --color-blue-2. An option for converting to kebab-case seems like a nice-to-have though.

Do the generated CSS variable names feel right?
I could provide a map for the variable names or try to stay aligned to theme specification? A good example might be mapping plural to singular --colors-text -> --color-text.

Since the theme scales are objects and arrays, the plural naming convention makes sense in the theme object, but for the custom properties, we can probably use something like pluralize to use a singular naming convention. I.e. I think they should be named like --color-background and --fontSize-0

Should variable names that are generated from arrays append a numeric value or something else? If yes, should they always start at zero?

Yeah, I think using the object keys as-is is the most straight-forward naming convention, and since arrays are zero-based, fontSizes[0] would become --fontSize-0.

I added an optional prefix for the variable name. Should themeui provide a default prefix or is no prefix preferred by default? Happy to add a test for an optional prefix.

An optional prefix would be fantastic, but I don't think it's necessary to ship this. The default could be un-prefixed, even though there might be potential for collisions. If you want to add that to the PR, feel free to do so.

Should the function return a string of CSS or an object that could be applied with JS element.style.setProperty(key, value);? I personally don't mind but would love to know how other people want to use this.

For the initial use-case, I think being able to pass a style object to either the React style prop, the Emotion css prop, or the Global component would cover most use-cases. If someone needs a CSS string version, there are existing utilities that can convert the value, and I don't think we need to support that in this utility. It looks like you've implemented it as a string currently, but hopefully it's not too difficult to switch to an array.

What happens when a user doesn't add a unit like in spacing below? Should we just output the value based on what is provided, always add a unit or give an option to provide one?

For number values, we'll probably want to convert some CSS properties to use pixel units and leave properties like lineHeight as unitless values. If the numbers are consumed only within Emotion, we wouldn't need this, but I think part of the idea here is to make the theme object consumable in other CSS contexts.

@alex-page
Copy link
Contributor Author

Thanks for all the great points. I am out for a few days but will jump back into this later in the week.

@alex-page
Copy link
Contributor Author

alex-page commented Jul 30, 2019

I have gone through and fixed up the following based on the feedback:

  • Nested properties in theme object
  • Remove plurals in theme object
  • Test for optional prefix
  • Returns object ( I think this will work for React style prop but I haven't tested it )

For number values, we'll probably want to convert some CSS properties to use pixel units and leave properties like lineHeight as unitless values. If the numbers are consumed only within Emotion, we wouldn't need this, but I think part of the idea here is to make the theme object consumable in other CSS contexts.

Not including units may be intentional ( if it is I would love to know why ). For now the function returns the values based on the input. I would feel a bit dirty appending px to the end. What if they intended rem?

I feel like there could be a linter to make sure that certain properties have units ( space, size ). For keeping the conversion to css variables simple it feels like the theme object should supply the unit.

@jxnblk
Copy link
Member

jxnblk commented Jul 30, 2019

Awesome! Will take another look in a few!

Not including units may be intentional ( if it is I would love to know why )

With Emotion, unitless number values are converted to pixel values for CSS properties where it makes sense. This is also how the style prop in React works, and Styled Components supports the same thing. In Theme UI, you can define values in e.g. theme.space as numbers, but they render as pixels. For this to work outside of emotion, I think we'll want a way to convert numbers to pixel string values. This is not needed in this PR though, and it's something I can look into later. (I suspect @emotion/core might have this utility already)

@alex-page
Copy link
Contributor Author

With Emotion, unitless number values are converted to pixel values for CSS properties where it makes sense. This is also how the style prop in React works, and Styled Components supports the same thing. In Theme UI, you can define values in e.g. theme.space as numbers, but they render as pixels. For this to work outside of emotion, I think we'll want a way to convert numbers to pixel string values. This is not needed in this PR though, and it's something I can look into later. (I suspect @emotion/core might have this utility already)

This is super interesting! Thanks for the context 💯

@alex-page
Copy link
Contributor Author

This feels pretty polished now. Let me know if there are any additional changes 👍

@jxnblk
Copy link
Member

jxnblk commented Jul 31, 2019

This looks great! Thanks for working on this!

@eschaefer
Copy link
Contributor

Hey all, just for awareness, this broke compatibility with IE11, which does not support CSS variables. I love this lib but I imagine quite a few people still need to support this unfortunate browser...

@alex-page
Copy link
Contributor Author

@eschaefer you can use theme-ui in multiple ways this is just one option. You could try using tachyons or tailwind package if you want to generate css classes which would work in IE11.

@jxnblk
Copy link
Member

jxnblk commented Sep 26, 2019

@eschaefer you can turn off custom properties with this flag in your theme: https://theme-ui.com/color-modes#turn-off-custom-properties

@eschaefer
Copy link
Contributor

Thanks @jxnblk! This solves the issue perfectly! I was searching for the wrong text ("css variables") in the documentation. 🙄

@alex-page alex-page changed the title Implement Theme UI to CSS variables utility transformer Implement Theme UI to Custom properties utility transformer Sep 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants