Skip to content

Commit

Permalink
#14: Extend the supported frameworks to Vue
Browse files Browse the repository at this point in the history
  • Loading branch information
Leo Y. Li authored and ndelangen committed Apr 16, 2019
1 parent 0664887 commit d3ff9a8
Show file tree
Hide file tree
Showing 16 changed files with 125 additions and 51 deletions.
15 changes: 9 additions & 6 deletions addons/addon-contexts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@
"description": "Storybook Addon Contexts",
"keywords": [
"storybook",
"react"
"react",
"vue"
],
"author": "Leo Y. Li",
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist/**/*",
"register.js"
"register.js",
"react.js",
"vue.js"
],
"repository": {
"type": "git",
"url": "https://github.com/leoyli/addon-contexts.git"
},
"bugs": {
"url": "https://github.com/leoyli/addon-contexts/issues"
},
"scripts": {
"prettier": "prettier --config .prettierrc --write '**/*.{ts,tsx}'",
"type:check": "tsc --isolatedModules --noEmit ",
Expand All @@ -42,7 +42,9 @@
"@babel/preset-react": "7.0.0",
"@babel/preset-typescript": "7.3.3",
"@types/jest": "24.0.11",
"@types/node": "^11.13.2",
"@types/react": "16.8.12",
"@types/vue": "^2.0.0",
"jest": "24.7.1",
"jest-dom": "3.1.3",
"jest-haste-map": "24.7.1",
Expand All @@ -51,7 +53,8 @@
"react": "16.8.6",
"react-dom": "16.8.6",
"react-testing-library": "6.1.2",
"typescript": "3.4.2"
"typescript": "3.4.2",
"vue": "^2.6.10"
},
"peerDependencies": {
"@storybook/addons": ">=5 <6",
Expand Down
3 changes: 3 additions & 0 deletions addons/addon-contexts/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { withContexts } from './dist/preview/frameworks/react';
export { withContexts };
export default withContexts;
14 changes: 11 additions & 3 deletions addons/addon-contexts/src/@types/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Component } from 'vue';

export * from './manager';
export * from './preview';

// helpers
export type AnyFunctionReturns<T> = (...args: any[]) => T;
export type AnyFunctionReturns<T> = (...arg: any[]) => T;
export type GenericObject = { [key: string]: GenericObject };
export type GenericProp = GenericObject | null;
export type StringTuple = [string, string];
Expand Down Expand Up @@ -38,6 +40,12 @@ export type WrapperSettings = {
parameters?: AddonSetting[] | undefined;
};

export type Wrapper = (...args: [AnyFunctionReturns<unknown>, unknown, WrapperSettings]) => unknown;
export type Wrapper = (...arg: [AnyFunctionReturns<any>, unknown, WrapperSettings]) => unknown;

export type Renderer = (
nodes: ContextNode[],
props: GenericObject,
next: AnyFunctionReturns<unknown>
) => Component;

export type WithContexts = (contexts: AddonSetting[]) => unknown;
export type GetAddonDecorator = (render: Renderer) => (contexts: AddonSetting[]) => unknown;
2 changes: 1 addition & 1 deletion addons/addon-contexts/src/@types/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type TToolbarControl = FCNoChildren<
Omit<
ContextNode & {
selected: string;
setSelected: (...args: StringTuple) => void;
setSelected: (...arg: StringTuple) => void;
},
'components'
>
Expand Down
17 changes: 8 additions & 9 deletions addons/addon-contexts/src/@types/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,26 @@ import {
StringObject,
WrapperSettings,
} from './index';
import { Component } from 'vue';

export type Memorize = <T, U extends any[]>(
fn: (...args: U) => T,
resolver?: (...args: U) => unknown
) => (...args: U) => T;
fn: (...arg: U) => T,
resolver?: (...arg: U) => unknown
) => (...arg: U) => T;

export type Singleton = <T, U extends any[]>(fn: (...args: U) => T) => (...args: U) => T;
export type Singleton = <T, U extends any[]>(fn: (...arg: U) => T) => (...arg: U) => T;

export type AggregateComponents = <T>(
h: AnyFunctionReturns<T>
) => (
...args: [ContextNode['components'], GenericProp, AddonOptions, number]
...arg: [ContextNode['components'], GenericProp, AddonOptions, number]
) => AnyFunctionReturns<T>;

export type AggregateContexts = <T>(
h: AnyFunctionReturns<T>
) => (...args: [ContextNode[], GenericObject, AnyFunctionReturns<any>]) => T;
) => (...arg: [ContextNode[], GenericObject, AnyFunctionReturns<any>]) => T;

export type GetMergedSettings = (
...args: [Partial<AddonSetting>, Partial<AddonSetting>]
) => ContextNode;
export type GetMergedSettings = (...arg: [Partial<AddonSetting>, Partial<AddonSetting>]) => ContextNode;

export type GetContextNodes = (settings: WrapperSettings) => ContextNode[];

Expand Down
15 changes: 3 additions & 12 deletions addons/addon-contexts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
import { makeDecorator } from '@storybook/addons';
import { ID, PARAM } from './constants';
import { wrapper } from './preview';
import { WithContexts } from './@types';

export const withContexts: WithContexts = makeDecorator({
name: ID,
parameterName: PARAM,
skipIfNoParametersOrOptions: true,
allowDeprecatedUsage: false,
wrapper,
});
import { withContexts } from './preview/frameworks/react';
export { withContexts };
export default withContexts;
9 changes: 7 additions & 2 deletions addons/addon-contexts/src/preview/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import addons from '@storybook/addons';
import { FORCE_RE_RENDER } from '@storybook/core-events';
import { UPDATE_PREVIEW, UPDATE_MANAGER } from '../constants';
import { getContextNodes, getPropsMap, aggregateContexts, singleton } from './libs';
import { GetContextNodes } from '../@types';
import { GenericProp, GetContextNodes } from '../@types';

/**
* @Public
* A singleton for handling wrapper-manager side-effects
*/
export const addonContextsAPI = singleton(() => {
let selectionState = {};
const channel = addons.getChannel();
let selectionState = {};

// from manager
channel.on(UPDATE_PREVIEW, (state) => (selectionState = Object.freeze(state)));
Expand All @@ -23,10 +23,15 @@ export const addonContextsAPI = singleton(() => {
return nodes;
};

// (Vue) hold a reference for updating props in its reactive system
let reactivePropsMap = {};
const updateReactiveSystem = (propsMap: GenericProp) => Object.assign(reactivePropsMap, propsMap);

return {
getContextNodes: getContextNodesWithSideEffects,
getSelectionState: () => selectionState,
getPropsMap,
getRenderFrom: aggregateContexts,
updateReactiveSystem,
};
});
13 changes: 13 additions & 0 deletions addons/addon-contexts/src/preview/frameworks/react.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { getAddonDecorator } from '../index';
import { addonContextsAPI } from '../api';
import { Renderer } from '../../@types';

export const renderReact: Renderer = (...arg) => {
const { getRenderFrom } = addonContextsAPI();
return getRenderFrom(React.createElement)(...arg);
};

export const withContexts = getAddonDecorator(renderReact);

export default withContexts;
22 changes: 22 additions & 0 deletions addons/addon-contexts/src/preview/frameworks/vue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Vue, { Component } from 'vue';
import { getAddonDecorator } from '../index';
import { addonContextsAPI } from '../api';
import { ID } from '../../constants';
import { Renderer } from '../../@types';

export const renderVue: Renderer = (nodes, props, next) => {
const { getRenderFrom, updateReactiveSystem } = addonContextsAPI();
const reactiveProps = updateReactiveSystem(props);
return Vue.extend({
name: ID,
data: () => reactiveProps,
render: (createElement) =>
getRenderFrom((component, props, children) =>
createElement(component, { props }, [children])
)(nodes, reactiveProps, () => createElement(next() as Component)),
});
};

export const withContexts = getAddonDecorator(renderVue);

export default withContexts;
23 changes: 22 additions & 1 deletion addons/addon-contexts/src/preview/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
export { reactWrapper as wrapper } from './react';
import { makeDecorator } from '@storybook/addons';
import { addonContextsAPI } from './api';
import { ID, PARAM } from '../constants';
import { GetAddonDecorator, Wrapper } from '../@types';

export const getAddonDecorator: GetAddonDecorator = (render) => {
const wrapper: Wrapper = (getStory, context, settings) => {
const { getContextNodes, getSelectionState, getPropsMap } = addonContextsAPI();
const nodes = getContextNodes(settings);
const state = getSelectionState();
const props = getPropsMap(nodes, state);
return render(nodes, props, () => getStory(context));
};

return makeDecorator({
name: ID,
parameterName: PARAM,
skipIfNoParametersOrOptions: true,
allowDeprecatedUsage: false,
wrapper,
});
};
1 change: 1 addition & 0 deletions addons/addon-contexts/src/preview/libs/aggregators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export const aggregateContexts: AggregateContexts = (h) => (nodes, propsMap, nex
.map(({ nodeId, components = [], options = {} }) =>
_aggregateComponents(h)(components, propsMap[nodeId], options, components.length - 1)
)
.reverse()
.reduce((acc, agg) => agg(() => acc), next());
2 changes: 1 addition & 1 deletion addons/addon-contexts/src/preview/libs/getContextNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GetContextNodes, GetMergedSettings } from '../../@types';

/**
* @private
* Merges the global (options) and the local (parameters) from a pair of setting;
* Merges the global (options) and the story (parameters) from a pair of setting;
* @return the normalized definition for a contextual environment (-> node).
*/
export const _getMergedSettings: GetMergedSettings = (
Expand Down
12 changes: 0 additions & 12 deletions addons/addon-contexts/src/preview/react.ts

This file was deleted.

4 changes: 2 additions & 2 deletions addons/addon-contexts/src/register.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createElement as h } from 'react';
import { createElement } from 'react';
import addons, { types } from '@storybook/addons';
import { AddonManager } from './manager/AddonManager';
import { ID } from './constants';
Expand All @@ -8,6 +8,6 @@ addons.register(ID, (api) =>
title: ID,
type: types.TOOL,
match: ({ viewMode }) => viewMode === 'story',
render: () => h(AddonManager, { channel: api.getChannel() }),
render: () => createElement(AddonManager, { channel: api.getChannel() }),
})
);
3 changes: 3 additions & 0 deletions addons/addon-contexts/vue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { withContexts } from './dist/preview/frameworks/vue';
export { withContexts };
export default withContexts;
21 changes: 19 additions & 2 deletions addons/addon-contexts/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,7 @@
resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b"
integrity sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==

"@storybook/[email protected]", "@storybook/addons@^5.0.6":
"@storybook/[email protected]", "@storybook/addons@^5.0.0":
version "5.0.6"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.0.6.tgz#3ecb7fd8421e6557b1abc71ebede905e8decfebc"
integrity sha512-VZFYnckWRErkOTZG3a3y7jvnPUjOsTCbWSxvJVMM5SfPzlZbcUz16wJDCJ/pQWI0VzhHFEAVfae9DcuiF031Ow==
Expand All @@ -1093,7 +1093,7 @@
dependencies:
core-js "^2.6.5"

"@storybook/components@^5.0.6":
"@storybook/components@^5.0.0":
version "5.0.6"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.0.6.tgz#de77af3443f771d94a692edb719bc0d8c0149daf"
integrity sha512-C++A39n9O09PU2e4Y8x/zbZ+Tf0t/mfPw83Mkh8d8OHS4rHdVKEhq6QC8oDuqT9YBNhJOohtg5d9n+7s8sqZyQ==
Expand Down Expand Up @@ -1218,6 +1218,11 @@
dependencies:
"@types/jest-diff" "*"

"@types/node@^11.13.2":
version "11.13.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.2.tgz#dc85dde46aa8740bb4aed54b8104250f8f849503"
integrity sha512-HOtU5KqROKT7qX/itKHuTtt5fV0iXbheQvrgbLNXFJQBY/eh+VS5vmmTAVlo3qIGMsypm0G4N1t2AXjy1ZicaQ==

"@types/prop-types@*":
version "15.7.0"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.0.tgz#4c48fed958d6dcf9487195a0ef6456d5f6e0163a"
Expand All @@ -1236,6 +1241,13 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==

"@types/vue@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/vue/-/vue-2.0.0.tgz#ec77b3d89591deb9ca5cb052368aa9c32be088e7"
integrity sha1-7Hez2JWR3rnKXLBSNoqpwyvgiOc=
dependencies:
vue "*"

"@types/yargs@^12.0.2", "@types/yargs@^12.0.9":
version "12.0.10"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.10.tgz#17a8ec65cd8e88f51b418ceb271af18d3137df67"
Expand Down Expand Up @@ -5412,6 +5424,11 @@ [email protected]:
core-util-is "1.0.2"
extsprintf "^1.2.0"

vue@*, vue@^2.6.10:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==

w3c-hr-time@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
Expand Down

0 comments on commit d3ff9a8

Please sign in to comment.