CSS variables
can easily implement the theme, using the theme modules provided by Gem will have more advantages:
TypeScript integration
Prevent multiple theme CSS custom property name conflicts
Observable ThemeStore object
import { createTheme } from '@mantou/gem/helper/theme';
const theme = createTheme({
primaryColor: '#eee',
});
const styles = css`
div {
border: 2px solid ${theme.primaryColor};
}
`;
@customElement('app-root')
@adoptedStyle(styles)
class App extends GemElement {} As can be seen from the above usage, once an object is created as a theme, the fields read from the theme are CSS variables:
console.log(theme.primaryColor);
// => var(--primary-color-xxxxx) Sometimes you may need to read the original object, such as printing the subject to the element:
import { createTheme, getThemeStore } from '@mantou/gem/helper/theme';
const theme = createTheme({
primaryColor: '#eee',
});
const themeStore = getThemeStore(theme);
const styles = css`
div {
border: 2px solid ${theme.primaryColor};
}
`;
@customElement('app-root')
@adoptedStyle(styles)
@connectStore(themeStore)
class App extends GemElement {
render = () => {
return html`
<div>primaryColor: ${themeStore.primaryColor}</div>
`;
}
} If you want to support dark mode, you can use matchMedia
for media queries, and then use different themes, E.g:
import { createTheme } from '@mantou/gem/helper/theme';
const lightTheme = {
primaryColor: '#333',
};
const darkTheme = {
primaryColor: '#eee',
};
const theme = createTheme(matchMedia('(prefers-color-scheme: dark)').matches ? darkTheme : lightTheme);
const styles = css`
div {
border: 2px solid ${theme.primaryColor};
}
`;
@customElement('app-root')
@adoptedStyle(styles)
class App extends GemElement {} Scoped and override theme v1 only supports global themes, while v2 supports scoped themes and theme overrides:
// Global theme will be automatically added to `document`
const theme = createTheme({ textColor: '#eee' });
const scopedTheme = createScopedTheme({ scopeTextColor: '#333' });
const overrideTheme = createOverrideTheme(theme, { textColor: '#eff' });
const styles = css`
:scope {
color: ${theme.textColor};
background: ${scopedTheme.scopeTextColor};
}
`;
@customElement('my-element')
@adoptedStyle(styles)
@adoptedStyle(scopedTheme)
@adoptedStyle(overrideTheme)
class MyElement extends GemElement {} Additionally, thanks to relative color syntax
, colors ending with Color in the theme directly support using "weights" (similar to font weight) to adjust brightness: theme.textColor500, which is a color slightly brighter than the original textColor.
The theme is implemented using CSS variables, which may need to be dynamically set during rendering, this can also be achieved through themes, but unlike other types of themes, decorators are required to apply and update the theme.
import { createDecoratorTheme } from '@mantou/gem/helper/theme';
const elementTheme = createDecoratorTheme({ color: '' });
const style = css`
:host(:where(:not([hidden]))) {
border-color: ${elementTheme.color};
}
`;
@customElement('app-root')
class App extends GemElement {
@attribute color;
@elementTheme()
#theme = () => ({ color: this.color })
render = () => {
return html``;
}
}