Closed
Description
Fresh eyes needed. We should also take inspiration from https://theme-ui.com/
We can even create a TS language service to tell us what themes are available with intellisense!
Global theming
Define your tokens in your options:
{
base: {},
default: {},
[optionalotherthemes]: {} // every other theme needs to have the same keys from default
}
Then use them in your CSS sourced from default:
css`
color: primary; // or
color: theme(primary);
`
Transforms to:
color: #fff;
color: var(--var-123abc);
Hardcodes and use the variable so it works with/without a parent theme.
Prepare a theme provider for consumers (you should only ever create one of these):
import { createThemeProvider } from '@compiled/css-in-js';
export const ThemeProvider = createThemeProvider();
// Optional "runtime" themes.
export const ThemeProvider = createThemeProvider({ ... });
Transforms to:
import { _TP } from '@compiled/css-in-js';
const theme = { base: { ... }, default: { '--var-abc123': '#000', ... }, ... };
// optional runtime themes would be merged in and converted to css variables
export const ThemeProvider = (props) => (
<_TP theme={props.theme}>
{props.children(theme[props.mode])
<_TP>
);
And then your consumers use like:
import { ThemeProvider } from 'your-design-system';
const App = () => (
<ThemeProvider theme="dark">
{style => <div style={style}>...</div>
</ThemeProvider>
);
Component theming
Would be the same as above with one key difference - the theme isn't sourced from the config. It's sourced inline.
import { createVariants } from '@compiled/css-in-js';
const useVariants = createVariants<'primary' | 'danger'>({
default: { default: {}, [optionalotherthemes]: {} },
[optionalotherthemes]: {},
});
<button style={useVariants('primary')} css={{ border: 'border', color: 'color' }}>
blah
</button>
import { useMode } from '@compiled/style;
// transformed to css variables
const variants = { default: {}, ... };
const useVariants = (variant: string) => {
const mode = useMode();
const defaultVariant = variants.default;
return {
...defaultVariant.default,
...defaultVariant[mode],
...variants[variant][mode],
};
};
The type safety aspect is missing a little. Perhaps instead of using string literals theme(primary)
and variant(color)
we could import them?
import { themeRefs, createVariants } from '@compiled/css-in-js';
const { useVariants, variant } = createVariants({});
const theme = themeRefs();
<div
style={useVariants('primary')}
css={{
backgroundColor: variant('backgroundColor'),
color: theme('primary'),
}}
/>
???
Goals
- Minimal use of react context
- Css variables for passing style values around
- Don't force specific markup to consumers
- Ensure bleeding of css variables doesn't affect things it shouldn't
Lingering thoughts
- What about runtime themes (i.e. they aren't known until runtime)?