Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tonai/storybook-addon-themes
https://github.com/tonai/storybook-addon-themes
addon storybook theme
Last synced: 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/tonai/storybook-addon-themes
- Owner: tonai
- License: mit
- Created: 2018-01-22T13:38:12.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2023-01-06T01:43:21.000Z (about 2 years ago)
- Last Synced: 2024-09-30T01:07:47.113Z (3 months ago)
- Topics: addon, storybook, theme
- Language: TypeScript
- Size: 623 KB
- Stars: 83
- Watchers: 5
- Forks: 30
- Open Issues: 22
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-ccamel - tonai/storybook-addon-themes - (TypeScript)
README
# Storybook Addon Themes
Greatly inspired by [@storybook/addon-backgrounds](https://github.com/storybooks/storybook/tree/next/addons/backgrounds).
This Storybook Theme Decorator can be used to add a custom HTML class or classes to the preview in [Storybook](https://storybook.js.org).
![Demo](media/demo.gif)
## Compatibility
This version is compatible with storybook version `6.0.x`.
## Installation
```sh
npm i -D storybook-addon-themes
```## Getting started
Then activate the addon by adding it to the storybook `main.js` file (located in the Storybook config directory):
```jsx
module.exports = {
addons: [
// Maybe other addons here...
'storybook-addon-themes'
// Or here...
],
};
```See the [storybook documentation](https://storybook.js.org/docs/addons/using-addons/) for more informations.
## Parameters
The `themes` parameter accept an array of `Theme` object.
Each `Theme` is an object with the following properties:
* `name` (`string`): Name of the theme
* `class` (`string | string[]` - optional): HTML class(es) associated with the theme
* `color` (`string`): The color of the badge in the theme selector
* `default` [_deprecated_] (`boolean` - optional): Is the theme selected by default?The `themes` parameter also accept an object with the following properties:
* `default` (`string` - optional): Name of theme selected by default
* `list` (`Theme[]` - required): The list of themes
* `clearable` (`boolean` - optional - default is `true`): Can the user clear the selected theme ?
* `disable` (`boolean` - optional): Disable the addon for a story
* `Decorator` (`Component` - optional): A component to use as the decorator component ([see below](#custom-decorator) for more information)
* `onChange` (`(themeName: Theme) => void` - optional): A callback that will be executed when the theme changes
* `target` (`string` - optional): Target element selected with `document.querySelector()` to which classes are applied. Defaults to `body`, `root` if classes should be applied to `documentElement`.## Configuration
### Globally
You can configure the themes globally in the storybook `preview.js` file:
```jsx
export const parameters = {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: 'theme-twt', color: '#00aced' },
{ name: 'facebook', class: 'theme-fb', color: '#3b5998' }
],
},
};
```For backward compatibility `default` (`boolean`) can also be set directly on `Theme` object.
**This has been deprecated** because of the difficulty of changing the default theme due to the need to redefine all `Theme` objects.```jsx
// deprecated
export const parameters = {
themes: [
{ name: 'twitter', class: 'theme-twt', color: '#00aced', default: true },
{ name: 'facebook', class: 'theme-fb', color: '#3b5998' }
],
};
```See the [storybook documentation](https://storybook.js.org/docs/addons/using-addons/#global-configuration) for more informations.
### In story (Component Story Format)
Or configure the themes in your story file like this:
```jsx
export default {
title: 'CSF|Button',
component: Button,
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
```If you only want to activate the addon or override the themes for a specific story you can write:
```jsx
export default {
title: 'CSF|Button',
component: Button,
};export const withText = () => Hello Button;
withText.story = {
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
```### In story (StoriesOf API)
Alternatively with the old StoriesOf API:
```jsx
import { storiesOf } from '@storybook/react'; // <- or your storybook frameworkstoriesOf('StoriesOf|Button', module)
.addParameters({
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
})
.add('with text', () => Click me);
```And for a single story:
```jsx
import { storiesOf } from '@storybook/react';storiesOf('StoriesOf|Button', module)
.add('with text', () => Click me, {
themes: {
list: [
{ name: 'red', class: 'theme-red', color: 'rgba(255, 0, 0)' },
],
},
});```
### Overwriting single properties
You can also only override a single key on the themes parameter, for instance to set a different default value for a single story:
```jsx
export default {
title: 'CSF|Button',
component: Button,
};export const withText = () => Hello Button;
withText.story = {
parameters: {
themes: {
default: 'facebook',
},
},
};
```## Usage with decorator
By default the classes will be added to the `body` element or the element configured with `target`.
But in this case your theme will not be visible by other addons (like [@storybook/addon-storyshots](https://github.com/storybookjs/storybook/tree/next/addons/storyshots)).
To fix this you can add the `withThemes` decorator in your stories.
But the decorator method is not available for all frameworks
See [here](#framework-support-table) for the list of supported framework.
### Globally
Setup the decorator globally in the `preview.js` file:
```jsx
import { addDecorator } from '@storybook/react'; // <- or your storybook framework
import { withThemes } from 'storybook-addon-themes/react'; // <- or your storybook frameworkaddDecorator(withThemes);
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
};
```### In story (Component Story Format)
Or in your story file (for all stories in that file):
```jsx
export default {
title: 'CSF|Button',
component: Button,
decorators: [ withThemes ],
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
```Or just for a specific story:
```jsx
export const withText = () => Hello Button;
withText.story = {
decorators: [ withThemes ],
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
```### In story (StoriesOf API)
And alternatively with the old StoriesOf API:
```jsx
import { storiesOf } from '@storybook/react'; // <- or your storybook framework
import { withThemes } from 'storybook-addon-themes/react';storiesOf('StoriesOf|Button', module)
.addDecorator(withThemes)
.add('with text', () => Click me);
```### Custom decorator
#### General
You can provide a component that will be used as decorator using the `Decorator` option in the `theme` parameter.
The decorator will get the following properties :
* `theme`: The selected theme or `undefined` if none is selected.
* `themes`: The list of themes as provided in the `list` option of the `theme` parameter.
* `themeClasses`: The formatted theme classes of the selected theme (if the `class` option exists on the selected theme).
* `themeName`: The name of the selected theme (equal to `none` if none is selected).Don't forget to render the story using the `children` prop (React/HTML) or the `` element (Vue/Svelte).
#### HTML example
To manage reactivity with the HTML storybook your decorator must return an array containing two elements :
* the HTML element to display in the story
* An update callback that will be called when the theme change. Like the decorator, the callback will receive the same props (without `children`).Example of a customized decorator that use a CSS file for changing the theme:
```js
function getOrCreate(id) {
const elementOnDom = document.getElementById(id);
if (elementOnDom) {
return elementOnDom;
}const element = document.createElement('link');
element.setAttribute('id', id);
element.setAttribute('rel', 'stylesheet');
return element;
}function Decorator(props) {
const { children } = props;function setStyles({ theme, themeName }) {
const link = getOrCreate('theme-stylesheet');
if (!theme) {
link.parentNode && link.parentNode.removeChild(link);
} else {
link.href = themeName === 'facebook' ? 'Button-fb.css' : 'Button-twt.css';
children.appendChild(link);
}
}
setStyles(props);return [children, setStyles];
}
```#### React example
Same example as above for React:
```js
function Decorator(props) {
const { children, themeName } = props;
return (
<>
{children}
{themeName === 'twitter' && }
{themeName === 'facebook' && }
>
);
};
```## Framework Support Table
| | [React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)| [Riot](app/riot)| [Ember](app/ember)| [Preact](app/preact)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|Usage without decorator |+| |+|+|+|+|+|+|+|+|+|+|
|Usage with decorator |+| |+| | | |+| |+| | | |