@storybook/vue3 7.0.0-alpha.46 → 7.0.0-alpha.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/vue3",
3
- "version": "7.0.0-alpha.46",
3
+ "version": "7.0.0-alpha.47",
4
4
  "description": "Storybook Vue 3 renderer",
5
5
  "keywords": [
6
6
  "storybook"
@@ -41,6 +41,7 @@
41
41
  "types": "dist/index.d.ts",
42
42
  "files": [
43
43
  "dist/**/*",
44
+ "template/**/*",
44
45
  "README.md",
45
46
  "*.js",
46
47
  "*.d.ts"
@@ -50,11 +51,11 @@
50
51
  "prep": "../../../scripts/prepare/bundle.ts"
51
52
  },
52
53
  "dependencies": {
53
- "@storybook/addons": "7.0.0-alpha.46",
54
- "@storybook/core-client": "7.0.0-alpha.46",
55
- "@storybook/docs-tools": "7.0.0-alpha.46",
56
- "@storybook/store": "7.0.0-alpha.46",
57
- "@storybook/types": "7.0.0-alpha.46",
54
+ "@storybook/addons": "7.0.0-alpha.47",
55
+ "@storybook/core-client": "7.0.0-alpha.47",
56
+ "@storybook/docs-tools": "7.0.0-alpha.47",
57
+ "@storybook/store": "7.0.0-alpha.47",
58
+ "@storybook/types": "7.0.0-alpha.47",
58
59
  "global": "^4.4.0",
59
60
  "react": "16.14.0",
60
61
  "react-dom": "16.14.0",
@@ -90,5 +91,5 @@
90
91
  ],
91
92
  "platform": "browser"
92
93
  },
93
- "gitHead": "c64b5be851ed2affac56e1daaac3f453fbe6f230"
94
+ "gitHead": "1c706a4a778831e012343c905f86225fa71491a7"
94
95
  }
@@ -0,0 +1,62 @@
1
+ import MyButton from './Button.vue';
2
+
3
+ // More on default export: https://storybook.js.org/docs/vue/writing-stories/introduction#default-export
4
+ export default {
5
+ title: 'Example/Button',
6
+ component: MyButton,
7
+ // More on component templates: https://storybook.js.org/docs/vue/writing-stories/introduction#using-args
8
+ render: (args) => ({
9
+ // Components used in your story `template` are defined in the `components` object
10
+ components: {
11
+ MyButton,
12
+ },
13
+ // The story's `args` need to be mapped into the template through the `setup()` method
14
+ setup() {
15
+ return {
16
+ args,
17
+ };
18
+ },
19
+ // And then the `args` are bound to your component with `v-bind="args"`
20
+ template: '<my-button v-bind="args" />',
21
+ }),
22
+ // More on argTypes: https://storybook.js.org/docs/vue/api/argtypes
23
+ argTypes: {
24
+ backgroundColor: {
25
+ control: 'color',
26
+ },
27
+ onClick: {},
28
+ size: {
29
+ control: {
30
+ type: 'select',
31
+ },
32
+ options: ['small', 'medium', 'large'],
33
+ },
34
+ },
35
+ };
36
+
37
+ export const Primary = {
38
+ args: {
39
+ primary: true,
40
+ label: 'Button',
41
+ },
42
+ };
43
+
44
+ export const Secondary = {
45
+ args: {
46
+ label: 'Button',
47
+ },
48
+ };
49
+
50
+ export const Large = {
51
+ args: {
52
+ size: 'large',
53
+ label: 'Button',
54
+ },
55
+ };
56
+
57
+ export const Small = {
58
+ args: {
59
+ size: 'small',
60
+ label: 'Button',
61
+ },
62
+ };
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <button type="button" :class="classes" @click="onClick" :style="style">{{ label }}</button>
3
+ </template>
4
+
5
+ <script>
6
+ import './button.css';
7
+ import { reactive, computed } from 'vue';
8
+
9
+ export default {
10
+ name: 'my-button',
11
+
12
+ props: {
13
+ label: {
14
+ type: String,
15
+ required: true,
16
+ },
17
+ primary: {
18
+ type: Boolean,
19
+ default: false,
20
+ },
21
+ size: {
22
+ type: String,
23
+ validator: function (value) {
24
+ return ['small', 'medium', 'large'].indexOf(value) !== -1;
25
+ },
26
+ },
27
+ backgroundColor: {
28
+ type: String,
29
+ },
30
+ },
31
+
32
+ emits: ['click'],
33
+
34
+ setup(props, { emit }) {
35
+ props = reactive(props);
36
+ return {
37
+ classes: computed(() => ({
38
+ 'storybook-button': true,
39
+ 'storybook-button--primary': props.primary,
40
+ 'storybook-button--secondary': !props.primary,
41
+ [`storybook-button--${props.size || 'medium'}`]: true,
42
+ })),
43
+ style: computed(() => ({
44
+ backgroundColor: props.backgroundColor,
45
+ })),
46
+ onClick() {
47
+ emit('click');
48
+ }
49
+ }
50
+ },
51
+ };
52
+ </script>
@@ -0,0 +1,39 @@
1
+ import MyHeader from './Header.vue';
2
+
3
+ export default {
4
+ title: 'Example/Header',
5
+ component: MyHeader,
6
+ render: (args) => ({
7
+ // Components used in your story `template` are defined in the `components` object
8
+ components: {
9
+ MyHeader,
10
+ },
11
+ // The story's `args` need to be mapped into the template through the `setup()` method
12
+ setup() {
13
+ // Story args can be spread into the returned object
14
+ return {
15
+ ...args,
16
+ };
17
+ },
18
+ // Then, the spread values can be accessed directly in the template
19
+ template: '<my-header :user="user" />',
20
+ }),
21
+ parameters: {
22
+ // More on Story layout: https://storybook.js.org/docs/vue/configure/story-layout
23
+ layout: 'fullscreen',
24
+ },
25
+ };
26
+
27
+ export const LoggedIn = {
28
+ args: {
29
+ user: {
30
+ name: 'Jane Doe',
31
+ },
32
+ },
33
+ };
34
+
35
+ export const LoggedOut = {
36
+ args: {
37
+ user: null,
38
+ },
39
+ };
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <header>
3
+ <div class="wrapper">
4
+ <div>
5
+ <svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
6
+ <g fill="none" fill-rule="evenodd">
7
+ <path d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z" fill="#FFF" />
8
+ <path d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z" fill="#555AB9" />
9
+ <path d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z" fill="#91BAF8" />
10
+ </g>
11
+ </svg>
12
+ <h1>Acme</h1>
13
+ </div>
14
+ <div>
15
+ <span class="welcome" v-if="user">Welcome, <b>{{ user.name }}</b>!</span>
16
+ <my-button size="small" @click="$emit('logout')" label="Log out" v-if="user" />
17
+ <my-button size="small" @click="$emit('login')" label="Log in" v-if="!user" />
18
+ <my-button primary size="small" @click="$emit('createAccount')" label="Sign up" v-if="!user" />
19
+ </div>
20
+ </div>
21
+ </header>
22
+ </template>
23
+
24
+ <script>
25
+ import './header.css';
26
+ import MyButton from './Button.vue';
27
+
28
+ export default {
29
+ name: 'my-header',
30
+
31
+ components: { MyButton },
32
+
33
+ props: {
34
+ user: {
35
+ type: Object,
36
+ },
37
+ },
38
+
39
+ emits: ['login', 'logout', 'createAccount'],
40
+ };
41
+ </script>
@@ -0,0 +1,36 @@
1
+ import { within, userEvent } from '@storybook/testing-library';
2
+ import MyPage from './Page.vue';
3
+
4
+ export default {
5
+ title: 'Example/Page',
6
+ component: MyPage,
7
+ render: () => ({
8
+ // Components used in your story `template` are defined in the `components` object
9
+ components: { MyPage },
10
+ // Here we define the `template`
11
+ template: '<my-page />',
12
+ }),
13
+ parameters: {
14
+ // More on Story layout: https://storybook.js.org/docs/vue/configure/story-layout
15
+ layout: 'fullscreen',
16
+ },
17
+ };
18
+
19
+ export const LoggedOut = {};
20
+
21
+ // More on interaction testing: https://storybook.js.org/docs/vue/writing-tests/interaction-testing
22
+ export const LoggedIn = {
23
+ render: () => ({
24
+ components: {
25
+ MyPage,
26
+ },
27
+ template: '<my-page />',
28
+ }),
29
+ play: async ({ canvasElement }) => {
30
+ const canvas = within(canvasElement);
31
+ const loginButton = await canvas.getByRole('button', {
32
+ name: /Log in/i,
33
+ });
34
+ await userEvent.click(loginButton);
35
+ },
36
+ };
@@ -0,0 +1,88 @@
1
+ <template>
2
+ <article>
3
+ <my-header
4
+ :user="user"
5
+ @login="onLogin"
6
+ @logout="onLogout"
7
+ @createAccount="onCreateAccount"
8
+ />
9
+
10
+ <section>
11
+ <h2>Pages in Storybook</h2>
12
+ <p>
13
+ We recommend building UIs with a
14
+ <a href="https://componentdriven.org" target="_blank" rel="noopener noreferrer">
15
+ <strong>component-driven</strong>
16
+ </a>
17
+ process starting with atomic components and ending with pages.
18
+ </p>
19
+ <p>
20
+ Render pages with mock data. This makes it easy to build and review page states without
21
+ needing to navigate to them in your app. Here are some handy patterns for managing page data
22
+ in Storybook:
23
+ </p>
24
+ <ul>
25
+ <li>
26
+ Use a higher-level connected component. Storybook helps you compose such data from the
27
+ "args" of child component stories
28
+ </li>
29
+ <li>
30
+ Assemble data in the page component from your services. You can mock these services out
31
+ using Storybook.
32
+ </li>
33
+ </ul>
34
+ <p>
35
+ Get a guided tutorial on component-driven development at
36
+ <a href="https://storybook.js.org/tutorials/" target="_blank" rel="noopener noreferrer"
37
+ >Storybook tutorials</a
38
+ >
39
+ . Read more in the
40
+ <a href="https://storybook.js.org/docs" target="_blank" rel="noopener noreferrer">docs</a>
41
+ .
42
+ </p>
43
+ <div class="tip-wrapper">
44
+ <span class="tip">Tip</span>
45
+ Adjust the width of the canvas with the
46
+ <svg width="10" height="10" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg">
47
+ <g fill="none" fill-rule="evenodd">
48
+ <path
49
+ d="M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z"
50
+ id="a"
51
+ fill="#999"
52
+ />
53
+ </g>
54
+ </svg>
55
+ Viewports addon in the toolbar
56
+ </div>
57
+ </section>
58
+ </article>
59
+ </template>
60
+
61
+ <script>
62
+ import './page.css';
63
+ import MyHeader from './Header.vue';
64
+
65
+ export default {
66
+ name: 'my-page',
67
+
68
+ components: { MyHeader },
69
+
70
+ data() {
71
+ return {
72
+ user: null
73
+ }
74
+ },
75
+
76
+ methods: {
77
+ onLogin() {
78
+ this.user = { name: 'Jane Doe' };
79
+ },
80
+ onLogout() {
81
+ this.user = null;
82
+ },
83
+ onCreateAccount() {
84
+ this.user = { name: 'Jane Doe' };
85
+ },
86
+ },
87
+ };
88
+ </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <button type="button" :class="classes" @click="onClick" :style="style">{{ label }}</button>
3
+ </template>
4
+
5
+ <script>
6
+ import './button.css';
7
+ import { reactive, computed } from 'vue';
8
+
9
+ export default {
10
+ name: 'my-button',
11
+
12
+ props: {
13
+ label: {
14
+ type: String,
15
+ required: true,
16
+ },
17
+ primary: {
18
+ type: Boolean,
19
+ default: false,
20
+ },
21
+ size: {
22
+ type: String,
23
+ validator: function (value) {
24
+ return ['small', 'medium', 'large'].indexOf(value) !== -1;
25
+ },
26
+ },
27
+ backgroundColor: {
28
+ type: String,
29
+ },
30
+ },
31
+
32
+ emits: ['click'],
33
+
34
+ setup(props, { emit }) {
35
+ props = reactive(props);
36
+ return {
37
+ classes: computed(() => ({
38
+ 'storybook-button': true,
39
+ 'storybook-button--primary': props.primary,
40
+ 'storybook-button--secondary': !props.primary,
41
+ [`storybook-button--${props.size || 'medium'}`]: true,
42
+ })),
43
+ style: computed(() => ({
44
+ backgroundColor: props.backgroundColor,
45
+ })),
46
+ onClick() {
47
+ emit('click');
48
+ }
49
+ }
50
+ },
51
+ };
52
+ </script>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <form id="interaction-test-form" @submit.prevent="onSubmit">
3
+ <label>
4
+ Enter Value
5
+ <input type="text" data-testid="value" :value="value" required @click="setValue" />
6
+ </label>
7
+ <button type="submit">Submit</button>
8
+ <p v-if="complete">Completed!!</p>
9
+ </form>
10
+ </template>
11
+
12
+ <script>
13
+ export default {
14
+ name: 'my-form',
15
+
16
+ props: {
17
+ onSuccess: {
18
+ type: Function,
19
+ },
20
+ },
21
+
22
+ data() {
23
+ return {
24
+ value: '',
25
+ complete: false,
26
+ };
27
+ },
28
+
29
+ methods: {
30
+ setValue(event) {
31
+ this.value = event.target.value;
32
+ },
33
+ onSubmit() {
34
+ this.onSuccess(this.value);
35
+ setTimeout(() => {
36
+ this.complete = true;
37
+ }, 500);
38
+ setTimeout(() => {
39
+ this.complete = false;
40
+ }, 1500);
41
+ },
42
+ },
43
+ };
44
+ </script>
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <div v-html="content"></div>
3
+ </template>
4
+
5
+ <script>
6
+
7
+ export default {
8
+ name: 'my-html',
9
+
10
+ props: {
11
+ content: {
12
+ type: String,
13
+ required: true,
14
+ },
15
+ },
16
+
17
+
18
+ setup() { },
19
+ };
20
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <pre data-testid="pre" :style="style">{{ finalText }}</pre>
3
+ </template>
4
+
5
+ <script>
6
+ import { reactive, computed } from 'vue';
7
+
8
+ export default {
9
+ name: 'my-pre',
10
+
11
+ props: {
12
+ // deepscan-disable-next-line
13
+ style: {
14
+ type: Object,
15
+ },
16
+ object: {
17
+ type: Object,
18
+ },
19
+ text: {
20
+ type: String,
21
+ default: '',
22
+ },
23
+ },
24
+
25
+ setup(props, { emit }) {
26
+ props = reactive(props);
27
+ return {
28
+ finalText: computed(() =>
29
+ props.object ? JSON.stringify(props.object, null, 2) : props.text
30
+ ),
31
+ };
32
+ },
33
+ };
34
+ </script>
@@ -0,0 +1,30 @@
1
+ .storybook-button {
2
+ font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3
+ font-weight: 700;
4
+ border: 0;
5
+ border-radius: 3em;
6
+ cursor: pointer;
7
+ display: inline-block;
8
+ line-height: 1;
9
+ }
10
+ .storybook-button--primary {
11
+ color: white;
12
+ background-color: #1ea7fd;
13
+ }
14
+ .storybook-button--secondary {
15
+ color: #333;
16
+ background-color: transparent;
17
+ box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
18
+ }
19
+ .storybook-button--small {
20
+ font-size: 12px;
21
+ padding: 10px 16px;
22
+ }
23
+ .storybook-button--medium {
24
+ font-size: 14px;
25
+ padding: 11px 20px;
26
+ }
27
+ .storybook-button--large {
28
+ font-size: 16px;
29
+ padding: 12px 24px;
30
+ }
@@ -0,0 +1,9 @@
1
+ import globalThis from 'global';
2
+
3
+ import Button from './Button.vue';
4
+ import Pre from './Pre.vue';
5
+ import Form from './Form.vue';
6
+ import Html from './Html.vue';
7
+
8
+ globalThis.Components = { Button, Pre, Form, Html };
9
+ globalThis.storybookRenderer = 'vue3';
@@ -0,0 +1,29 @@
1
+ import GlobalUsage from './GlobalUsage.vue';
2
+
3
+ export default {
4
+ component: GlobalUsage,
5
+ argTypes: {},
6
+ render: (args) => ({
7
+ // Components used in your story `template` are defined in the `components` object
8
+ components: { GlobalUsage },
9
+ // The story's `args` need to be mapped into the template through the `setup()` method
10
+ setup() {
11
+ return { args };
12
+ },
13
+ // And then the `args` are bound to your component with `v-bind="args"`
14
+ template: '<global-usage v-bind="args" />',
15
+ }),
16
+ };
17
+
18
+ export const Primary = {
19
+ args: {
20
+ primary: true,
21
+ label: 'Globally Defined',
22
+ },
23
+ };
24
+
25
+ export const Secondary = {
26
+ args: {
27
+ label: 'Globally Defined',
28
+ },
29
+ };
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <global-button v-bind="$props" />
3
+ </template>
@@ -0,0 +1,43 @@
1
+ import OverrideArgs from './OverrideArgs.vue';
2
+
3
+ // Emulate something that isn't serializable
4
+ const icons = {
5
+ Primary: {
6
+ template: '<span>Primary Icon</span>',
7
+ },
8
+ Secondary: {
9
+ template: '<span>Secondary Icon</span>',
10
+ },
11
+ };
12
+
13
+ export default {
14
+ component: OverrideArgs,
15
+ argTypes: {
16
+ // To show that other props are passed through
17
+ backgroundColor: { control: 'color' },
18
+ icon: {
19
+ control: {
20
+ type: 'select',
21
+ options: Object.keys(icons),
22
+ },
23
+ defaultValue: 'Primary',
24
+ },
25
+ },
26
+ render: (args) => {
27
+ // Individual properties can be overridden by spreading the args
28
+ // and the replacing the key-values that need to be updated
29
+ args = { ...args, icon: icons[args.icon] }; // eslint-disable-line no-param-reassign
30
+ return {
31
+ // Components used in your story `template` are defined in the `components` object
32
+ components: { OverrideArgs },
33
+ // Updated `args` need to be mapped into the template through the `setup()` method
34
+ setup() {
35
+ return { args };
36
+ },
37
+ // And then the `args` are bound to your component with `v-bind="args"`
38
+ template: '<override-args v-bind="args" />',
39
+ };
40
+ },
41
+ };
42
+
43
+ export const TestOne = {};
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <button type="button" :class="classes" :style="style">
3
+ <!-- You can use <component /> with `:is` when passing a component as a prop -->
4
+ <component :is="icon" />
5
+ </button>
6
+ </template>
7
+
8
+ <script lang="typescript">
9
+ import { h, computed, reactive } from 'vue';
10
+
11
+ export default {
12
+ name: 'override-args',
13
+
14
+ props: {
15
+ icon: {
16
+ type: Object,
17
+ required: true,
18
+ },
19
+
20
+ backgroundColor: {
21
+ type: String
22
+ },
23
+ },
24
+
25
+ // @ts-expect-error (Converted from ts-ignore)
26
+ setup(props, { emit }) {
27
+ const classes = {
28
+ 'storybook-button': true,
29
+ 'storybook-button--primary': true,
30
+ 'storybook-button--large': true,
31
+ };
32
+ const style = computed(() => ({
33
+ backgroundColor: props.backgroundColor,
34
+ }));
35
+
36
+ // Notice that `icon` prop component is still passed through even though it isn't mapped
37
+ return { classes, style, }
38
+ },
39
+ };
40
+ </script>
@@ -0,0 +1,66 @@
1
+ import globalThis from 'global';
2
+ import { h } from 'vue';
3
+
4
+ const { Button, Pre } = globalThis.Components;
5
+
6
+ export default {
7
+ component: Button,
8
+ };
9
+
10
+ export const ComponentTemplate = {
11
+ args: { label: 'With component' },
12
+ decorators: [
13
+ () => ({
14
+ components: {
15
+ Pre,
16
+ },
17
+ template: `
18
+ <Pre text="decorator" />
19
+ <story/>
20
+ `,
21
+ }),
22
+ ],
23
+ };
24
+
25
+ export const SimpleTemplate = {
26
+ args: { label: 'With border' },
27
+ decorators: [
28
+ () => ({
29
+ template: `
30
+ <div style="border: 5px solid red;">
31
+ <story/>
32
+ </div>
33
+ `,
34
+ }),
35
+ ],
36
+ };
37
+
38
+ export const VueWrapper = {
39
+ args: { label: 'With Vue wrapper' },
40
+ decorators: [
41
+ (storyFn) => {
42
+ // Call the `storyFn` to receive a component that Vue can render
43
+ const story = storyFn();
44
+ // Vue 3 "Functional" component as decorator
45
+ return () => {
46
+ return h('div', { style: 'border: 2px solid blue' }, h(story));
47
+ };
48
+ },
49
+ ],
50
+ };
51
+
52
+ export const DynamicWrapper = {
53
+ args: { label: 'With dynamic wrapper', primary: true },
54
+ argTypes: {
55
+ // Number type is detected, but we still want to constrain the range from 1-6
56
+ level: { control: { type: 'range', min: 1, max: 6 } },
57
+ },
58
+ decorators: [
59
+ (storyFn, { args }) => ({
60
+ template: `<div :style="{ borderWidth: level, borderColor: 'red', borderStyle: 'solid' }"><story /></div>`,
61
+ data() {
62
+ return { level: `${args.level}px` };
63
+ },
64
+ }),
65
+ ],
66
+ };
@@ -0,0 +1,13 @@
1
+ import globalThis from 'global';
2
+ // eslint-disable-next-line import/no-extraneous-dependencies
3
+ import { setup } from '@storybook/vue3';
4
+
5
+ // TODO: I'd like to be able to export rather than imperatively calling an imported function
6
+ // export const setup = (app) => {
7
+ // app.component('GlobalButton', Button);
8
+ // };
9
+
10
+ setup((app) => {
11
+ // This adds a component that can be used globally in stories
12
+ app.component('GlobalButton', globalThis.Components.Button);
13
+ });
@@ -0,0 +1,46 @@
1
+ import globalThis from 'global';
2
+ import { Meta, Story, Canvas } from '@storybook/addon-docs';
3
+
4
+ <Meta title="stories/renderers/vue3/vue3-mdx" />
5
+
6
+ # Vue3-specific MDX Stories
7
+
8
+ export const Button = globalThis.Components.Button;
9
+
10
+ export const Template = (args, { argTypes }) => ({
11
+ components: { MyButton: Button },
12
+ template: '<my-button v-bind="args" />',
13
+ setup() {
14
+ return { args };
15
+ },
16
+ });
17
+
18
+ ## Primary
19
+
20
+ <Canvas>
21
+ <Story name="Primary">
22
+ {{
23
+ components: { MyButton: Button },
24
+ template: '<my-button :primary="true" label="Primary button" />',
25
+ }}
26
+ </Story>
27
+ </Canvas>
28
+
29
+ ## Secondary
30
+
31
+ <Canvas>
32
+ <Story name="Secondary">
33
+ {{
34
+ components: { MyButton: Button },
35
+ template: '<my-button :primary="false" label="Secondary button" />',
36
+ }}
37
+ </Story>
38
+ </Canvas>
39
+
40
+ ## From template
41
+
42
+ <Canvas>
43
+ <Story name="From Template" args={{ label: 'From template' }}>
44
+ {Template.bind({})}
45
+ </Story>
46
+ </Canvas>