Merge branch 'feature/vue2-fixes' into shilman/vue2-rendering-improvements

This commit is contained in:
Michael Shilman 2022-10-01 18:44:18 +08:00
commit cb868fc991
3 changed files with 43 additions and 10 deletions

View File

@ -1,3 +1,4 @@
import { within, userEvent } from '@storybook/testing-library';
import MyButton from '../Button.vue';
export default {
@ -11,7 +12,8 @@ export default {
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { MyButton },
template: '<my-button :color="color" :rounded="rounded">{{label}}</my-button>',
template: `
<my-button :color="color" :rounded="rounded">{{label}}</my-button>`,
});
export const Rounded = Template.bind({});
@ -20,6 +22,18 @@ Rounded.args = {
color: '#f00',
label: 'A Button with rounded edges',
};
Rounded.decorators = [
(storyFn, context) => {
return storyFn({ ...context, args: { ...context.args, label: 'Overridden args' } });
},
() => ({
template: '<div style="background: #eee;"><story/></div>',
}),
];
Rounded.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole('button'));
};
export const Square = Template.bind({});
Square.args = {

View File

@ -10,7 +10,8 @@ export const WRAPS = 'STORYBOOK_WRAPS';
function prepare(
rawStory: StoryFnVueReturnType,
innerStory?: VueConstructor
innerStory?: VueConstructor,
context?: StoryContext<VueFramework>
): VueConstructor | null {
let story: ComponentOptions<Vue> | VueConstructor;
@ -38,7 +39,11 @@ function prepare(
// @ts-expect-error // https://github.com/storybookjs/storybook/pull/7578#discussion_r307985279
[WRAPS]: story,
// @ts-expect-error // https://github.com/storybookjs/storybook/pull/7578#discussion_r307984824
[VALUES]: { ...(innerStory ? innerStory.options[VALUES] : {}), ...extractProps(story) },
[VALUES]: {
...(innerStory ? innerStory.options[VALUES] : {}),
...extractProps(story),
...(context?.args || {}),
},
functional: true,
render(h, { data, parent, children }) {
return h(
@ -77,6 +82,8 @@ export function decorateStory(
return prepare(decoratedStory, story as any);
},
(context) => prepare(storyFn(context))
(context) => {
return prepare(storyFn(context), null, context);
}
);
}

View File

@ -42,9 +42,8 @@ const getRoot = (domElement: Element): [Instance, Element] => {
};
},
render(h) {
map.set(domElement, [instance, target]);
const children = this[COMPONENT] ? [h(this[COMPONENT])] : undefined;
return h('div', { attrs: { id: 'storybook-vue-root' } }, children);
map.set(domElement, instance);
return this[COMPONENT] ? [h(this[COMPONENT])] : undefined;
},
});
@ -92,7 +91,6 @@ export function renderToDOM(
title,
name,
storyFn,
storyContext: { args },
showMain,
showError,
showException,
@ -104,6 +102,20 @@ export function renderToDOM(
Vue.config.errorHandler = showException;
const element = storyFn();
let mountTarget: Element;
// Vue2 mount always replaces the mount target with Vue-generated DOM.
// https://v2.vuejs.org/v2/api/#el:~:text=replaced%20with%20Vue%2Dgenerated%20DOM
// We cannot mount to the domElement directly, because it would be replaced. That would
// break the references to the domElement like canvasElement used in the play function.
// Instead, we mount to a child element of the domElement, creating one if necessary.
if (domElement.hasChildNodes()) {
mountTarget = domElement.firstElementChild;
} else {
mountTarget = document.createElement('div');
domElement.appendChild(mountTarget);
}
if (!element) {
showError({
title: `Expecting a Vue component from the story: "${name}" of "${title}".`,
@ -121,10 +133,10 @@ export function renderToDOM(
}
// @ts-expect-error https://github.com/storybookjs/storrybook/pull/7578#discussion_r307986139
root[VALUES] = { ...element.options[VALUES], ...args };
root[VALUES] = { ...element.options[VALUES] };
if (!map.has(domElement)) {
root.$mount(target);
root.$mount(mountTarget);
}
showMain();