Custom <story>
blocks for Vue single file components that work out of the box with Vue CLI 3 and vue-cli-plugin-storybook
.
yarn add vue-storybook
const { storyLoader, registerStories } = require("vue-storybook");
A Webpack loader + helper script that allows you to embellish your pre-existing Vue single file components (SFC) with a custom <story>
block that's automatically translated into a Storybook-flavored story.
Repo: https://github.com/mattrothenberg/vue-storybook-example-project
<story name="Disabled Button">
<my-button :disabled="true">Can't touch this</my-button>
</story>
turns into:
Given an existing Vue CLI + vue-cli-plugin-storybook
project, modify your project's vue.config.js
thusly.
// vue.config.js
module.exports = {
chainWebpack: config => {
config.resolve.symlinks(false);
},
configureWebpack: config => {
config.module.rules.push({
resourceQuery: /blockType=story/,
loader: "vue-storybook"
});
}
};
Add a custom <story>
block to your single file component. The following Storybook plugins/APIs are supported:
- Actions
- Story Options
- Notes
- Knobs
It is also possible to pass options for other addons using the parameters
attribute.
You can optionally group components by specifiying a group
attribute.
<story
options="{
panelPosition: 'right'
}"
name="with knobs"
group="MyButton"
notes="### this is the coolest story ever"
knobs="{
initialText: {
default: text('Initial Text', 'default value goes here')
},
isDisabled: {
default: boolean('Is Disabled?', false)
}
}"
parameters="{
foo: { ... }
}"
>
<my-button :disabled="isDisabled" @click="action('show me the money', isDisabled)">{{initialText}}</my-button>
</story>
Then, in your main index.stories.js
(or wherever your write your stories), leverage our helper script to start adding stories. NB: the signature of registerStories
has changed significantly.
registerStories(req, filename, storiesOf, config);
config
is now an object with the following keys,
{
knobs: {
// put the knobs you plan on using
// (things like `text` or `select`)
// in this object
},
decorators: [
// an array of decorator functions
],
methods: {
action // where action is the exported member from `addon-actions`
}
}
// Import Storybook + all 'yr plugins!
import { storiesOf } from "@storybook/vue";
import { action } from "@storybook/addon-actions";
import { withNotes } from "@storybook/addon-notes";
import { withKnobs, text, boolean } from "@storybook/addon-knobs/vue";
// Import our helper
import { registerStories } from "vue-storybook";
// Require the Vue SFC with <story> blocks inside
const req = require.context("./", true, /\.vue$/);
// Programatically register these stories
function loadStories() {
req.keys().forEach(filename => {
let config = {
knobs: {
text,
boolean
},
decorators: [
withKnobs,
function(context, story) {
return {
template: `
<div><story /></div>`
};
}
],
methods: {
action
}
};
registerStories(req, filename, storiesOf, config);
});
}
// Let's go!
configure(loadStories, module)
- Actions
- Knobs
- Notes
- Info
- Readme