Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor knobs - no longer include all runtimes #1832

Merged
merged 5 commits into from
Sep 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 40 additions & 19 deletions addons/knobs/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# Storybook Addon Knobs

Storybook Addon Knobs allow you to edit React props dynamically using the Storybook UI.
You can also use Knobs as a dynamic variable inside stories in [Storybook](https://storybook.js.org).

[![Greenkeeper badge](https://badges.greenkeeper.io/storybooks/storybook.svg)](https://greenkeeper.io/)
[![Build Status](https://travis-ci.org/storybooks/storybook.svg?branch=master)](https://travis-ci.org/storybooks/storybook)
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://storybooks-slackin.herokuapp.com/badge.svg)](https://storybooks-slackin.herokuapp.com/)

Storybook Addon Knobs allow you to edit React props dynamically using the Storybook UI.
You can also use Knobs as a dynamic variable inside stories in [Storybook](https://storybook.js.org).
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-nqnzoygycp.now.sh/badge.svg)](https://now-examples-slackin-nqnzoygycp.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)

This addon works with Storybook for:
[React](https://github.com/storybooks/storybook/tree/master/app/react).
[React Native](https://github.com/storybooks/storybook/tree/master/app/react-native).
[Vue](https://github.com/storybooks/storybook/tree/master/app/vue).

This is how Knobs look like:

Expand All @@ -37,7 +40,7 @@ Now, write your stories with knobs.

```js
import { storiesOf } from '@storybook/react';
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs';
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';

const stories = storiesOf('Storybook Knobs', module);

Expand All @@ -50,7 +53,7 @@ stories.add('with a button', () => (
<button disabled={boolean('Disabled', false)} >
{text('Label', 'Hello Button')}
</button>
))
));

// Knobs as dynamic variables.
stories.add('as dynamic variables', () => {
Expand All @@ -62,6 +65,20 @@ stories.add('as dynamic variables', () => {
});
```

> In the case of Vue, use these imports:
>
> ```js
> import { storiesOf } from '@storybook/vue';
> import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/vue';
> ```
>
> In the case of React-Native, use these imports:
>
> ```js
> import { storiesOf } from '@storybook/react-native';
> import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';
> ```

You can see your Knobs in a Storybook panel as shown below.

![](docs/demo.png)
Expand Down Expand Up @@ -89,7 +106,7 @@ Just like that, you can import any other following Knobs:
Allows you to get some text from the user.

```js
import { text } from '@storybook/addon-knobs';
import { text } from '@storybook/addon-knobs/react';

const label = 'Your Name';
const defaultValue = 'Arunoda Susiripala';
Expand All @@ -102,7 +119,7 @@ const value = text(label, defaultValue);
Allows you to get a boolean value from the user.

```js
import { boolean } from '@storybook/addon-knobs';
import { boolean } from '@storybook/addon-knobs/react';

const label = 'Agree?';
const defaultValue = false;
Expand All @@ -115,7 +132,7 @@ const value = boolean(label, defaultValue);
Allows you to get a number from the user.

```js
import { number } from '@storybook/addon-knobs';
import { number } from '@storybook/addon-knobs/react';

const label = 'Age';
const defaultValue = 78;
Expand All @@ -128,7 +145,7 @@ const value = number(label, defaultValue);
Allows you to get a number from the user using a range slider.

```js
import { number } from '@storybook/addon-knobs';
import { number } from '@storybook/addon-knobs/react';

const label = 'Temperature';
const defaultValue = 73;
Expand All @@ -147,7 +164,7 @@ const value = number(label, defaultValue, options);
Allows you to get a colour from the user.

```js
import { color } from '@storybook/addon-knobs';
import { color } from '@storybook/addon-knobs/react';

const label = 'Color';
const defaultValue = '#ff00ff';
Expand All @@ -160,7 +177,7 @@ const value = color(label, defaultValue);
Allows you to get a JSON object or array from the user.

```js
import { object } from '@storybook/addon-knobs';
import { object } from '@storybook/addon-knobs/react';

const label = 'Styles';
const defaultValue = {
Expand All @@ -177,7 +194,7 @@ const value = object(label, defaultValue);
Allows you to get an array of strings from the user.

```js
import { array } from '@storybook/addon-knobs';
import { array } from '@storybook/addon-knobs/react';

const label = 'Styles';
const defaultValue = ['Red']
Expand All @@ -189,7 +206,7 @@ const value = array(label, defaultValue);
> By default it's a comma, but this can be override by passing a separator variable.
>
> ```js
> import { array } from '@storybook/addon-knobs';
> import { array } from '@storybook/addon-knobs/react';
>
> const label = 'Styles';
> const defaultValue = ['Red'];
Expand All @@ -202,7 +219,7 @@ const value = array(label, defaultValue);
Allows you to get a value from a select box from the user.

```js
import { select } from '@storybook/addon-knobs';
import { select } from '@storybook/addon-knobs/react';

const label = 'Colors';
const options = {
Expand All @@ -222,7 +239,7 @@ const value = select(label, options, defaultValue);
Allow you to get date (and time) from the user.

```js
import { date } from '@storybook/addon-knobs';
import { date } from '@storybook/addon-knobs/react';

const label = 'Event Date';
const defaultValue = new Date('Jan 20 2017');
Expand All @@ -237,7 +254,11 @@ If you feel like this addon is not performing well enough there is an option to
Usage:

```js
story.addDecorator(withKnobsOptions({
import { storiesOf } from '@storybook/react';

const stories = storiesOf('Storybook Knobs', module);

stories.addDecorator(withKnobsOptions({
debounce: { wait: number, leading: boolean}, // Same as lodash debounce.
timestamps: true // Doesn't emit events while user is typing.
}));
Expand Down
1 change: 1 addition & 0 deletions addons/knobs/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/react');
55 changes: 55 additions & 0 deletions addons/knobs/src/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import KnobManager from './KnobManager';

export const manager = new KnobManager();

export function knob(name, options) {
return manager.knob(name, options);
}

export function text(name, value) {
return manager.knob(name, { type: 'text', value });
}

export function boolean(name, value) {
return manager.knob(name, { type: 'boolean', value });
}

export function number(name, value, options = {}) {
const defaults = {
range: false,
min: 0,
max: 10,
step: 1,
};

const mergedOptions = { ...defaults, ...options };

const finalOptions = {
...mergedOptions,
type: 'number',
value,
};

return manager.knob(name, finalOptions);
}

export function color(name, value) {
return manager.knob(name, { type: 'color', value });
}

export function object(name, value) {
return manager.knob(name, { type: 'object', value });
}

export function select(name, options, value) {
return manager.knob(name, { type: 'select', options, value });
}

export function array(name, value, separator = ',') {
return manager.knob(name, { type: 'array', value, separator });
}

export function date(name, value = new Date()) {
const proxyValue = value ? value.getTime() : null;
return manager.knob(name, { type: 'date', value: proxyValue });
}
65 changes: 10 additions & 55 deletions addons/knobs/src/index.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,21 @@
import { window } from 'global';
import deprecate from 'util-deprecate';
import addons from '@storybook/addons';
import KnobManager from './KnobManager';

import { vueHandler } from './vue';
import { reactHandler } from './react';

const manager = new KnobManager();

export function knob(name, options) {
return manager.knob(name, options);
}

export function text(name, value) {
return manager.knob(name, { type: 'text', value });
}

export function boolean(name, value) {
return manager.knob(name, { type: 'boolean', value });
}

export function number(name, value, options = {}) {
const defaults = {
range: false,
min: 0,
max: 10,
step: 1,
};

const mergedOptions = { ...defaults, ...options };

const finalOptions = {
...mergedOptions,
type: 'number',
value,
};
import { knob, text, boolean, number, color, object, array, date, manager } from './base';

return manager.knob(name, finalOptions);
}

export function color(name, value) {
return manager.knob(name, { type: 'color', value });
}

export function object(name, value) {
return manager.knob(name, { type: 'object', value });
}
export { knob, text, boolean, number, color, object, array, date };

export function select(name, options, value) {
return manager.knob(name, { type: 'select', options, value });
}

export function array(name, value, separator = ',') {
return manager.knob(name, { type: 'array', value, separator });
}

export function date(name, value = new Date()) {
const proxyValue = value ? value.getTime() : null;
return manager.knob(name, { type: 'date', value: proxyValue });
}
deprecate(
() => {},
'Using @storybook/addon-knobs directly is discouraged, please use @storybook/addon-knobs/{{framework}}'
);

// "Higher order component" / wrapper style API
// In 3.3, this will become `withKnobs`, once our decorator API supports it.
// See https://github.com/storybooks/storybook/pull/1527
// generic higher-order component decorator for all platforms - usage is discouraged
// This file Should be removed with 4.0 release
function wrapperKnobs(options) {
const channel = addons.getChannel();
manager.setChannel(channel);
Expand Down
26 changes: 23 additions & 3 deletions addons/knobs/src/react/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import React from 'react';
import addons from '@storybook/addons';

import WrapStory from './WrapStory';

/**
* Handles a react story
*/
import { knob, text, boolean, number, color, object, array, date, select, manager } from '../base';

export { knob, text, boolean, number, color, object, array, date, select };

export const reactHandler = (channel, knobStore) => getStory => context => {
const initialContent = getStory(context);
const props = { context, storyFn: getStory, channel, knobStore, initialContent };
return <WrapStory {...props} />;
};

function wrapperKnobs(options) {
const channel = addons.getChannel();
manager.setChannel(channel);

if (options) channel.emit('addon:knobs:setOptions', options);

return reactHandler(channel, manager.knobStore);
}

export function withKnobs(storyFn, context) {
return wrapperKnobs()(storyFn)(context);
}

export function withKnobsOptions(options = {}) {
return (storyFn, context) => wrapperKnobs(options)(storyFn)(context);
}
23 changes: 23 additions & 0 deletions addons/knobs/src/vue/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import addons from '@storybook/addons';

import { knob, text, boolean, number, color, object, array, date, select, manager } from '../base';

export { knob, text, boolean, number, color, object, array, date, select };

export const vueHandler = (channel, knobStore) => getStory => context => ({
render(h) {
return h(getStory(context));
Expand Down Expand Up @@ -35,3 +41,20 @@ export const vueHandler = (channel, knobStore) => getStory => context => ({
knobStore.unsubscribe(this.setPaneKnobs);
},
});

function wrapperKnobs(options) {
const channel = addons.getChannel();
manager.setChannel(channel);

if (options) channel.emit('addon:knobs:setOptions', options);

return vueHandler(channel, manager.knobStore);
}

export function withKnobs(storyFn, context) {
return wrapperKnobs()(storyFn)(context);
}

export function withKnobsOptions(options = {}) {
return (storyFn, context) => wrapperKnobs(options)(storyFn)(context);
}
1 change: 1 addition & 0 deletions addons/knobs/vue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/vue');
2 changes: 1 addition & 1 deletion examples/cra-kitchen-sink/src/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
array,
date,
object,
} from '@storybook/addon-knobs';
} from '@storybook/addon-knobs/react';
import centered from '@storybook/addon-centered';
import { withInfo } from '@storybook/addon-info';

Expand Down
11 changes: 10 additions & 1 deletion examples/crna-kitchen-sink/storybook/stories/Knobs/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import React from 'react';
import { View, Text } from 'react-native';

import { text, number, boolean, color, select, array, date, object } from '@storybook/addon-knobs';
import {
text,
number,
boolean,
color,
select,
array,
date,
object,
} from '@storybook/addon-knobs/react';

export default () => {
const name = text('Name', 'Storyteller');
Expand Down
Loading