mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 19:30:36 -06:00
104 lines
3.7 KiB
Markdown
104 lines
3.7 KiB
Markdown
|
## 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.
|