mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 12:44:10 -06:00
183 lines
7.8 KiB
Markdown
183 lines
7.8 KiB
Markdown
# Storybook
|
||
|
||
[Storybook](https://storybook.js.org/) is a tool which we use to manage our design system and the components which are a part of it. Storybook consists of _stories:_ each story represents a component and a case in which it is used. To show a wide variety of use cases is good both documentation wise and for troubleshooting -- it might be possible to reproduce a bug for an edge case in a story.
|
||
|
||
Storybook is:
|
||
|
||
- A good way to publish our design system with its implementations
|
||
- Used as a tool for documentation
|
||
- Used for debugging and displaying edge cases
|
||
|
||
## How to create stories
|
||
|
||
Stories for a component should be placed next to the component file. The Storybook file requires the same name as the component file. For example, a story for `SomeComponent.tsx` will have the file name `SomeComponent.story.tsx`. If a story should be internal, not visible in production, name the file `SomeComponent.story.internal.tsx`.
|
||
|
||
### Writing stories
|
||
|
||
When writing stories, we use the [CSF format](https://storybook.js.org/docs/formats/component-story-format/). For more in-depth information on writing stories, see [Storybook’s documentation on writing stories](https://storybook.js.org/docs/basics/writing-stories/).
|
||
|
||
With the CSF format, the default export defines some general information about the stories in the file:
|
||
|
||
- `title`: Where the component is going to live in the hierarchy
|
||
- `decorators`: A list which can contain wrappers or provide context, such as theming
|
||
|
||
```jsx
|
||
// In MyComponent.story.tsx
|
||
|
||
import MyComponent from './MyComponent';
|
||
|
||
export default {
|
||
title: 'General/MyComponent',
|
||
component: MyComponent,
|
||
decorators: [ ... ],
|
||
}
|
||
|
||
```
|
||
|
||
When it comes to writing the actual stories, you continue in the same file with named exports. The exports are turned into the story name.
|
||
|
||
```jsx
|
||
// Will produce a story name “some story”
|
||
export const someStory = () => <MyComponent />;
|
||
```
|
||
|
||
If you want to write cover cases with different values for props, then using knobs is usually enough. You don’t need to create a new story. This will be covered further down.
|
||
|
||
### Categorization
|
||
|
||
We currently have these categories:
|
||
|
||
- **Docs Overview** - Guidelines and information regarding the design system
|
||
- **Forms** - Components commonly used in forms such as different kind of inputs
|
||
- **General** - Components which can be used in a lot of different places
|
||
- **Visualizations** - Data visualizations
|
||
- **Panel** - Components belonging to panels and panel editors
|
||
|
||
## Writing MDX documentation
|
||
|
||
An MDX file is basically a markdown file with the possibility to add jsx. These files are used by Storybook to create a “docs” tab.
|
||
|
||
### Link the MDX file to a component’s stories
|
||
|
||
To link a component’s stories with an MDX file you have to do this:
|
||
|
||
```jsx
|
||
// In TabsBar.story.tsx
|
||
|
||
import { TabsBar } from "./TabsBar";
|
||
|
||
// Import the MDX file
|
||
import mdx from "./TabsBar.mdx";
|
||
|
||
export default {
|
||
title: "General/Tabs/TabsBar",
|
||
component: TabsBar,
|
||
parameters: {
|
||
docs: {
|
||
// This is the reference required for the MDX file
|
||
page: mdx,
|
||
},
|
||
},
|
||
};
|
||
```
|
||
|
||
### MDX file structure
|
||
|
||
There are some things that the MDX file should contain:
|
||
|
||
- When and why the component should be used
|
||
- Best practices - dos and don’ts for the component
|
||
- Usage examples with code. It is possible to use the `Preview` element to show live examples in MDX
|
||
- Props table. This can be generated by doing the following:
|
||
|
||
```jsx
|
||
// In MyComponent.mdx
|
||
|
||
import { Props } from "@storybook/addon-docs/blocks";
|
||
import { MyComponent } from "./MyComponent";
|
||
|
||
<Props of={MyComponent} />;
|
||
```
|
||
|
||
### MDX file without a relationship to a component
|
||
|
||
An MDX file can exist by itself without any connection to a story. This can be good for writing things such as a general guidelines page. Two things are required for this to work:
|
||
|
||
- The file needs to be named `*.story.mdx`
|
||
- A `Meta` tag must exist that says where in the hierarchy the component lives. It can look like this:
|
||
|
||
```jsx
|
||
<Meta title="Docs Overview/Color Palettes"/>
|
||
|
||
# Guidelines for using colors
|
||
|
||
...
|
||
|
||
```
|
||
|
||
You can add parameters to the Meta tag. This example shows how to hide the tools:
|
||
|
||
```jsx
|
||
<Meta title="Docs Overview/Color Palettes" parameters={{ options: { isToolshown: false }}}/>
|
||
|
||
# Guidelines for using colors
|
||
|
||
...
|
||
|
||
```
|
||
|
||
## Documenting component properties
|
||
|
||
A quick way to get an overview of what a component does is by looking at its properties. That's why it is important that we document these in a good way.
|
||
|
||
### Comments
|
||
|
||
When writing the props interface for a component, it is possible to add a comment to that specific property, which will end up in the Props table in the MDX file. The comments are generated by [react-docgen](https://github.com/reactjs/react-docgen) and are formatted by writing `/** */`.
|
||
|
||
```jsx
|
||
interface MyProps {
|
||
/** Sets the initial values, which are overridden when the query returns a value*/
|
||
defaultValues: Array<T>;
|
||
}
|
||
```
|
||
|
||
### Knobs
|
||
|
||
Knobs is an [addon to Storybook](https://github.com/storybookjs/storybook/tree/master/addons/knobs) which can be used to easily switch values in the UI. A good use case for it is to try different props for the component. Using knobs is easy. Grafana is set up so knobs can be used straight out of the box. Here is an example of how you might use it.
|
||
|
||
```jsx
|
||
// In MyComponent.story.tsx
|
||
|
||
import { number, text } from "@storybook/addon-knobs";
|
||
|
||
export const basicStory = () => (
|
||
<MyComponent
|
||
max={number("Max value", 10)}
|
||
min={number("Min value", -10)}
|
||
title={text("Title", "Look at the value!")}
|
||
/>
|
||
);
|
||
```
|
||
|
||
The general convention is that the first parameter of the knob is its name and the second is the default value. There are some more types:
|
||
|
||
| Knob | Description |
|
||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||
| `text` | Any text field |
|
||
| `number` | Any number input. Also [available as range](https://github.com/storybookjs/storybook/tree/master/addons/knobs#number-bound-by-range) |
|
||
| `boolean` | A switch between true/false |
|
||
| `color` | Color picker |
|
||
| `object` | JSON input or array. Good to use if the property requires more complex data structures. |
|
||
| `array` | Array of strings separated by a comma |
|
||
| `select` | Select a value from an options object. Good for trying different test cases. |
|
||
| `options` | Configurable UI for selecting a range of options |
|
||
| `files` | File selector |
|
||
| `date` | Select date as stringified Unix timestamp |
|
||
| `button` | Has a handler which is called when clicked |
|
||
|
||
## Best practices
|
||
|
||
- When creating a new component or writing documentation for an existing one, always cover the basic use case it was intended for with a code example.
|
||
- Use stories and knobs to create edge cases. If you are trying to solve a bug, try to reproduce it with a story.
|
||
- Do not create stories in the MDX, always create them in the `*.story.tsx` file.
|