Theme-ui: `transformers` middleware for theme values

Created on 12 Jul 2019  ·  6Comments  ·  Source: system-ui/theme-ui

In our custom theme implementation on our team at work, we used functions to get tokens. for example:

<div
  css={theme => ({
    color: theme.color('red')
  })}
>
  This is our token red
</div>

This enabled us to do some cool things, for example, to use https://github.com/VinSpee/alpha-string-to-rgba so we could do this:

<div
  css={theme => ({
    color: theme.color('red.5')
  })}
>
  This is our token red, transformed to 50% opacity by `aRGB`.
</div>

Maybe the API could look like something like this (just spitballing here):

const theme = {
  colors: {
    red: '#E62A1E'
  },
  transformers: {
    colors: currentTheme => val => aRGB(currentTheme.colors)(val),
  },
};

any thoughts on something like this? It's like a middleware for tokens. It could (optionally, and simply) open up a lot of possibilities.

Most helpful comment

For anyone else coming here wanting to stick to theme-ui's API but want to change some of the ways theme data is stored you can use a Proxy

For example, my theme operates on a base-8 scale.
So if I want spacing to act like <Box margin={3}/> to give me { margin: 24px; } I can set a Proxy for the space prop.

const theme = {
  space: new Proxy([], {
    get: (_, num) => num * 8,
  }),
}

Note Be aware of the support for Proxy:
https://caniuse.com/#search=proxy
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

All 6 comments

i supposed this would go in styled-system's repo?

This is definitely possible, if you look at the source code for @styled-system/css it has a transforms dictionary already for negative margins. The thing I worry about is the coupling that this would create between a particular set of theme transformers/middleware/plugins and the components built with that configuration – i.e. keeping this sort of thing in a theme object could potentially have weird effects when swapping components and themes around. Generally I'd lean towards using custom utilities for something like this directly in the component, but it is an interesting idea and certainly warrants some further discussion

That’s a good consideration WRT Coupling a component to a theme. In my experience, more often than not, components are going to be coupled to a particular theme. Compete portability is achievable but is difficult - like a CSS Zen Garden exercise rather than a practical matter

In my experience, more often than not, components are going to be coupled to a particular theme.

With Theme UI we're hoping to change this.

Component/theme coupling is something that is currently true, but doesn't need to be. This ruins interoperability and portability. Large software companies often build complex, bespoke component libraries to solve their specific needs which often center around app UIs. This will typically result in special theme shapes that work best for them.

This doesn't work well for content heavy sites and personal blogs/portfolios/stores/etc.

Theme UI exposes a curated collection of components which are coupled to a Theme Spec. By keeping the spec and shape of themes rigid we can also ensure that other component libraries can magically work without much effort. There's also safety in numbers, here 🦓

Theme UI arose after a lot of analysis 📚 and @jxnblk magic ✨. It's a more general solution built for Gatsby Themes (blogs/notes/portfolios) that _can_ have swappable themes that are inspired by both Styled System and Typography.js. This ensures that projects that opt in to the "Theme UI way" automatically work/compose together.

If we can achieve a place where 90% of a site's design can be driven by a human-readable, JSON-serializable theme.js then we've achieved our goal. After all, we're hoping that a large amount of themes (whether at the app, site, or component level) can boil down to custom sets of predetermined CSS properties

It also means that any framework or ecosystem that speaks React/MDX/JSX can benefit from it, too. 🗺 ❤️ 📈


Also, one thing to mention is that these transformations, if known (steps in a scale), can happen as part of generating the static theme values. This is the approach that we'd recommend.

Going to close this out, since I think @johno covered some of the rationale with how we're approaching theming here

For anyone else coming here wanting to stick to theme-ui's API but want to change some of the ways theme data is stored you can use a Proxy

For example, my theme operates on a base-8 scale.
So if I want spacing to act like <Box margin={3}/> to give me { margin: 24px; } I can set a Proxy for the space prop.

const theme = {
  space: new Proxy([], {
    get: (_, num) => num * 8,
  }),
}

Note Be aware of the support for Proxy:
https://caniuse.com/#search=proxy
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jxnblk picture jxnblk  ·  4Comments

8eecf0d2 picture 8eecf0d2  ·  3Comments

VinSpee picture VinSpee  ·  3Comments

calvinwyoung picture calvinwyoung  ·  3Comments

muhajirdev picture muhajirdev  ·  3Comments