Skip to content

Commit

Permalink
Addon-contexts: Improve Vue integration (#6632)
Browse files Browse the repository at this point in the history
Addon-contexts: Improve Vue integration
  • Loading branch information
shilman authored Apr 26, 2019
2 parents fba0541 + c1bcdb1 commit 9bb3ae8
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 4 deletions.
13 changes: 9 additions & 4 deletions addons/contexts/src/preview/frameworks/vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ import { ID } from '../../shared/constants';
* This is the framework specific bindings for Vue.
* '@storybook/vue' expects the returning object from a decorator to be a 'VueComponent'.
*/
export const renderVue: Render<Vue.Component> = (contextNodes, propsMap, getStoryVNode) => {
export const renderVue: Render<Vue.Component> = (contextNodes, propsMap, getStoryComponent) => {
const { getRendererFrom, updateReactiveSystem } = ContextsPreviewAPI();
const reactiveProps = updateReactiveSystem(propsMap);
return Vue.extend({
name: ID,
data: () => reactiveProps,
render: createElement =>
getRendererFrom((component, props, children) =>
createElement(component, { props }, [children])
)(contextNodes, reactiveProps, () => createElement(getStoryVNode())),
getRendererFrom((Component, props, children) => {
const { key, ref, style, classNames, ...rest } = props || Object();
const contextData =
Component instanceof Object
? { key, ref, style, class: classNames, props: rest } // component as a Vue object
: { key, ref, style, class: classNames, attrs: rest }; // component as a HTML tag string
return createElement(Component, contextData, [children]);
})(contextNodes, reactiveProps, () => createElement(getStoryComponent())),
});
};

Expand Down
1 change: 1 addition & 0 deletions examples/vue-kitchen-sink/.storybook/addons.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ import '@storybook/addon-knobs/register';
import '@storybook/addon-viewport/register';
import '@storybook/addon-options/register';
import '@storybook/addon-backgrounds/register';
import '@storybook/addon-contexts/register';
1 change: 1 addition & 0 deletions examples/vue-kitchen-sink/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@storybook/addon-actions": "5.1.0-alpha.34",
"@storybook/addon-backgrounds": "5.1.0-alpha.34",
"@storybook/addon-centered": "5.1.0-alpha.34",
"@storybook/addon-contexts": "5.1.0-alpha.34",
"@storybook/addon-knobs": "5.1.0-alpha.34",
"@storybook/addon-links": "5.1.0-alpha.34",
"@storybook/addon-notes": "5.1.0-alpha.34",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Storyshots Addon|Contexts Languages 1`] = `
<div
style="color: white; background: rgb(23, 63, 95); height: 100vh; padding: 10px;"
>
<div>

Your locale is unknown, so I say NULL!

</div>
</div>
`;

exports[`Storyshots Addon|Contexts Simple CSS Theming 1`] = `
<div
style="color: white; background: rgb(23, 63, 95); height: 100vh; padding: 10px;"
>
<span>
I'm a children of the injected 'div' (where provides a theming context).
</span>
</div>
`;
144 changes: 144 additions & 0 deletions examples/vue-kitchen-sink/src/stories/addon-contexts.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { storiesOf } from '@storybook/vue';
import { withContexts } from '@storybook/addon-contexts/vue';

// Example A: Simple CSS Theming
const topLevelContexts = [
{
icon: 'sidebaralt',
title: 'CSS Themes',
components: ['div'],
params: [
{
name: 'Desert',
props: {
style: { color: 'brown', background: '#F4A261', height: '100vh', padding: '10px' },
},
},
{
name: 'Ocean',
props: {
style: { color: 'white', background: '#173F5F', height: '100vh', padding: '10px' },
},
default: true,
},
],
},
];

const storyLevelContexts = [
{
title: 'CSS Themes',
params: [
{
name: 'Forest',
props: {
style: { color: 'teal', background: '#00b894', height: '100vh', padding: '10px' },
},
},
],
},
];

const stories = storiesOf('Addon|Contexts', module).addDecorator(withContexts(topLevelContexts));

stories.add(
'Simple CSS Theming',
() => ({
template:
"<span>I'm a children of the injected 'div' (where provides a theming context).</span>",
}),
{
contexts: storyLevelContexts,
}
);

// Example B: Language (Vue provide/inject API)
const createContext = initialValue => {
const uid = `_${Date.now()}${Math.random()}`;
return {
Provider: {
name: `Context.Provider`,
props: ['value'],
provide() {
return this.value === undefined
? undefined
: {
[uid]: () => this.value,
};
},
template: `
<div>
<slot />
</div>
`,
},
Consumer: {
name: `Context.Consumer`,
inject: {
[uid]: {
default: () => () =>
initialValue instanceof Object ? { ...initialValue } : { value: initialValue },
},
},
computed: {
value() {
return this[uid]();
},
},
template: `
<div>
<slot v-bind="value" />
</div>
`,
},
};
};

const NaiveIntlContext = createContext({
locale: 'unknown',
greeting: 'NULL',
});

stories.add(
'Languages',
() => ({
components: { 'NaiveIntlContext.Consumer': NaiveIntlContext.Consumer },
template: `
<NaiveIntlContext.Consumer v-slot="{ locale, greeting }">
Your locale is {{ locale }}, so I say {{ greeting }}!
</NaiveIntlContext.Consumer>
`,
}),
{
contexts: [
{
icon: 'globe',
title: 'Languages',
components: [NaiveIntlContext.Provider],
params: [
{
name: 'English',
props: {
value: { locale: 'en', greeting: 'Hello' },
},
},
{
name: 'French',
props: {
value: { locale: 'fr', greeting: 'Bonjour' },
},
},
{
name: 'Chinese',
props: {
value: { locale: 'cn', greeting: '你好' },
},
},
],
options: {
cancelable: true,
},
},
],
}
);

1 comment on commit 9bb3ae8

@vercel
Copy link

@vercel vercel bot commented on 9bb3ae8 Apr 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.