mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-09 00:19:13 +08:00
Merge pull request #11842 from storybookjs/chore_add_configure_snippets
Chore add snippets for configure section for 6.0
This commit is contained in:
commit
e975e25569
@ -5,16 +5,27 @@ title: 'Environment variables'
|
||||
You can use environment variables in Storybook to change its behaviour in different “modes”.
|
||||
If you supply an environment variable prefixed with `STORYBOOK_`, it will be available in `process.env`:
|
||||
|
||||
```sh
|
||||
STORYBOOK_THEME=red STORYBOOK_DATA_KEY=12345 npm run storybook
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-set-environment-variables.sh.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Then we can access these environment variables anywhere inside our preview JavaScript code like below:
|
||||
|
||||
```js
|
||||
console.log(process.env.STORYBOOK_THEME);
|
||||
console.log(process.env.STORYBOOK_DATA_KEY);
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-read-environment-variables.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
You can also access these variables in your custom `<head>`/`<body>` using the substitution `%STORYBOOK_X%`, for example: `%STORYBOOK_THEME%` will become `red`.
|
||||
|
||||
|
@ -4,23 +4,16 @@ title: 'Features and behavior'
|
||||
|
||||
To control the layout of Storybook’s UI you can use the `setConfig` addons API in your [`.storybook/manager.js`](./overview.md#configure-story-rendering):
|
||||
|
||||
```js
|
||||
import { addons } from '@storybook/addons';
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-config-layout.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
addons.setConfig({
|
||||
isFullscreen: false,
|
||||
showNav: true,
|
||||
showPanel: true,
|
||||
panelPosition: 'bottom',
|
||||
sidebarAnimations: true,
|
||||
enableShortcuts: true,
|
||||
isToolshown: true,
|
||||
theme: undefined,
|
||||
selectedPanel: undefined,
|
||||
initialActive: 'sidebar',
|
||||
showRoots: false,
|
||||
});
|
||||
```
|
||||
The following table details how to use the API values:
|
||||
|
||||
| Name | Type | Description | Example Value |
|
||||
|
@ -18,25 +18,42 @@ By default, Storybook's webpack configuration will allow you to:
|
||||
|
||||
You can import images and other local files and have them built into the Storybook:
|
||||
|
||||
```js
|
||||
// This will include './static/image.png' in the bundle and return a path to be included in a src attribute
|
||||
import imageFile from './static/image.png';
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/my-component-story-import-static-asset.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
- Import JSON as JavaScript
|
||||
|
||||
You can import `.json` files and have them expanded to a JavaScript object:
|
||||
|
||||
```js
|
||||
// This will automatically be parsed to the contents of `data.json`
|
||||
import data from './data.json';
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/my-component-story-import-json.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
If you want to know the exact details of the webpack config, the best way is to run:
|
||||
|
||||
```sh
|
||||
yarn storybook --debug-webpack
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-run-webpack-config.sh.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
### Extending Storybook’s webpack config
|
||||
|
||||
@ -46,30 +63,15 @@ The value should export a `function`, which will receive the default config as i
|
||||
|
||||
For example, here's a `.storybook/main.js` to add [Sass](https://sass-lang.com/) support:
|
||||
|
||||
```js
|
||||
// .storybook/main.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
const path = require('path');
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-main-add-sass-config.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
// Export a function. Accept the base config as the only param.
|
||||
module.exports = {
|
||||
webpackFinal: async (config, { configType }) => {
|
||||
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||
// You can change the configuration based on that.
|
||||
// 'PRODUCTION' is used when building the static version of storybook.
|
||||
|
||||
// Make whatever fine-grained changes you need
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
include: path.resolve(__dirname, '../'),
|
||||
});
|
||||
|
||||
// Return the altered config
|
||||
return config;
|
||||
},
|
||||
};
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Storybook uses the config returned from the above function to render your components in Storybook's "preview" iframe. Note that Storybook has a completely separate webpack config for its own UI (also referred to as the "manager"), so the customizations you make only applies to the rendering of your stories, i.e. you can completely replace `config.module.rules` if you want.
|
||||
|
||||
@ -80,14 +82,15 @@ Nevertheless, edit `config` with care. Make sure to preserve the following confi
|
||||
|
||||
Furthermore, `config` requires the `HtmlWebpackplugin` to generate the preview page, so rather than overwriting `config.plugins` you should probably append to it (or overwrite it with care), see [the following issue](https://github.com/storybookjs/storybook/issues/6020) for examples on how to handle this:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
webpackFinal: (config) => {
|
||||
config.plugins.push(...);
|
||||
return config;
|
||||
},
|
||||
}
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-main-simplified-config.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Finally, if your custom webpack config uses a loader that does not explicitly include specific file extensions via the `test` property, it is necessary to `exclude` the `.ejs` file extension from that loader.
|
||||
|
||||
@ -99,19 +102,15 @@ If you have an existing webpack config for your project and want to reuse this a
|
||||
|
||||
The following code snippet shows how you can replace the loaders from Storybook with the ones from your app's `webpack.config.js`:
|
||||
|
||||
```js
|
||||
// .storybook/main.js
|
||||
const path = require('path');
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
// your app's webpack.config.js
|
||||
const custom = require('../webpack.config.js');
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-main-using-existing-config.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
module.exports = {
|
||||
webpackFinal: (config) => {
|
||||
return { ...config, module: { ...config.module, rules: custom.module.rules } };
|
||||
},
|
||||
};
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Babel
|
||||
|
||||
@ -153,20 +152,15 @@ To make it easier to configure Typescript handling, use the `typescript` field i
|
||||
|
||||
The following code snippets shows the fields for you to use with TypeScript:
|
||||
|
||||
```js
|
||||
// .storybook/main.js
|
||||
module.exports = {
|
||||
typescript: {
|
||||
check: false,
|
||||
checkOptions: {},
|
||||
reactDocgen: 'react-docgen-typescript',
|
||||
reactDocgenTypescriptOptions: {
|
||||
shouldExtractLiteralValuesFromEnum: true,
|
||||
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-main-add-ts-config.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
| Field | Framework | Description | Type |
|
||||
| :------------------------------- | :-------: | :--------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------: |
|
||||
@ -189,11 +183,19 @@ If your component files import their own CSS, Storybook’s webpack config will
|
||||
|
||||
- If you are using a CSS precompiler, you may need to add a preset (such as the [SCSS preset](https://github.com/storybookjs/presets/tree/master/packages/preset-scss), or add a loader to Storybook’s webpack config).
|
||||
- In Angular, you'll need to take special care how you handle CSS:
|
||||
- Either [customize your webpack config](#extending-storybooks-webpack-config)
|
||||
- Or use syntax to use a inline loader:
|
||||
```js
|
||||
import '!style-loader!css-loader!./styles.css';
|
||||
```
|
||||
|
||||
- Either [customize your webpack config](#extending-storybooks-webpack-config)
|
||||
- Or use syntax to use a inline loader:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'angular/storybook-angular-inline-css-loader.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
To use your CSS in all stories, you simply import it in [`.storybook/preview.js`](./overview.md#configure-story-rendering)
|
||||
|
||||
@ -211,23 +213,15 @@ You can import any media assets by importing (or requiring) them. This works out
|
||||
|
||||
Afterwards you can use any asset in your stories:
|
||||
|
||||
```js
|
||||
// your-story-with-assets.story.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import React from 'react';
|
||||
import imageFile from './static/image.png';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'react/component-story-static-asset-with-import.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export default {
|
||||
title: 'img',
|
||||
};
|
||||
|
||||
const image = {
|
||||
src: imageFile,
|
||||
alt: 'my image',
|
||||
};
|
||||
|
||||
export const withAnImage = () => <img src={image.src} alt={image.alt} />;
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
### Serving static files via Storybook
|
||||
|
||||
@ -235,57 +229,54 @@ We recommend serving static files via Storybook to ensure that your components a
|
||||
|
||||
Configure a directory (or a list of directories) where your assets live when starting Storybook. Use the`-s` flag in your npm script like so:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start-storybook": "start-storybook -s ./public -p 9001"
|
||||
}
|
||||
}
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-serve-static-assets-script.json.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Here `./public` is your static directory. Now use it in a component or story like this.
|
||||
|
||||
```js
|
||||
// your-story-with-asset.story.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import React from 'react';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'react/component-story-static-asset-without-import.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export default {
|
||||
title: 'img',
|
||||
};
|
||||
|
||||
// assume image.png is located in the "public" directory.
|
||||
export const withAnImage = () => <img src="/image.png" alt="my image" />;
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
You can also pass a list of directories separated by commas without spaces instead of a single directory.
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start-storybook": "start-storybook -s ./public,./static -p 9001"
|
||||
}
|
||||
}
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-serve-static-assets-script-multifolder.json.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
### Reference assets from a CDN
|
||||
|
||||
Upload your files to an online CDN and reference them. In this example we’re using a placeholder image service.
|
||||
|
||||
```js
|
||||
// your-story-with-CDN-asset.story.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import React from 'react';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'react/component-story-static-asset-cdn.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export default {
|
||||
title: 'img',
|
||||
};
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
// assume image.png is located in the "public" directory.
|
||||
export const withAnImage = () => (
|
||||
<img src="https://placehold.it/350x150" alt="My CDN placeholder" />
|
||||
);
|
||||
```
|
||||
|
||||
### Absolute versus relative paths
|
||||
|
||||
|
@ -14,14 +14,15 @@ Note you can change the folder that Storybook uses by setting the `-c` flag to y
|
||||
|
||||
The main configuration file is `main.js`. This file controls the behaviour of the Storybook server, and so you must restart Storybook’s process when you change it. It contains the following:
|
||||
|
||||
```js
|
||||
// .storybook/main.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
module.exports = {
|
||||
stories: ['../src/**/*.stories.(js|mdx)'],
|
||||
addons: ['@storybook/addon-essentials'],
|
||||
};
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-main-default-setup.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
The `main.js` configuration file is a [preset](../api/presets.md) and as such has a powerful interface, but the key fields within it are:
|
||||
|
||||
@ -45,13 +46,15 @@ If you want to use a different naming convention, you can alter the glob, using
|
||||
|
||||
For example if you wanted to pull both `.md` and `.js` files from the `my-project/src/components` directory, you could write:
|
||||
|
||||
```js
|
||||
// .storybook/main.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
module.exports = {
|
||||
stories: ['../my-project/src/components/*.@(js|md)'],
|
||||
};
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-main-js-md-files.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Configure story rendering
|
||||
|
||||
|
@ -16,23 +16,31 @@ By default, Storybook will treat your highest level of groups as “roots”--wh
|
||||
|
||||
If you’d prefer all groups to be expandable, you can set the `showRoots` option to `false` in [`./storybook/manager.js`](./overview.md#configure-story-rendering):
|
||||
|
||||
```js
|
||||
// ./storybook/manager.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import { addons } from `@storybook/addons`;
|
||||
addons.setConfig({ showRoots: false });
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-manager-disable-roots.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Generating titles based on `__dirname`
|
||||
|
||||
As a CSF file is a JavaScript file, the exports (including the default export) can be generated dynamically. In particular you can use the `__dirname` variable to generate the title based on the path name (this example uses the paths.macro):
|
||||
|
||||
```js
|
||||
import base from 'paths.macro';
|
||||
export default {
|
||||
title: `${base}/Component`,
|
||||
};
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/component-story-dynamic-title.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
|
||||
## Permalinking to stories
|
||||
|
||||
@ -40,30 +48,28 @@ By default, Storybook generates an `id` for each story based on the component ti
|
||||
|
||||
Consider the following story:
|
||||
|
||||
```js
|
||||
// your-story.story.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
export default {
|
||||
title: 'Foo/Bar',
|
||||
};
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/foo-bar-baz-story.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export const Baz = BarStory.bind({});
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Storybook's ID-generation logic will give this the `id` `foo-bar--baz`, so the link would be `?path=/story/foo-bar--baz`.
|
||||
|
||||
It is possible to manually set the id of a story, which in particular is useful if you want to rename stories without breaking permalinks. Suppose you want to change the position in the hierarchy to `OtherFoo/Bar` and the story name to `Moo`. Here's how to do that:
|
||||
|
||||
```js
|
||||
// your-story.story.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
export default {
|
||||
title: 'OtherFoo/Bar',
|
||||
id: 'Foo/Bar', // or 'foo-bar' if you prefer
|
||||
};
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/other-foo-bar-story.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export const Baz = () => BarStory.bind({});
|
||||
Baz.storyName = 'Moo';
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Storybook will prioritize the `id` over the title for ID generation, if provided, and will prioritize the `story.name` over the export key for display.
|
||||
|
@ -8,19 +8,16 @@ In Storybook, your stories render in a special “preview” iframe (Canvas tab)
|
||||
|
||||
If you need to add extra elements to the `head` of the preview iframe, for instance to load static stylesheets, font files, or similar, you can create a file called [`.storybook/preview-head.html`](./overview.md#configure-story-rendering) and add tags like this:
|
||||
|
||||
```html
|
||||
<!-- .storybook/preview-head.html -->
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-head-example.html.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- Pull in static files served from your Static director or the internet -->
|
||||
<link rel=”preload” href=”your/font” />
|
||||
<!-- Or you can load custom head-tag JavaScript: -->
|
||||
<script src="https://use.typekit.net/xxxyyy.js"></script>
|
||||
<script>
|
||||
try {
|
||||
Typekit.load();
|
||||
} catch (e) {}
|
||||
</script>
|
||||
```
|
||||
|
||||
<div class="aside">
|
||||
|
||||
@ -34,20 +31,27 @@ Sometimes, you may need to add different tags to the `<body>`. This is useful fo
|
||||
|
||||
You can accomplish this by creating a file called `preview-body.html` inside your `.storybook` directory and add tags like this:
|
||||
|
||||
```html
|
||||
<!-- .storybook/preview-body.html -->
|
||||
<div id="custom-root"></div>
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-body-example.html.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
If using relative sizing in your project (like `rem` or `em`), you may update the base `font-size` by adding a `style` tag to `preview-body.html`:
|
||||
|
||||
```html
|
||||
<style>
|
||||
body {
|
||||
font-size: 15px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-body-font-size.html.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<div class="aside">
|
||||
|
||||
|
@ -12,22 +12,27 @@ Storybook includes two themes that look good out of the box: "normal" (a light t
|
||||
|
||||
Make sure you have installed [`@storybook/addons`](https://www.npmjs.com/package/@storybook/addons) and [`@storybook/theming`](https://www.npmjs.com/package/@storybook/theming) packages.
|
||||
|
||||
```sh
|
||||
npm install @storybook/addons --save-dev
|
||||
npm install @storybook/theming --save-dev
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-install-theme-packages.sh.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
As an example, you can tell Storybook to use the "dark" theme by modifying [`.storybook/manager.js`](./overview.md#configure-story-rendering):
|
||||
|
||||
```js
|
||||
// .storybook/manager.js
|
||||
import { addons } from '@storybook/addons';
|
||||
import { themes } from '@storybook/theming';
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
addons.setConfig({
|
||||
theme: themes.dark,
|
||||
});
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-manager-dark-theme.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
When setting a theme, set a full theme object. The theme is replaced, not combined.
|
||||
|
||||
@ -37,30 +42,27 @@ When setting a theme, set a full theme object. The theme is replaced, not combin
|
||||
|
||||
Supposing you have a Storybook theme defined for the main UI in [`.storybook/manager.js`](./overview.md#configure-story-rendering):
|
||||
|
||||
```js
|
||||
// .storybook/manager.js
|
||||
import { addons } from '@storybook/addons';
|
||||
// or a custom theme
|
||||
import { themes } from '@storybook/theming';
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
addons.setConfig({
|
||||
theme: themes.dark,
|
||||
});
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-manager-dark-theme.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Here's how you'd specify the same theme for docs in [`.storybook/preview.js`](./overview.md#configure-story-rendering):
|
||||
|
||||
```js
|
||||
// .storybook/preview.js
|
||||
import { themes } from '@storybook/theming';
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
// or global addParameters
|
||||
export const parameters = {
|
||||
docs: {
|
||||
theme: themes.dark,
|
||||
},
|
||||
};
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-docs-dark-theme.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Continue to read if you want to learn how to create your theme.
|
||||
|
||||
@ -72,75 +74,41 @@ First create a new file in `.storybook` called `yourTheme.js`.
|
||||
|
||||
Next paste the code below and tweak the variables.
|
||||
|
||||
```js
|
||||
// yourTheme.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import { create } from '@storybook/theming/create';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/your-theme.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export default create({
|
||||
base: 'light',
|
||||
|
||||
colorPrimary: 'hotpink',
|
||||
colorSecondary: 'deepskyblue',
|
||||
|
||||
// UI
|
||||
appBg: 'white',
|
||||
appContentBg: 'silver',
|
||||
appBorderColor: 'grey',
|
||||
appBorderRadius: 4,
|
||||
|
||||
// Typography
|
||||
fontBase: '"Open Sans", sans-serif',
|
||||
fontCode: 'monospace',
|
||||
|
||||
// Text colors
|
||||
textColor: 'black',
|
||||
textInverseColor: 'rgba(255,255,255,0.9)',
|
||||
|
||||
// Toolbar default and active colors
|
||||
barTextColor: 'silver',
|
||||
barSelectedColor: 'black',
|
||||
barBg: 'hotpink',
|
||||
|
||||
// Form colors
|
||||
inputBg: 'white',
|
||||
inputBorder: 'silver',
|
||||
inputTextColor: 'black',
|
||||
inputBorderRadius: 4,
|
||||
|
||||
brandTitle: 'My custom storybook',
|
||||
brandUrl: 'https://example.com',
|
||||
brandImage: 'https://placehold.it/350x150',
|
||||
});
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Finally, import your theme into [`.storybook/manager.js`](./overview.md#configure-story-rendering) and add it to your Storybook parameters.
|
||||
|
||||
```js
|
||||
// .storybook/manager.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import { addons } from '@storybook/addons';
|
||||
import yourTheme from './yourTheme';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-manager-custom-theme.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
addons.setConfig({
|
||||
theme: yourTheme,
|
||||
});
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
The `@storybook/theming` package is built using TypeScript, so this should help create a valid theme for TypeScript users. The types are part of the package itself.
|
||||
|
||||
Many theme variables are optional, the `base` property is NOT. This is a perfectly valid theme:
|
||||
|
||||
```ts
|
||||
import { create } from '@storybook/theming/create';
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
export default create({
|
||||
base: 'light',
|
||||
brandTitle: 'My custom storybook',
|
||||
brandUrl: 'https://example.com',
|
||||
brandImage: 'https://placehold.it/350x150',
|
||||
});
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-theme-example-variables.ts.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## CSS escape hatches
|
||||
|
||||
@ -165,37 +133,29 @@ If you're using MDX for docs, there's one more level of themability. MDX allows
|
||||
|
||||
Here's how you might insert a custom code renderer for `code` blocks on the page, in [`.storybook/preview.js`](./overview.md#configure-story-rendering):
|
||||
|
||||
```js
|
||||
// .storybook/preview.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import { CodeBlock } from './CodeBlock';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-custom-code-renderer.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export const parameters = {
|
||||
docs: {
|
||||
components: {
|
||||
code: CodeBlock,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
You can even override a Storybook block component.
|
||||
|
||||
Here's how you might insert a custom `<Preview />` block:
|
||||
Here's how you might insert a custom `<Canvas />` block:
|
||||
|
||||
```js
|
||||
// .storybook/preview.js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
import { MyPreview } from './MyPreview';
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-custom-canvas.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
export const parameters = {
|
||||
docs: {
|
||||
components: {
|
||||
Preview: MyPreview,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Addons and theme creation
|
||||
|
||||
@ -203,37 +163,50 @@ Some addons require specific theme variables that a Storybook user must add. If
|
||||
|
||||
For example, the popular Actions addon uses [react-inspector](https://github.com/xyc/react-inspector/blob/master/src/styles/themes/chromeLight.js) which has themes of its own. Supply additional theme variables to style it like so:
|
||||
|
||||
```js
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
addonActionsTheme: {
|
||||
...chromeLight,
|
||||
BASE_FONT_FAMILY: typography.fonts.mono,
|
||||
BASE_BACKGROUND_COLOR: 'transparent',
|
||||
}
|
||||
```
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-preview-extended-theme-variables.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Using the theme for addon authors
|
||||
|
||||
Reuse the theme variables above for a native Storybook developer experience. The theming engine relies on [emotion](https://emotion.sh/), a CSS-in-JS library.
|
||||
|
||||
```js
|
||||
import { styled } from '@storybook/theming';
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/storybook-theming-styled-import.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Use the theme variables in object notation:
|
||||
|
||||
```js
|
||||
const Component = styled.div(({ theme }) => ({
|
||||
background: theme.background.app,
|
||||
width: 0,
|
||||
}));
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'react/component-styled-variables-object-notation.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Or with template literals:
|
||||
|
||||
```js
|
||||
const Component = styled.div`
|
||||
background: `${props => props.theme.background.app}`
|
||||
width: 0;
|
||||
`;
|
||||
```
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'react/component-styled-variables-template-literals.js.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
@ -0,0 +1,3 @@
|
||||
```js
|
||||
import '!style-loader!css-loader!./styles.css';
|
||||
```
|
@ -0,0 +1,8 @@
|
||||
```js
|
||||
// MyComponent.stories.js
|
||||
|
||||
import base from 'paths.macro';
|
||||
export default {
|
||||
title: `${base}/Component`
|
||||
}
|
||||
```
|
9
docs/snippets/common/foo-bar-baz-story.js.mdx
Normal file
9
docs/snippets/common/foo-bar-baz-story.js.mdx
Normal file
@ -0,0 +1,9 @@
|
||||
```js
|
||||
// Foo-Bar.stories.js
|
||||
|
||||
export default {
|
||||
title: 'Foo/Bar',
|
||||
};
|
||||
|
||||
export const Baz = BarStory.bind({});
|
||||
```
|
@ -0,0 +1,4 @@
|
||||
```js
|
||||
// This will automatically be parsed to the contents of `data.json`
|
||||
import data from './data.json';
|
||||
```
|
@ -0,0 +1,5 @@
|
||||
```js
|
||||
// This will include './static/image.png' in the bundle.
|
||||
// And return a path to be included in a src attribute
|
||||
import imageFile from './static/image.png';
|
||||
```
|
11
docs/snippets/common/other-foo-bar-story.js.mdx
Normal file
11
docs/snippets/common/other-foo-bar-story.js.mdx
Normal file
@ -0,0 +1,11 @@
|
||||
```js
|
||||
// your-story.story.js
|
||||
|
||||
export default {
|
||||
title: 'OtherFoo/Bar',
|
||||
id: 'Foo/Bar', // or 'foo-bar' if you prefer
|
||||
};
|
||||
|
||||
export const Baz = () => BarStory.bind({});
|
||||
Baz.storyName = 'Moo';
|
||||
```
|
19
docs/snippets/common/storybook-config-layout.js.mdx
Normal file
19
docs/snippets/common/storybook-config-layout.js.mdx
Normal file
@ -0,0 +1,19 @@
|
||||
```js
|
||||
// .storybook/manager.js
|
||||
|
||||
import { addons } from '@storybook/addons';
|
||||
|
||||
addons.setConfig({
|
||||
isFullscreen: false,
|
||||
showNav: true,
|
||||
showPanel: true,
|
||||
panelPosition: 'bottom',
|
||||
sidebarAnimations: true,
|
||||
enableShortcuts: true,
|
||||
isToolshown: true,
|
||||
theme: undefined,
|
||||
selectedPanel: undefined,
|
||||
initialActive: 'sidebar',
|
||||
showRoots: false,
|
||||
});
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
```sh
|
||||
npm install @storybook/addons @storybook/theming --save-dev
|
||||
```
|
24
docs/snippets/common/storybook-main-add-sass-config.js.mdx
Normal file
24
docs/snippets/common/storybook-main-add-sass-config.js.mdx
Normal file
@ -0,0 +1,24 @@
|
||||
```js
|
||||
// .storybook/main.js
|
||||
|
||||
const path = require('path');
|
||||
|
||||
// Export a function. Accept the base config as the only param.
|
||||
module.exports = {
|
||||
webpackFinal: async (config, { configType }) => {
|
||||
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||
// You can change the configuration based on that.
|
||||
// 'PRODUCTION' is used when building the static version of storybook.
|
||||
|
||||
// Make whatever fine-grained changes you need
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
include: path.resolve(__dirname, '../'),
|
||||
});
|
||||
|
||||
// Return the altered config
|
||||
return config;
|
||||
},
|
||||
};
|
||||
```
|
15
docs/snippets/common/storybook-main-add-ts-config.js.mdx
Normal file
15
docs/snippets/common/storybook-main-add-ts-config.js.mdx
Normal file
@ -0,0 +1,15 @@
|
||||
```js
|
||||
// .storybook/main.js
|
||||
|
||||
module.exports = {
|
||||
typescript: {
|
||||
check: false,
|
||||
checkOptions: {},
|
||||
reactDocgen: 'react-docgen-typescript',
|
||||
reactDocgenTypescriptOptions: {
|
||||
shouldExtractLiteralValuesFromEnum: true,
|
||||
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
8
docs/snippets/common/storybook-main-default-setup.js.mdx
Normal file
8
docs/snippets/common/storybook-main-default-setup.js.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
```js
|
||||
// .storybook/main.js
|
||||
|
||||
module.exports = {
|
||||
stories: ['../src/**/*.stories.(js|mdx)'],
|
||||
addons: ['@storybook/addon-essentials']
|
||||
}
|
||||
```
|
8
docs/snippets/common/storybook-main-js-md-files.js.mdx
Normal file
8
docs/snippets/common/storybook-main-js-md-files.js.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
```js
|
||||
// .storybook/main.js
|
||||
|
||||
module.exports = {
|
||||
stories: ['../my-project/src/components/*.@(js|md)'],
|
||||
};
|
||||
|
||||
```
|
10
docs/snippets/common/storybook-main-simplified-config.js.mdx
Normal file
10
docs/snippets/common/storybook-main-simplified-config.js.mdx
Normal file
@ -0,0 +1,10 @@
|
||||
```js
|
||||
./storybook/main.js
|
||||
|
||||
module.exports = {
|
||||
webpackFinal: (config) => {
|
||||
config.plugins.push(...);
|
||||
return config;
|
||||
},
|
||||
}
|
||||
```
|
@ -0,0 +1,14 @@
|
||||
```js
|
||||
// .storybook/main.js
|
||||
|
||||
const path = require('path');
|
||||
|
||||
// your app's webpack.config.js
|
||||
const custom = require('../webpack.config.js');
|
||||
|
||||
module.exports = {
|
||||
webpackFinal: (config) => {
|
||||
return { ...config, module: { ...config.module, rules: custom.module.rules } };
|
||||
},
|
||||
};
|
||||
```
|
10
docs/snippets/common/storybook-manager-custom-theme.js.mdx
Normal file
10
docs/snippets/common/storybook-manager-custom-theme.js.mdx
Normal file
@ -0,0 +1,10 @@
|
||||
```js
|
||||
// .storybook/manager.js
|
||||
|
||||
import { addons } from '@storybook/addons';
|
||||
import yourTheme from './yourTheme';
|
||||
|
||||
addons.setConfig({
|
||||
theme: yourTheme,
|
||||
});
|
||||
```
|
10
docs/snippets/common/storybook-manager-dark-theme.js.mdx
Normal file
10
docs/snippets/common/storybook-manager-dark-theme.js.mdx
Normal file
@ -0,0 +1,10 @@
|
||||
```js
|
||||
// .storybook/manager.js
|
||||
|
||||
import { addons } from '@storybook/addons';
|
||||
import { themes } from '@storybook/theming';
|
||||
|
||||
addons.setConfig({
|
||||
theme: themes.dark,
|
||||
});
|
||||
```
|
@ -0,0 +1,6 @@
|
||||
```js
|
||||
// ./storybook/manager.js
|
||||
|
||||
import { addons } from `@storybook/addons`;
|
||||
addons.setConfig({ showRoots: false });
|
||||
```
|
@ -0,0 +1,4 @@
|
||||
```html
|
||||
<!-- .storybook/preview-body.html -->
|
||||
<div id="custom-root"></div>
|
||||
```
|
@ -0,0 +1,8 @@
|
||||
```html
|
||||
<!-- .storybook/preview-body.html -->
|
||||
<style>
|
||||
body {
|
||||
font-size: 15px;
|
||||
}
|
||||
</style>
|
||||
```
|
13
docs/snippets/common/storybook-preview-custom-canvas.js.mdx
Normal file
13
docs/snippets/common/storybook-preview-custom-canvas.js.mdx
Normal file
@ -0,0 +1,13 @@
|
||||
```js
|
||||
// .storybook/preview.js
|
||||
|
||||
import { MyCanvas } from './MyCanvas';
|
||||
|
||||
export const parameters = {
|
||||
docs: {
|
||||
components: {
|
||||
Canvas: MyCanvas,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
@ -0,0 +1,13 @@
|
||||
```js
|
||||
// .storybook/preview.js
|
||||
|
||||
import { CodeBlock } from './CodeBlock';
|
||||
|
||||
export const parameters = {
|
||||
docs: {
|
||||
components: {
|
||||
code: CodeBlock,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
@ -0,0 +1,11 @@
|
||||
```js
|
||||
// .storybook/preview.js
|
||||
import { themes } from '@storybook/theming';
|
||||
|
||||
// or global addParameters
|
||||
export const parameters = {
|
||||
docs: {
|
||||
theme: themes.dark,
|
||||
},
|
||||
};
|
||||
```
|
@ -0,0 +1,7 @@
|
||||
```js
|
||||
addonActionsTheme: {
|
||||
...chromeLight,
|
||||
BASE_FONT_FAMILY: typography.fonts.mono,
|
||||
BASE_BACKGROUND_COLOR: 'transparent',
|
||||
}
|
||||
```
|
10
docs/snippets/common/storybook-preview-head-example.html.mdx
Normal file
10
docs/snippets/common/storybook-preview-head-example.html.mdx
Normal file
@ -0,0 +1,10 @@
|
||||
```html
|
||||
<!-- .storybook/preview-head.html -->
|
||||
|
||||
<!-- Pull in static files served from your Static director or the internet -->
|
||||
<link rel=”preload” href=”your/font” />
|
||||
<!-- Or you can load custom head-tag JavaScript: -->
|
||||
<script src="https://use.typekit.net/xxxyyy.js"></script>
|
||||
<script>try{ Typekit.load(); } catch(e){ }</script>
|
||||
|
||||
```
|
@ -0,0 +1,4 @@
|
||||
```js
|
||||
console.log(process.env.STORYBOOK_THEME);
|
||||
console.log(process.env.STORYBOOK_DATA_KEY);
|
||||
```
|
3
docs/snippets/common/storybook-run-webpack-config.sh.mdx
Normal file
3
docs/snippets/common/storybook-run-webpack-config.sh.mdx
Normal file
@ -0,0 +1,3 @@
|
||||
```sh
|
||||
yarn storybook --debug-webpack
|
||||
```
|
@ -0,0 +1,7 @@
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start-storybook": "start-storybook -s ./public,./static -p 9001"
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,7 @@
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start-storybook": "start-storybook -s ./public -p 9001"
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
```sh
|
||||
STORYBOOK_THEME=red STORYBOOK_DATA_KEY=12345 npm run storybook
|
||||
```
|
@ -0,0 +1,11 @@
|
||||
```ts
|
||||
|
||||
import { create } from '@storybook/theming/create';
|
||||
|
||||
export default create({
|
||||
base: 'light',
|
||||
brandTitle: 'My custom storybook',
|
||||
brandUrl: 'https://example.com',
|
||||
brandImage: 'https://placehold.it/350x150',
|
||||
});
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
```js
|
||||
import { styled } from '@storybook/theming';
|
||||
```
|
41
docs/snippets/common/your-theme.js.mdx
Normal file
41
docs/snippets/common/your-theme.js.mdx
Normal file
@ -0,0 +1,41 @@
|
||||
```js
|
||||
// yourTheme.js
|
||||
|
||||
import { create } from '@storybook/theming/create';
|
||||
|
||||
export default create({
|
||||
base: 'light',
|
||||
|
||||
colorPrimary: 'hotpink',
|
||||
colorSecondary: 'deepskyblue',
|
||||
|
||||
// UI
|
||||
appBg: 'white',
|
||||
appContentBg: 'silver',
|
||||
appBorderColor: 'grey',
|
||||
appBorderRadius: 4,
|
||||
|
||||
// Typography
|
||||
fontBase: '"Open Sans", sans-serif',
|
||||
fontCode: 'monospace',
|
||||
|
||||
// Text colors
|
||||
textColor: 'black',
|
||||
textInverseColor: 'rgba(255,255,255,0.9)',
|
||||
|
||||
// Toolbar default and active colors
|
||||
barTextColor: 'silver',
|
||||
barSelectedColor: 'black',
|
||||
barBg: 'hotpink',
|
||||
|
||||
// Form colors
|
||||
inputBg: 'white',
|
||||
inputBorder: 'silver',
|
||||
inputTextColor: 'black',
|
||||
inputBorderRadius: 4,
|
||||
|
||||
brandTitle: 'My custom storybook',
|
||||
brandUrl: 'https://example.com',
|
||||
brandImage: 'https://placehold.it/350x150',
|
||||
});
|
||||
```
|
14
docs/snippets/react/component-story-static-asset-cdn.js.mdx
Normal file
14
docs/snippets/react/component-story-static-asset-cdn.js.mdx
Normal file
@ -0,0 +1,14 @@
|
||||
```js
|
||||
// MyComponent.stories.js
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default {
|
||||
title: 'img',
|
||||
};
|
||||
|
||||
// assume image.png is located in the "public" directory.
|
||||
export const withAnImage = () => (
|
||||
<img src="https://placehold.it/350x150" alt="My CDN placeholder" />
|
||||
);
|
||||
```
|
@ -0,0 +1,19 @@
|
||||
```js
|
||||
// MyComponent.stories.js
|
||||
|
||||
import React from 'react';
|
||||
import imageFile from './static/image.png';
|
||||
|
||||
export default {
|
||||
title: 'img',
|
||||
};
|
||||
|
||||
const image = {
|
||||
src: imageFile,
|
||||
alt: 'my image',
|
||||
};
|
||||
|
||||
export const withAnImage = () => (
|
||||
<img src={image.src} alt={image.alt} />
|
||||
);
|
||||
```
|
@ -0,0 +1,14 @@
|
||||
```js
|
||||
// MyComponent.stories.js
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default {
|
||||
title: 'img',
|
||||
};
|
||||
|
||||
// assume image.png is located in the "public" directory.
|
||||
export const withAnImage = () => (
|
||||
<img src="/image.png" alt="my image" />
|
||||
);
|
||||
```
|
@ -0,0 +1,8 @@
|
||||
```js
|
||||
// MyComponent.js
|
||||
|
||||
const Component = styled.div(({ theme }) => ({
|
||||
background: theme.background.app,
|
||||
width: 0,
|
||||
}));
|
||||
```
|
@ -0,0 +1,6 @@
|
||||
```js
|
||||
const Component = styled.div`
|
||||
background: `${props => props.theme.background.app}`
|
||||
width: 0;
|
||||
`;
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user