mirror of
https://github.com/grafana/grafana.git
synced 2025-01-04 13:17:16 -06:00
Docs: How to work with themes (#17876)
* Add docs for themes * Edit description a little bit * Update themes.md
This commit is contained in:
parent
a2c1462675
commit
498572d2d8
103
style_guides/themes.md
Normal file
103
style_guides/themes.md
Normal file
@ -0,0 +1,103 @@
|
||||
## Core changes
|
||||
|
||||
JS is the primary source of theme variables for Grafana. Theme definitions are located in `@grafana/ui/themes` directory.
|
||||
|
||||
#### Themes are implemented in pure js.
|
||||
|
||||
This is because our goal is to share variables between app and SASS. To achieve that themes are necessary during build time to be exposed to sass loader via `node-sass` functions (https://github.com/sass/node-sass/blob/master/README.md#functions--v300---experimental). This retrieval is implemented in `getThemeVariable(variablePath, themeName)`.
|
||||
|
||||
#### Themes are available to React components via `ThemeContext`
|
||||
|
||||
Context is available via `import { ThemeContext } from '@grafana/ui';`
|
||||
|
||||
**If you skip `themeName` param, then dark theme's variant will be used**
|
||||
|
||||
## Using themes in Grafana
|
||||
|
||||
### SASS
|
||||
|
||||
`getThemeVariable` is a function, that's available in sass files. Use it i.e. like this:
|
||||
|
||||
```scss
|
||||
// In theme agnostic SASS file
|
||||
.foo {
|
||||
font-size: getThemeVariable('typography.size.m');
|
||||
}
|
||||
|
||||
// In *.[themeName].scss
|
||||
.bar {
|
||||
background-color: getThemeVariable('colors.blueLight', '[themeName]');
|
||||
}
|
||||
```
|
||||
|
||||
### React
|
||||
|
||||
#### Using `ThemeContext` directly
|
||||
|
||||
```ts
|
||||
import { ThemeContext } from '@grafana/ui';
|
||||
|
||||
<ThemeContext.Consumer>{theme => <Foo theme={theme} />}</ThemeContext.Consumer>;
|
||||
```
|
||||
|
||||
#### Using `withTheme` HOC
|
||||
|
||||
With this method your component will be automatically wrapped in `ThemeContext.Consumer` and provided with current theme via `theme` prop. Component used with `withTheme` must implement `Themeable` interface.
|
||||
|
||||
```ts
|
||||
import { ThemeContext, Themeable } from '@grafana/ui';
|
||||
|
||||
interface FooProps extends Themeable {}
|
||||
|
||||
const Foo: React.FunctionComponent<FooProps> = () => ...
|
||||
|
||||
export default withTheme(Foo);
|
||||
```
|
||||
|
||||
### Storybook
|
||||
|
||||
All stories are wrapped with `ThemeContext.Provider` using global decorator. To render `Themeable` component that's not wrapped by `withTheme` HOC you either create a new component in your story:
|
||||
|
||||
```tsx
|
||||
// Foo.story.tsx
|
||||
const FooWithTheme = withTheme(Foo);
|
||||
|
||||
FooStories.add('Story' () => {
|
||||
return <FooWithTheme />
|
||||
});
|
||||
```
|
||||
|
||||
or use `renderComponentWithTheme` helper:
|
||||
|
||||
```tsx
|
||||
// Bar.story.tsx
|
||||
|
||||
BarStories.add('Story' () => {
|
||||
return renderComponentWithTheme(Bar, /* pass props here */)
|
||||
});
|
||||
```
|
||||
|
||||
### Angular
|
||||
|
||||
There should be very few cases when theme would be used in Angular context. For this purpise there is a function available that retrieves current theme: `import { getCurrentTheme } from app/core/utils/ConfigProvider`
|
||||
|
||||
## Limitations
|
||||
|
||||
- #### Hot updates
|
||||
Changes in JS theme files _are not subject of hot updates_ during development. This applies to styles that comes from SASS files (which means 100% until we introduce css in js approach). This is a consequence of the fact that `getThemeVariable` util is executed during webpack pipeline.
|
||||
- #### You must ensure ThemeContext provider is available in a React tree
|
||||
By default all react2angular directives have `ThemeContext.Provider` ensured. But, there are cases where we create another React tree via `ReactDOM.render`. This happens in case of graph legend rendering and `ReactContainer` directive. In such cases theme consumption will fail. To make sure theme context is available in such cases, you need to wrap your rendered component with ThemeContext.Provider using `provideTheme` function:
|
||||
|
||||
```typescript
|
||||
// graph.ts
|
||||
import { provideTheme } from 'app/core/utils/ConfigProvider';
|
||||
|
||||
// Create component with ThemeContext.Provider first.
|
||||
// Otherwise React will create new components every time it renders!
|
||||
const LegendWithThemeProvider = provideTheme(Legend);
|
||||
|
||||
const legendReactElem = React.createElement(LegendWithThemeProvider, legendProps);
|
||||
ReactDOM.render(legendReactElem, this.legendElem, () => this.renderPanel());
|
||||
```
|
||||
|
||||
`provideTheme` makes current theme available via ThemeContext by checking if user has `lightTheme` set in her boot data.
|
Loading…
Reference in New Issue
Block a user