diff --git a/app/angular/src/client/index.js b/app/angular/src/client/index.js index ae0b8377b4d0..69d18178d225 100644 --- a/app/angular/src/client/index.js +++ b/app/angular/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; export { moduleMetadata } from './preview/angular/decorators'; diff --git a/app/angular/src/client/preview/index.js b/app/angular/src/client/preview/index.js index 877b04bca126..ceef96e9559b 100644 --- a/app/angular/src/client/preview/index.js +++ b/app/angular/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'angular'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/ember/src/client/index.js b/app/ember/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/ember/src/client/index.js +++ b/app/ember/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/ember/src/client/preview/index.js b/app/ember/src/client/preview/index.js index 877b04bca126..0f1db6ca1d4b 100644 --- a/app/ember/src/client/preview/index.js +++ b/app/ember/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'ember'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/html/src/client/index.js b/app/html/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/html/src/client/index.js +++ b/app/html/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/html/src/client/preview/index.js b/app/html/src/client/preview/index.js index 877b04bca126..c1ac22948c0a 100644 --- a/app/html/src/client/preview/index.js +++ b/app/html/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'html'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/marko/src/client/index.js b/app/marko/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/marko/src/client/index.js +++ b/app/marko/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/marko/src/client/preview/index.js b/app/marko/src/client/preview/index.js index 877b04bca126..120337969ee0 100644 --- a/app/marko/src/client/preview/index.js +++ b/app/marko/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'marko'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/mithril/src/client/index.js b/app/mithril/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/mithril/src/client/index.js +++ b/app/mithril/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/mithril/src/client/preview/index.js b/app/mithril/src/client/preview/index.js index 877b04bca126..3a7260766303 100644 --- a/app/mithril/src/client/preview/index.js +++ b/app/mithril/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'mithril'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/polymer/src/client/index.js b/app/polymer/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/polymer/src/client/index.js +++ b/app/polymer/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/polymer/src/client/preview/index.js b/app/polymer/src/client/preview/index.js index 877b04bca126..f0eecfaa929b 100644 --- a/app/polymer/src/client/preview/index.js +++ b/app/polymer/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'polymer'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/preact/src/client/index.js b/app/preact/src/client/index.js index 21d3f4bf39c9..17b16c61bc58 100644 --- a/app/preact/src/client/index.js +++ b/app/preact/src/client/index.js @@ -7,4 +7,5 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; diff --git a/app/preact/src/client/preview/index.js b/app/preact/src/client/preview/index.js index 877b04bca126..24ed7d776326 100644 --- a/app/preact/src/client/preview/index.js +++ b/app/preact/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'preact'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/react-native/src/index.ts b/app/react-native/src/index.ts index 5ab573d3f77e..98b2a8d5c06e 100644 --- a/app/react-native/src/index.ts +++ b/app/react-native/src/index.ts @@ -2,7 +2,7 @@ import Preview from './preview'; const preview = new Preview(); -export const storiesOf = preview.api().storiesOf.bind(preview); +const rawStoriesOf = preview.api().storiesOf.bind(preview); export const setAddon = preview.api().setAddon.bind(preview); export const addDecorator = preview.api().addDecorator.bind(preview); export const addParameters = preview.api().addParameters.bind(preview); @@ -11,3 +11,6 @@ export const configure = preview.configure; export const getStorybook = preview.api().getStorybook.bind(preview); export const getStorybookUI = preview.getStorybookUI; export const raw = preview.api().raw.bind(preview); + +export const storiesOf = (...args: any[]) => + rawStoriesOf(...args).addParameters({ framework: 'react-native' }); diff --git a/app/react/src/client/index.js b/app/react/src/client/index.js index 57c4a7e7381e..fd2728055bb7 100644 --- a/app/react/src/client/index.js +++ b/app/react/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, raw, forceReRender, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/react/src/client/preview/index.js b/app/react/src/client/preview/index.js index 877b04bca126..43a5688e3f7c 100644 --- a/app/react/src/client/preview/index.js +++ b/app/react/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'react'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/riot/src/client/index.js b/app/riot/src/client/index.js index 63cdd10a4d13..f85aa98cd81e 100644 --- a/app/riot/src/client/index.js +++ b/app/riot/src/client/index.js @@ -12,6 +12,7 @@ export { compileNow, asCompiledCode, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/riot/src/client/preview/index.js b/app/riot/src/client/preview/index.js index 0c26e0ec9ec8..e88be225239a 100644 --- a/app/riot/src/client/preview/index.js +++ b/app/riot/src/client/preview/index.js @@ -5,10 +5,9 @@ import riot, { tag2, mount as vendorMount } from 'riot'; import render from './render'; import { compileNow as unboundCompileNow, asCompiledCode } from './compileStageFunctions'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -17,6 +16,10 @@ export const { raw, } = clientApi; +const framework = 'riot'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; const mount = vendorMount.bind(riot, '#root'); const compileNow = unboundCompileNow.bind(null, tag2); diff --git a/app/svelte/src/client/index.js b/app/svelte/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/svelte/src/client/index.js +++ b/app/svelte/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/svelte/src/client/preview/index.js b/app/svelte/src/client/preview/index.js index 877b04bca126..abfe16ee830a 100644 --- a/app/svelte/src/client/preview/index.js +++ b/app/svelte/src/client/preview/index.js @@ -3,10 +3,9 @@ import { start } from '@storybook/core/client'; import './globals'; import render from './render'; -const { clientApi, configApi, forceReRender } = start(render); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -15,5 +14,9 @@ export const { raw, } = clientApi; +const framework = 'svelte'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/app/vue/src/client/index.js b/app/vue/src/client/index.js index 8034a9d6433d..c3f87077b852 100644 --- a/app/vue/src/client/index.js +++ b/app/vue/src/client/index.js @@ -7,6 +7,7 @@ export { getStorybook, forceReRender, raw, + load, } from './preview'; if (module && module.hot && module.hot.decline) { diff --git a/app/vue/src/client/preview/index.js b/app/vue/src/client/preview/index.js index fcce19ac10d7..71d6fbe03b74 100644 --- a/app/vue/src/client/preview/index.js +++ b/app/vue/src/client/preview/index.js @@ -70,10 +70,9 @@ function decorateStory(getStory, decorators) { ); } -const { clientApi, configApi, forceReRender } = start(render, { decorateStory }); +const { load: coreLoad, clientApi, configApi, forceReRender } = start(render, { decorateStory }); export const { - storiesOf, setAddon, addDecorator, addParameters, @@ -82,5 +81,9 @@ export const { raw, } = clientApi; +const framework = 'vue'; +export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework }); +export const load = (...args) => coreLoad(...args, framework); + export const { configure } = configApi; export { forceReRender }; diff --git a/examples/angular-cli/src/stories/__snapshots__/core.stories.storyshot b/examples/angular-cli/src/stories/__snapshots__/core.stories.storyshot index 3cd3e7cbbba7..0025d65968cf 100644 --- a/examples/angular-cli/src/stories/__snapshots__/core.stories.storyshot +++ b/examples/angular-cli/src/stories/__snapshots__/core.stories.storyshot @@ -12,7 +12,7 @@ exports[`Storyshots Core|Parameters passed to story 1`] = ` diff --git a/examples/official-storybook/config.js b/examples/official-storybook/config.js index a8c0cc7cba6f..2e996bd8c0ca 100644 --- a/examples/official-storybook/config.js +++ b/examples/official-storybook/config.js @@ -1,5 +1,5 @@ import React from 'react'; -import { storiesOf, configure, addDecorator, addParameters } from '@storybook/react'; +import { load, addDecorator, addParameters } from '@storybook/react'; import { Global, ThemeProvider, themes, createReset, convert } from '@storybook/theming'; import { withCssResources } from '@storybook/addon-cssresources'; @@ -58,75 +58,6 @@ addParameters({ ], }); -let previousExports = {}; -if (module && module.hot && module.hot.dispose) { - ({ previousExports = {} } = module.hot.data || {}); - - module.hot.dispose(data => { - // eslint-disable-next-line no-param-reassign - data.previousExports = previousExports; - }); -} - -// The simplest version of examples would just export this function for users to use -function importAll(context) { - const storyStore = window.__STORYBOOK_CLIENT_API__._storyStore; // eslint-disable-line no-undef, no-underscore-dangle - - context.keys().forEach(filename => { - const fileExports = context(filename); - - // A old-style story file - if (!fileExports.default) { - return; - } - - const { default: component, ...examples } = fileExports; - let componentOptions = component; - if (component.prototype && component.prototype.isReactComponent) { - componentOptions = { component }; - } - const kindName = componentOptions.title || componentOptions.component.displayName; - - if (previousExports[filename]) { - if (previousExports[filename] === fileExports) { - return; - } - - // Otherwise clear this kind - storyStore.removeStoryKind(kindName); - storyStore.incrementRevision(); - } - - // We pass true here to avoid the warning about HMR. It's cool clientApi, we got this - const kind = storiesOf(kindName, true); - - (componentOptions.decorators || []).forEach(decorator => { - kind.addDecorator(decorator); - }); - if (componentOptions.parameters) { - kind.addParameters(componentOptions.parameters); - } - - Object.keys(examples).forEach(key => { - const example = examples[key]; - const { title = key, parameters } = example; - kind.add(title, example, parameters); - }); - - previousExports[filename] = fileExports; - }); -} - -function loadStories() { - let req; - req = require.context('../../lib/ui/src', true, /\.stories\.js$/); - importAll(req); - - req = require.context('../../lib/components/src', true, /\.stories\.tsx?$/); - importAll(req); - - req = require.context('./stories', true, /\.stories\.js$/); - importAll(req); -} - -configure(loadStories, module); +load(require.context('../../lib/ui/src', true, /\.stories\.js$/), module); +load(require.context('../../lib/components/src', true, /\.stories\.tsx?$/), module); +load(require.context('./stories', true, /\.stories\.js$/), module); diff --git a/examples/riot-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot b/examples/riot-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot index 3ac3198ef022..2a250274756c 100644 --- a/examples/riot-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot +++ b/examples/riot-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot @@ -6,7 +6,7 @@ exports[`Storyshots Core|Parameters passed to story 1`] = ` id="root" >
- Parameters are {"options":{"hierarchyRootSeparator":{},"hierarchySeparator":{}},"globalParameter":"globalParameter","chapterParameter":"chapterParameter","storyParameter":"storyParameter","id":"root","dataIs":"parameters"} + Parameters are {"options":{"hierarchyRootSeparator":{},"hierarchySeparator":{}},"globalParameter":"globalParameter","framework":"riot","chapterParameter":"chapterParameter","storyParameter":"storyParameter","id":"root","dataIs":"parameters"}
`; diff --git a/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot b/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot index f94e524807e9..40d7a887f8a3 100644 --- a/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot +++ b/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot @@ -2,6 +2,6 @@ exports[`Storyshots Core|Parameters passed to story 1`] = `
- Parameters are {"options":{"hierarchyRootSeparator":{},"hierarchySeparator":{}},"globalParameter":"globalParameter","chapterParameter":"chapterParameter","storyParameter":"storyParameter"} + Parameters are {"options":{"hierarchyRootSeparator":{},"hierarchySeparator":{}},"globalParameter":"globalParameter","framework":"vue","chapterParameter":"chapterParameter","storyParameter":"storyParameter"}
`; diff --git a/lib/core/src/client/preview/start.js b/lib/core/src/client/preview/start.js index 5d5733afa1a1..584731412216 100644 --- a/lib/core/src/client/preview/start.js +++ b/lib/core/src/client/preview/start.js @@ -240,5 +240,67 @@ export default function start(render, { decorateStory } = {}) { window.__STORYBOOK_ADDONS_CHANNEL__ = channel; // may not be defined } - return { context, clientApi, configApi, forceReRender }; + let previousExports = {}; + const loadStories = (req, framework) => () => { + req.keys().forEach(filename => { + const fileExports = req(filename); + + // An old-style story file + if (!fileExports.default) { + return; + } + + if (!fileExports.default.title) { + throw new Error( + `Unexpected default export without title: ${JSON.stringify(fileExports.default)}` + ); + } + + const { default: meta, ...examples } = fileExports; + const kindName = meta.title; + + if (previousExports[filename]) { + if (previousExports[filename] === fileExports) { + return; + } + + // Otherwise clear this kind + storyStore.removeStoryKind(kindName); + storyStore.incrementRevision(); + } + + // We pass true here to avoid the warning about HMR. It's cool clientApi, we got this + const kind = clientApi.storiesOf(kindName, true); + kind.addParameters({ framework }); + + (meta.decorators || []).forEach(decorator => { + kind.addDecorator(decorator); + }); + if (meta.parameters) { + kind.addParameters(meta.parameters); + } + + Object.keys(examples).forEach(key => { + const example = examples[key]; + const { title = example.title || key, parameters } = example; + kind.add(title, example, parameters); + }); + + previousExports[filename] = fileExports; + }); + }; + + const load = (req, m, framework) => { + if (m && m.hot && m.hot.dispose) { + ({ previousExports = {} } = m.hot.data || {}); + + m.hot.dispose(data => { + // eslint-disable-next-line no-param-reassign + data.previousExports = previousExports; + }); + } + configApi.configure(loadStories(req, framework), m); + }; + + return { load, context, clientApi, configApi, forceReRender }; }