From 46955585228f387ee525c7bfc492d6b51978d558 Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Thu, 13 Jul 2017 13:57:34 +0300 Subject: [PATCH 1/3] Add addon composition --- addons/notes/src/index.js | 6 ++ .../.storybook/addon-composition.js | 59 +++++++++++++++ .../cra-kitchen-sink/.storybook/config.js | 2 + .../cra-kitchen-sink/src/stories/index.js | 75 +++++-------------- 4 files changed, 87 insertions(+), 55 deletions(-) create mode 100644 examples/cra-kitchen-sink/.storybook/addon-composition.js diff --git a/addons/notes/src/index.js b/addons/notes/src/index.js index d7202a3d757c..20a6d61d5f5b 100644 --- a/addons/notes/src/index.js +++ b/addons/notes/src/index.js @@ -12,6 +12,12 @@ export const addonNotes = ({ notes }) => { }; }; +export const withNotes = (storyFn, context, notes) => { + const channel = addons.getChannel(); + channel.emit('storybook/notes/add_notes', notes); + return storyFn(context); +}; + Object.defineProperty(exports, 'WithNotes', { configurable: true, enumerable: true, diff --git a/examples/cra-kitchen-sink/.storybook/addon-composition.js b/examples/cra-kitchen-sink/.storybook/addon-composition.js new file mode 100644 index 000000000000..dfd3454d02c9 --- /dev/null +++ b/examples/cra-kitchen-sink/.storybook/addon-composition.js @@ -0,0 +1,59 @@ +import React from 'react'; + +function addX(story, context, options) { + console.log(options); + return story(context); +} + +export default { + getAddons(...addons) { + console.log(addons); + this._add = this.add; + + this.add = (name, storyFn) => { + + const apiFn = (context) => { + let writtingStory = null; + + const apiContext = { + ...context, + cleanStory: null, + }; + + apiContext.storyOf = (component) => { + if (typeof addonFn === 'function') { + writtingStory = component(cleanStory); + } else { + writtingStory = component; + } + apiContext.cleanStory = writtingStory; + return apiContext; + }; + // withX(...props) { + // writtingStory = addX(() => writtingStory, context, ...props); + // return apiContext; + // } + // }; + + addons.forEach((addonFn, ind) => { + if (typeof addonFn === 'function') { + const name = addonFn.name || `with${ind}`; + apiContext[name] = (...props) => { + writtingStory = addonFn(() => writtingStory, context, ...props); + // apiContext.cleanStory + return apiContext; + } + } + }); + + const result = storyFn(apiContext); + if (result === apiContext) { + return writtingStory; + } else { + return result; + } + }; + return this._add(name, apiFn) + } + } +}; diff --git a/examples/cra-kitchen-sink/.storybook/config.js b/examples/cra-kitchen-sink/.storybook/config.js index d1ed22531245..65a222da1a26 100644 --- a/examples/cra-kitchen-sink/.storybook/config.js +++ b/examples/cra-kitchen-sink/.storybook/config.js @@ -1,6 +1,7 @@ import { configure, setAddon } from '@storybook/react'; import { setOptions } from '@storybook/addon-options'; import infoAddon from '@storybook/addon-info'; +import getAddons from './addon-composition'; setOptions({ name: 'CRA Kitchen Sink', @@ -15,6 +16,7 @@ setOptions({ }); setAddon(infoAddon); +setAddon(getAddons); function loadStories() { require('../src/stories'); diff --git a/examples/cra-kitchen-sink/src/stories/index.js b/examples/cra-kitchen-sink/src/stories/index.js index e308ad065114..46bd262f5c3c 100644 --- a/examples/cra-kitchen-sink/src/stories/index.js +++ b/examples/cra-kitchen-sink/src/stories/index.js @@ -3,7 +3,7 @@ import EventEmiter from 'eventemitter3'; import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import { addonNotes, WithNotes } from '@storybook/addon-notes'; +import { addonNotes, WithNotes, withNotes } from '@storybook/addon-notes'; import { linkTo } from '@storybook/addon-links'; import WithEvents from '@storybook/addon-events'; import { @@ -19,7 +19,7 @@ import { object, } from '@storybook/addon-knobs'; import centered from '@storybook/addon-centered'; -import { withInfo } from '@storybook/addon-info'; +import { withInfo, addInfo } from '@storybook/addon-info'; import { Button, Welcome } from '@storybook/react/demo'; @@ -54,8 +54,25 @@ const InfoButton = () => {' '}Show Info{' '} ; +const withBorder = (storyFn, context, color) => +
+ {storyFn()} +
; + storiesOf('Button', module) - .addDecorator(withKnobs) + .getAddons(addInfo, withNotes, withBorder) + .addDecorator((storyFn, context) => withBorder(storyFn, context, 'gray')) + .add('with addons', context => + context + .storyOf( + + ) + .withBorder('red') + .addInfo({ info: 'Addons composition', _options: { inline: true } }) + .withNotes('Addons composition') + ) .add('with text', () => ) .add('with some emoji', () => ) .add('with notes', () => @@ -63,58 +80,6 @@ storiesOf('Button', module) ) - .add('with knobs', () => { - const name = text('Name', 'Storyteller'); - const age = number('Age', 70, { range: true, min: 0, max: 90, step: 5 }); - const fruits = { - apple: 'Apple', - banana: 'Banana', - cherry: 'Cherry', - }; - const fruit = select('Fruit', fruits, 'apple'); - const dollars = number('Dollars', 12.5); - - // NOTE: color picker is currently broken - const backgroundColor = color('background', '#ffff00'); - const items = array('Items', ['Laptop', 'Book', 'Whiskey']); - const otherStyles = object('Styles', { - border: '3px solid #ff00ff', - padding: '10px', - }); - const nice = boolean('Nice', true); - - // NOTE: put this last because it currently breaks everything after it :D - const birthday = date('Birthday', new Date('Jan 20 2017')); - - const intro = `My name is ${name}, I'm ${age} years old, and my favorite fruit is ${fruit}.`; - const style = { backgroundColor, ...otherStyles }; - const salutation = nice ? 'Nice to meet you!' : 'Leave me alone!'; - - return ( -
-

- {intro} -

-

- My birthday is: {new Date(birthday).toLocaleDateString()} -

-

- My wallet contains: ${dollars.toFixed(2)} -

-

In my backpack, I have:

- -

- {salutation} -

-
- ); - }) .addWithInfo( 'with some info', 'Use the [info addon](https://github.com/storybooks/storybook/tree/master/addons/info) with its painful API.', From c102c37bc07589a9ddd3cb75726856b7882de61b Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Thu, 13 Jul 2017 16:48:56 +0300 Subject: [PATCH 2/3] Full example --- .../.storybook/addon-composition.js | 16 ++------------- .../cra-kitchen-sink/src/stories/index.js | 20 +++++++++---------- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/examples/cra-kitchen-sink/.storybook/addon-composition.js b/examples/cra-kitchen-sink/.storybook/addon-composition.js index dfd3454d02c9..7b072049b741 100644 --- a/examples/cra-kitchen-sink/.storybook/addon-composition.js +++ b/examples/cra-kitchen-sink/.storybook/addon-composition.js @@ -1,13 +1,7 @@ import React from 'react'; -function addX(story, context, options) { - console.log(options); - return story(context); -} - export default { getAddons(...addons) { - console.log(addons); this._add = this.add; this.add = (name, storyFn) => { @@ -21,26 +15,20 @@ export default { }; apiContext.storyOf = (component) => { - if (typeof addonFn === 'function') { - writtingStory = component(cleanStory); + if (typeof component === 'function') { + writtingStory = component(apiContext.cleanStory); } else { writtingStory = component; } apiContext.cleanStory = writtingStory; return apiContext; }; - // withX(...props) { - // writtingStory = addX(() => writtingStory, context, ...props); - // return apiContext; - // } - // }; addons.forEach((addonFn, ind) => { if (typeof addonFn === 'function') { const name = addonFn.name || `with${ind}`; apiContext[name] = (...props) => { writtingStory = addonFn(() => writtingStory, context, ...props); - // apiContext.cleanStory return apiContext; } } diff --git a/examples/cra-kitchen-sink/src/stories/index.js b/examples/cra-kitchen-sink/src/stories/index.js index 46bd262f5c3c..4dd52a50a42a 100644 --- a/examples/cra-kitchen-sink/src/stories/index.js +++ b/examples/cra-kitchen-sink/src/stories/index.js @@ -55,7 +55,7 @@ const InfoButton = () => ; const withBorder = (storyFn, context, color) => -
+
{storyFn()}
; @@ -69,9 +69,15 @@ storiesOf('Button', module) Context is a key. Do you want to know more about "{context.kind}/{context.story}"? ) - .withBorder('red') - .addInfo({ info: 'Addons composition', _options: { inline: true } }) .withNotes('Addons composition') + .withBorder('red') + .addInfo('Addons composition', { inline: true }) + .storyOf(prevStory => +
+ Press this button: + {prevStory} +
+ ) ) .add('with text', () => ) .add('with some emoji', () => ) @@ -80,14 +86,6 @@ storiesOf('Button', module) ) - .addWithInfo( - 'with some info', - 'Use the [info addon](https://github.com/storybooks/storybook/tree/master/addons/info) with its painful API.', - context => -
- click the label in top right for info about "{context.story}" -
- ) .add( 'with new info', withInfo( From ad98ab2a6697a2e650cf57a49f3a5810f9bc5c2a Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Thu, 13 Jul 2017 22:25:04 +0300 Subject: [PATCH 3/3] Short example --- examples/cra-kitchen-sink/src/stories/index.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/cra-kitchen-sink/src/stories/index.js b/examples/cra-kitchen-sink/src/stories/index.js index 4dd52a50a42a..a2d31834311e 100644 --- a/examples/cra-kitchen-sink/src/stories/index.js +++ b/examples/cra-kitchen-sink/src/stories/index.js @@ -54,14 +54,13 @@ const InfoButton = () => {' '}Show Info{' '} ; -const withBorder = (storyFn, context, color) => -
+const withBorder = (storyFn, context, bcolor) => +
{storyFn()}
; storiesOf('Button', module) .getAddons(addInfo, withNotes, withBorder) - .addDecorator((storyFn, context) => withBorder(storyFn, context, 'gray')) .add('with addons', context => context .storyOf( @@ -71,13 +70,7 @@ storiesOf('Button', module) ) .withNotes('Addons composition') .withBorder('red') - .addInfo('Addons composition', { inline: true }) - .storyOf(prevStory => -
- Press this button: - {prevStory} -
- ) + .addInfo('Addons composition', { inline: false }) ) .add('with text', () => ) .add('with some emoji', () => )