From 9d4aecc2850d339261a0586634e5640f7831ece5 Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Sat, 27 Jan 2018 19:37:33 -0500 Subject: [PATCH 1/8] first pass at files knob type --- .eslintrc.js | 1 + addons/knobs/src/base.js | 4 +++ addons/knobs/src/components/types/Files.js | 36 ++++++++++++++++++++++ addons/knobs/src/components/types/index.js | 2 ++ addons/knobs/src/index.js | 3 +- addons/knobs/src/react/index.js | 3 +- addons/knobs/src/vue/index.js | 3 +- 7 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 addons/knobs/src/components/types/Files.js diff --git a/.eslintrc.js b/.eslintrc.js index ec55d7a46309..1ced19ffc135 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,6 +11,7 @@ module.exports = { sourceType: 'module', }, env: { + browser: true, es6: true, node: true, 'jest/globals': true, diff --git a/addons/knobs/src/base.js b/addons/knobs/src/base.js index 41597325b2b3..93cd3df1895d 100644 --- a/addons/knobs/src/base.js +++ b/addons/knobs/src/base.js @@ -61,3 +61,7 @@ export function date(name, value = new Date()) { export function button(name, callback) { return manager.knob(name, { type: 'button', callback, hideLabel: true }); } + +export function files(name, value = []) { + return manager.knob(name, { type: 'files', value }); +} diff --git a/addons/knobs/src/components/types/Files.js b/addons/knobs/src/components/types/Files.js new file mode 100644 index 000000000000..8eb73a5a2984 --- /dev/null +++ b/addons/knobs/src/components/types/Files.js @@ -0,0 +1,36 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +function fileReaderPromise(file) { + return new Promise(resolve => { + const fileReader = new FileReader(); + fileReader.onload = e => resolve(e.currentTarget.result); + fileReader.readAsDataURL(file); + }); +} + +const FilesType = ({ knob, onChange }) => ( + Promise.all(Array.from(e.target.files).map(fileReaderPromise)).then(onChange)} + /> +); + +FilesType.defaultProps = { + knob: {}, + onChange: value => value, +}; + +FilesType.propTypes = { + knob: PropTypes.shape({ + name: PropTypes.string, + }), + onChange: PropTypes.func, +}; + +FilesType.serialize = () => undefined; +FilesType.deserialize = () => undefined; + +export default FilesType; diff --git a/addons/knobs/src/components/types/index.js b/addons/knobs/src/components/types/index.js index ebd51deb858e..8b99c3e3f908 100644 --- a/addons/knobs/src/components/types/index.js +++ b/addons/knobs/src/components/types/index.js @@ -7,6 +7,7 @@ import SelectType from './Select'; import ArrayType from './Array'; import DateType from './Date'; import ButtonType from './Button'; +import FilesType from './Files'; export default { text: TextType, @@ -18,4 +19,5 @@ export default { array: ArrayType, date: DateType, button: ButtonType, + files: FilesType, }; diff --git a/addons/knobs/src/index.js b/addons/knobs/src/index.js index 7a4109270d06..a7166da4ce18 100644 --- a/addons/knobs/src/index.js +++ b/addons/knobs/src/index.js @@ -9,6 +9,7 @@ import { array, boolean, button, + files, color, date, knob, @@ -19,7 +20,7 @@ import { text, } from './base'; -export { knob, text, boolean, number, color, object, array, date, button, select }; +export { knob, text, boolean, number, color, object, array, date, button, files, select }; deprecate(() => {}, 'Using @storybook/addon-knobs directly is discouraged, please use @storybook/addon-knobs/{{framework}}'); diff --git a/addons/knobs/src/react/index.js b/addons/knobs/src/react/index.js index f4f2ddccc0b4..fe0e5fa71c0a 100644 --- a/addons/knobs/src/react/index.js +++ b/addons/knobs/src/react/index.js @@ -14,10 +14,11 @@ import { date, select, button, + files, manager, } from '../base'; -export { knob, text, boolean, number, color, object, array, date, select, button }; +export { knob, text, boolean, number, color, object, array, date, select, button, files }; export const reactHandler = (channel, knobStore) => getStory => context => { const initialContent = getStory(context); diff --git a/addons/knobs/src/vue/index.js b/addons/knobs/src/vue/index.js index d5cddbf0f790..8873bef3fd2c 100644 --- a/addons/knobs/src/vue/index.js +++ b/addons/knobs/src/vue/index.js @@ -11,10 +11,11 @@ import { date, select, button, + files, manager, } from '../base'; -export { knob, text, boolean, number, color, object, array, date, select, button }; +export { knob, text, boolean, number, color, object, array, date, select, button, files }; export const vueHandler = (channel, knobStore) => getStory => context => ({ data() { From 1f3a0117b94e36ba4a55b7ab70a5b6aba42574a7 Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Sun, 28 Jan 2018 14:16:43 -0500 Subject: [PATCH 2/8] adding files to all knobs story --- addons/knobs/example/stories/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/knobs/example/stories/index.js b/addons/knobs/example/stories/index.js index c295f90f9958..f4308fafb246 100644 --- a/addons/knobs/example/stories/index.js +++ b/addons/knobs/example/stories/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; import moment from 'moment'; -import { withKnobs, number, object, boolean, text, select, date, array, color } from '../../src'; +import { withKnobs, number, object, boolean, text, select, date, array, color, files } from '../../src'; const stories = storiesOf('Example of Knobs', module); @@ -20,6 +20,8 @@ stories.add('with all knobs', () => { const passions = array('Passions', ['Fishing', 'Skiing']); + const images = files('Happy Picture', ['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=']); + const customStyle = object('Style', { fontFamily: 'Arial', padding: 20, @@ -38,6 +40,7 @@ stories.add('with all knobs', () => { I like:

My favorite number is {favoriteNumber}.

My most comfortable room temperature is {comfortTemp} degrees Fahrenheit.

+

When I am happy I look like this:

); }); From 59d128697cec99a2020dabe38c6ddd36bb31346c Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Sun, 28 Jan 2018 14:25:25 -0500 Subject: [PATCH 3/8] updating readme --- addons/knobs/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/addons/knobs/README.md b/addons/knobs/README.md index 78b5039f760b..ab6f1e080852 100644 --- a/addons/knobs/README.md +++ b/addons/knobs/README.md @@ -247,6 +247,21 @@ const value = select(label, options, defaultValue); > You can also provide options as an array like this: `['red', 'blue', 'yellow']` +### files + +Allows you to get a value from a file input from the user. + +```js +import { files } from '@storybook/addon-knobs/react'; + +const label = 'Images'; +const defaultValue = []; + +const value = files(label, defaultValue); +``` + +> Multiple files can be selected, and will be returned as an array of [Data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) + ### date Allow you to get date (and time) from the user. From 37258a5c178edd11be18ce2d9c61da2a229a54bc Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Sun, 28 Jan 2018 15:52:17 -0500 Subject: [PATCH 4/8] importing filereader from global --- .eslintrc.js | 1 - addons/knobs/src/components/types/Files.js | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1ced19ffc135..ec55d7a46309 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,6 @@ module.exports = { sourceType: 'module', }, env: { - browser: true, es6: true, node: true, 'jest/globals': true, diff --git a/addons/knobs/src/components/types/Files.js b/addons/knobs/src/components/types/Files.js index 8eb73a5a2984..bc1fd1cc78f0 100644 --- a/addons/knobs/src/components/types/Files.js +++ b/addons/knobs/src/components/types/Files.js @@ -1,3 +1,4 @@ +import { FileReader } from 'global'; import PropTypes from 'prop-types'; import React from 'react'; From 30be96e039829de85fc561d240006ba4513f7c28 Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Wed, 28 Feb 2018 02:34:54 -0500 Subject: [PATCH 5/8] accept attribute --- addons/knobs/README.md | 2 +- addons/knobs/example/stories/index.js | 2 +- addons/knobs/src/base.js | 4 ++-- addons/knobs/src/components/types/Files.js | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/knobs/README.md b/addons/knobs/README.md index ab6f1e080852..1ef7664569d1 100644 --- a/addons/knobs/README.md +++ b/addons/knobs/README.md @@ -257,7 +257,7 @@ import { files } from '@storybook/addon-knobs/react'; const label = 'Images'; const defaultValue = []; -const value = files(label, defaultValue); +const value = files(label, accept, defaultValue); ``` > Multiple files can be selected, and will be returned as an array of [Data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) diff --git a/addons/knobs/example/stories/index.js b/addons/knobs/example/stories/index.js index f4308fafb246..05b1f36f1979 100644 --- a/addons/knobs/example/stories/index.js +++ b/addons/knobs/example/stories/index.js @@ -20,7 +20,7 @@ stories.add('with all knobs', () => { const passions = array('Passions', ['Fishing', 'Skiing']); - const images = files('Happy Picture', ['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=']); + const images = files('Happy Picture', 'image/*', ['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=']); const customStyle = object('Style', { fontFamily: 'Arial', diff --git a/addons/knobs/src/base.js b/addons/knobs/src/base.js index 93cd3df1895d..868da7e38d2e 100644 --- a/addons/knobs/src/base.js +++ b/addons/knobs/src/base.js @@ -62,6 +62,6 @@ export function button(name, callback) { return manager.knob(name, { type: 'button', callback, hideLabel: true }); } -export function files(name, value = []) { - return manager.knob(name, { type: 'files', value }); +export function files(name, accept, value = []) { + return manager.knob(name, { type: 'files', accept, value }); } diff --git a/addons/knobs/src/components/types/Files.js b/addons/knobs/src/components/types/Files.js index bc1fd1cc78f0..bff94041546e 100644 --- a/addons/knobs/src/components/types/Files.js +++ b/addons/knobs/src/components/types/Files.js @@ -16,6 +16,7 @@ const FilesType = ({ knob, onChange }) => ( type="file" multiple onChange={e => Promise.all(Array.from(e.target.files).map(fileReaderPromise)).then(onChange)} + accept={knob.accept} /> ); From 95881f255e7effb2cc6007e32f7512484dbce524 Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Wed, 28 Feb 2018 02:51:55 -0500 Subject: [PATCH 6/8] adding files knob import/export to polymer and vue files (untested) --- addons/knobs/src/angular/index.js | 3 ++- addons/knobs/src/polymer/index.js | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/addons/knobs/src/angular/index.js b/addons/knobs/src/angular/index.js index 03b581dfd110..1382fa9617b3 100644 --- a/addons/knobs/src/angular/index.js +++ b/addons/knobs/src/angular/index.js @@ -13,10 +13,11 @@ import { date, select, button, + files, manager, } from '../base'; -export { knob, text, boolean, number, color, object, array, date, select, button }; +export { knob, text, boolean, number, color, object, array, date, select, button, files }; export const angularHandler = (channel, knobStore) => getStory => context => prepareComponent({ getStory, context, channel, knobStore }); diff --git a/addons/knobs/src/polymer/index.js b/addons/knobs/src/polymer/index.js index 5bb16a890651..9454c665e0b8 100644 --- a/addons/knobs/src/polymer/index.js +++ b/addons/knobs/src/polymer/index.js @@ -2,9 +2,21 @@ import addons from '@storybook/addons'; import window from 'global'; import './WrapStory.html'; -import { knob, text, boolean, number, color, object, array, date, select, manager } from '../base'; - -export { knob, text, boolean, number, color, object, array, date, select }; +import { + knob, + text, + boolean, + number, + color, + object, + array, + date, + select, + files, + manager, +} from '../base'; + +export { knob, text, boolean, number, color, object, array, date, select, files }; export function button(name, callback) { return manager.knob(name, { type: 'button', value: Date.now(), callback, hideLabel: true }); From 2b67e010f50c8de4832f202ac46cacab61c73dfb Mon Sep 17 00:00:00 2001 From: Nic Luciano Date: Wed, 28 Feb 2018 02:52:14 -0500 Subject: [PATCH 7/8] adding knobs examples to examples/official-storybook --- .../stories/addon-knobs.stories.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/official-storybook/stories/addon-knobs.stories.js b/examples/official-storybook/stories/addon-knobs.stories.js index 50fda6c4d24e..8b14ce8d0bf2 100644 --- a/examples/official-storybook/stories/addon-knobs.stories.js +++ b/examples/official-storybook/stories/addon-knobs.stories.js @@ -13,6 +13,7 @@ import { date, button, object, + files, } from '@storybook/addon-knobs/react'; class AsyncItemLoader extends React.Component { @@ -66,6 +67,9 @@ storiesOf('Addons|Knobs.withKnobs', module) padding: '10px', }); const nice = boolean('Nice', true); + const images = files('Happy Picture', 'image/*', [ + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=', + ]); // NOTE: the default value must not change - e.g., do not do date('Label', new Date()) or date('Label') const defaultBirthday = new Date('Jan 20 2017 GMT+0'); @@ -85,6 +89,9 @@ storiesOf('Addons|Knobs.withKnobs', module)

In my backpack, I have:

    {items.map(item =>
  • {item}
  • )}

{salutation}

+

+ When I am happy I look like this: happy +


PS. My shirt pocket contains:

@@ -122,6 +129,9 @@ storiesOf('Addons|Knobs.withKnobsOptions', module) padding: '10px', }); const nice = boolean('Nice', true); + const images = files('Happy Picture', 'image/*', [ + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=', + ]); // NOTE: the default value must not change - e.g., do not do date('Label', new Date()) or date('Label') const defaultBirthday = new Date('Jan 20 2017 GMT+0'); @@ -144,6 +154,9 @@ storiesOf('Addons|Knobs.withKnobsOptions', module)

In my backpack, I have:

    {items.map(item =>
  • {item}
  • )}

{salutation}

+

+ When I am happy I look like this: happy +


PS. My shirt pocket contains:

From b57e8e7f38768b9bd77612ca68573aa48f582e62 Mon Sep 17 00:00:00 2001 From: Hypnosphi Date: Tue, 27 Mar 2018 03:59:33 +0300 Subject: [PATCH 8/8] Fix lint and tests --- addons/knobs/example/stories/index.js | 21 ++++++++++++++++--- .../addon-knobs.stories.storyshot | 14 +++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/addons/knobs/example/stories/index.js b/addons/knobs/example/stories/index.js index 8c400b8e26f9..bd4ec782a111 100644 --- a/addons/knobs/example/stories/index.js +++ b/addons/knobs/example/stories/index.js @@ -1,7 +1,18 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; import moment from 'moment'; -import { withKnobs, number, object, boolean, text, select, date, array, color, files } from '../../src'; +import { + withKnobs, + number, + object, + boolean, + text, + select, + date, + array, + color, + files, +} from '../../src'; const stories = storiesOf('Example of Knobs', module); @@ -20,7 +31,9 @@ stories.add('with all knobs', () => { const passions = array('Passions', ['Fishing', 'Skiing']); - const images = files('Happy Picture', 'image/*', ['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=']); + const images = files('Happy Picture', 'image/*', [ + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=', + ]); const customStyle = object('Style', { fontFamily: 'Arial', @@ -40,7 +53,9 @@ stories.add('with all knobs', () => {
    {passions.map(p =>
  • {p}
  • )}

My favorite number is {favoriteNumber}.

My most comfortable room temperature is {comfortTemp} degrees Fahrenheit.

-

When I am happy I look like this:

+

+ When I am happy I look like this: happy +

); }); diff --git a/examples/official-storybook/stories/__snapshots__/addon-knobs.stories.storyshot b/examples/official-storybook/stories/__snapshots__/addon-knobs.stories.storyshot index 1a1cb2209103..01efdf0c4570 100644 --- a/examples/official-storybook/stories/__snapshots__/addon-knobs.stories.storyshot +++ b/examples/official-storybook/stories/__snapshots__/addon-knobs.stories.storyshot @@ -44,6 +44,13 @@ exports[`Storyshots Addons|Knobs.withKnobs tweaks static values 1`] = `

Nice to meet you!

+

+ When I am happy I look like this: + happy +


PS. My shirt pocket contains: @@ -147,6 +154,13 @@ exports[`Storyshots Addons|Knobs.withKnobsOptions tweaks static values with debo

Nice to meet you!

+

+ When I am happy I look like this: + happy +


PS. My shirt pocket contains: