diff --git a/addons/storyshots/storyshots-core/src/frameworks/vue/renderTree.js b/addons/storyshots/storyshots-core/src/frameworks/vue/renderTree.js index 888c9820365..424070b7893 100644 --- a/addons/storyshots/storyshots-core/src/frameworks/vue/renderTree.js +++ b/addons/storyshots/storyshots-core/src/frameworks/vue/renderTree.js @@ -2,12 +2,15 @@ import Vue from 'vue'; function getRenderedTree(story, context) { - const storyElement = story.render(context); + const component = story.render(context); - const Constructor = Vue.extend(storyElement); - const vm = new Constructor().$mount(); + const vm = new Vue({ + render(h) { + return h(component); + }, + }); - return vm.$el; + return vm.$mount().$el; } export default getRenderedTree; diff --git a/app/vue/src/client/preview/index.js b/app/vue/src/client/preview/index.js index b859c3dd1c8..81956244829 100644 --- a/app/vue/src/client/preview/index.js +++ b/app/vue/src/client/preview/index.js @@ -1,30 +1,72 @@ import { start } from '@storybook/core/client'; +import Vue from 'vue'; import './globals'; import render from './render'; -const createWrapperComponent = Target => ({ - functional: true, - render(h, c) { - return h(Target, c.data, c.children); - }, -}); -const decorateStory = (getStory, decorators) => - decorators.reduce( - (decorated, decorator) => context => { - const story = () => decorated(context); - let decoratedStory = decorator(story, context); +export const WRAPS = 'STORYBOOK_WRAPS'; +export const VALUES = 'STORYBOOK_VALUES'; - if (typeof decoratedStory === 'string') { - decoratedStory = { template: decoratedStory }; +function extractProps(component) { + return Object.entries(component.options.props || {}) + .map(([name, def]) => ({ [name]: def.default })) + .reduce((wrap, prop) => ({ ...wrap, ...prop }), {}); +} + +function prepare(rawStory, innerStory) { + let story = rawStory; + // eslint-disable-next-line no-underscore-dangle + if (!story._isVue) { + if (typeof story === 'string') { + story = { template: story }; + } + if (innerStory) { + story.components = { ...(story.components || {}), story: innerStory }; + } + story = Vue.extend(story); + } else if (story.options[WRAPS]) { + return story; + } + + return Vue.extend({ + [WRAPS]: story, + [VALUES]: { ...(innerStory ? innerStory.options[VALUES] : {}), ...extractProps(story) }, + functional: true, + render(h, { data, parent, children }) { + return h( + story, + { + ...data, + props: { ...(data.props || {}), ...(parent.$root[VALUES] || {}) }, + }, + children + ); + }, + }); +} + +function decorateStory(getStory, decorators) { + return decorators.reduce( + (decorated, decorator) => context => { + let story; + const decoratedStory = decorator(() => { + story = decorated(context); + return story; + }, context); + + if (!story) { + story = decorated(context); } - decoratedStory.components = decoratedStory.components || {}; - decoratedStory.components.story = createWrapperComponent(story()); - return decoratedStory; + if (decoratedStory === story) { + return story; + } + + return prepare(decoratedStory, story); }, - getStory + context => prepare(getStory(context)) ); +} const { clientApi, configApi, forceReRender } = start(render, { decorateStory }); diff --git a/app/vue/src/client/preview/render.js b/app/vue/src/client/preview/render.js index 7204bfccae6..24ba65417a3 100644 --- a/app/vue/src/client/preview/render.js +++ b/app/vue/src/client/preview/render.js @@ -1,24 +1,17 @@ import { stripIndents } from 'common-tags'; import Vue from 'vue'; +import { VALUES } from '.'; let root = null; -function getComponentProxy(component) { - return Object.entries(component.props || {}) - .map(([name, def]) => ({ [name]: def.default })) - .reduce((wrap, prop) => ({ ...wrap, ...prop }), {}); -} - -function renderRoot(component, proxy) { +function renderRoot(component) { root = new Vue({ el: '#root', - beforeCreate() { - this.proxy = proxy; + data() { + return { [VALUES]: component.options[VALUES] }; }, - render(h) { - const props = this.proxy; - return h('div', { attrs: { id: 'root' } }, [h(component, { props })]); + return h('div', { attrs: { id: 'root' } }, [h(component)]); }, }); } @@ -49,15 +42,12 @@ export default function render({ showMain(); - const proxy = getComponentProxy(component); - // at component creation || refresh by HMR if (!root || !forceRender) { if (root) root.$destroy(); - renderRoot(component, proxy); + renderRoot(component); } else { - root.proxy = proxy; - root.$forceUpdate(); + root[VALUES] = component.options[VALUES]; } } diff --git a/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-centered.stories.storyshot b/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-centered.stories.storyshot index 66bdedf3c91..d19663d8679 100644 --- a/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-centered.stories.storyshot +++ b/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-centered.stories.storyshot @@ -7,28 +7,12 @@ exports[`Storyshots Addon|Centered rounded 1`] = `