diff --git a/addons/knobs/README.md b/addons/knobs/README.md
index 2da303546409..123dfbe59424 100644
--- a/addons/knobs/README.md
+++ b/addons/knobs/README.md
@@ -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:
@@ -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);
@@ -50,7 +53,7 @@ stories.add('with a button', () => (
-))
+));
// Knobs as dynamic variables.
stories.add('as dynamic variables', () => {
@@ -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)
@@ -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';
@@ -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;
@@ -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;
@@ -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;
@@ -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';
@@ -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 = {
@@ -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']
@@ -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'];
@@ -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 = {
@@ -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');
@@ -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.
}));
diff --git a/addons/knobs/react.js b/addons/knobs/react.js
new file mode 100644
index 000000000000..70e1111ae070
--- /dev/null
+++ b/addons/knobs/react.js
@@ -0,0 +1 @@
+module.exports = require('./dist/react');
diff --git a/addons/knobs/src/base.js b/addons/knobs/src/base.js
new file mode 100644
index 000000000000..8441c2f20fc9
--- /dev/null
+++ b/addons/knobs/src/base.js
@@ -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 });
+}
diff --git a/addons/knobs/src/index.js b/addons/knobs/src/index.js
index 2f4c16dcddca..2681f3860fb2 100644
--- a/addons/knobs/src/index.js
+++ b/addons/knobs/src/index.js
@@ -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);
diff --git a/addons/knobs/src/react/index.js b/addons/knobs/src/react/index.js
index 0b093d446ddc..e1c1b5d736d5 100644
--- a/addons/knobs/src/react/index.js
+++ b/addons/knobs/src/react/index.js
@@ -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 ;
};
+
+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);
+}
diff --git a/addons/knobs/src/vue/index.js b/addons/knobs/src/vue/index.js
index ae99e44f1c1a..9cc2590c7fc5 100644
--- a/addons/knobs/src/vue/index.js
+++ b/addons/knobs/src/vue/index.js
@@ -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));
@@ -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);
+}
diff --git a/addons/knobs/vue.js b/addons/knobs/vue.js
new file mode 100644
index 000000000000..42311b17563f
--- /dev/null
+++ b/addons/knobs/vue.js
@@ -0,0 +1 @@
+module.exports = require('./dist/vue');
diff --git a/examples/cra-kitchen-sink/src/stories/index.js b/examples/cra-kitchen-sink/src/stories/index.js
index 6a6e91d58df2..1865aff8c037 100644
--- a/examples/cra-kitchen-sink/src/stories/index.js
+++ b/examples/cra-kitchen-sink/src/stories/index.js
@@ -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';
diff --git a/examples/crna-kitchen-sink/storybook/stories/Knobs/index.js b/examples/crna-kitchen-sink/storybook/stories/Knobs/index.js
index 8ca5af5a4440..776fb1eb5729 100644
--- a/examples/crna-kitchen-sink/storybook/stories/Knobs/index.js
+++ b/examples/crna-kitchen-sink/storybook/stories/Knobs/index.js
@@ -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');
diff --git a/examples/react-native-vanilla/storybook/stories/Knobs/index.js b/examples/react-native-vanilla/storybook/stories/Knobs/index.js
index 8ca5af5a4440..776fb1eb5729 100644
--- a/examples/react-native-vanilla/storybook/stories/Knobs/index.js
+++ b/examples/react-native-vanilla/storybook/stories/Knobs/index.js
@@ -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');
diff --git a/examples/react-native-vanilla/storybook/stories/index.js b/examples/react-native-vanilla/storybook/stories/index.js
index 2eea2d4a4e29..2aab33712874 100644
--- a/examples/react-native-vanilla/storybook/stories/index.js
+++ b/examples/react-native-vanilla/storybook/stories/index.js
@@ -4,7 +4,7 @@ import { Text } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';
-import { withKnobs } from '@storybook/addon-knobs';
+import { withKnobs } from '@storybook/addon-knobs/react';
import knobsWrapper from './Knobs';
import Button from './Button';
diff --git a/examples/vue-kitchen-sink/src/stories/index.js b/examples/vue-kitchen-sink/src/stories/index.js
index cbaea1df5144..666cc4d19474 100644
--- a/examples/vue-kitchen-sink/src/stories/index.js
+++ b/examples/vue-kitchen-sink/src/stories/index.js
@@ -12,7 +12,7 @@ import {
select,
color,
date,
-} from '@storybook/addon-knobs';
+} from '@storybook/addon-knobs/vue';
import Centered from '@storybook/addon-centered';
import MyButton from './Button.vue';