-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
Changes from 3 commits
003912a
f5b0596
9f147b5
5e74ef8
8c23357
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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: | ||
|
||
|
@@ -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 { addonKnobs, text, boolean, number } from '@storybook/addon-knobs/dist/react'; | ||
|
||
const stories = storiesOf('Storybook Knobs', module); | ||
|
||
|
@@ -50,18 +53,33 @@ stories.add('with a button', () => ( | |
<button disabled={boolean('Disabled', false)} > | ||
{text('Label', 'Hello Button')} | ||
</button> | ||
)) | ||
)); | ||
|
||
const options = {}; | ||
// Knobs as dynamic variables. | ||
stories.add('as dynamic variables', () => { | ||
stories.add('as dynamic variables', withKnobsOptions(options)(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make this |
||
const name = text('Name', 'Arunoda Susiripala'); | ||
const age = number('Age', 89); | ||
|
||
const content = `I am ${name} and I'm ${age} years old.`; | ||
return (<div>{content}</div>); | ||
}); | ||
})); | ||
``` | ||
|
||
> In the case of Vue, use these imports: | ||
> | ||
> ```js | ||
> import { storiesOf } from '@storybook/vue'; | ||
> import { addonKnobs, text, boolean, number } from '@storybook/addon-knobs/dist/vue'; | ||
> ``` | ||
> | ||
> In the case of React-Native, use these imports: | ||
> | ||
> ```js | ||
> import { storiesOf } from '@storybook/react-native'; | ||
> import { addonKnobs, text, boolean, number } from '@storybook/addon-knobs/dist/react'; | ||
> ``` | ||
|
||
You can see your Knobs in a Storybook panel as shown below. | ||
|
||
![](docs/demo.png) | ||
|
@@ -236,12 +254,10 @@ const value = date(label, defaultValue); | |
If you feel like this addon is not performing well enough there is an option to use `withKnobsOptions` instead of `withKnobs`. | ||
Usage: | ||
|
||
```js | ||
story.addDecorator(withKnobsOptions({ | ||
debounce: { wait: number, leading: boolean}, // Same as lodash debounce. | ||
timestamps: true // Doesn't emit events while user is typing. | ||
})); | ||
``` | ||
story.addDecorator(withKnobsOptions({ | ||
debounce: { wait: number, leading: boolean}, // Same as lodash debounce. | ||
timestamps: true // Doesn't emit events while user is typing. | ||
})); | ||
|
||
## Typescript | ||
|
||
|
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 }); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,22 @@ | ||
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/knobs directly is discouraged, please use @storybook/knobs/dist/{{framework}}' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addons currently adopt the following es5 pattern for registration require('./dist/register') Can we do something analogous for frameworks? |
||
); | ||
|
||
// "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 | ||
// See https://github.com/storybooks/storybook/pull/1527 | ||
function wrapperKnobs(options) { | ||
const channel = addons.getChannel(); | ||
manager.setChannel(channel); | ||
|
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)); | ||
|
@@ -35,3 +41,23 @@ export const vueHandler = (channel, knobStore) => getStory => context => ({ | |
knobStore.unsubscribe(this.setPaneKnobs); | ||
}, | ||
}); | ||
|
||
// "Higher order component" / wrapper style API | ||
// In 3.3, this will become `withKnobs`, once our decorator API supports it. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is 3.3? Should we handle this API migration now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will delete that file with 4.0. Let's keep this as backwards compatible as possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK then the comment is wrong? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, I think the solution @tmeasday and I have in mind is backwards-compatible. |
||
// See https://github.com/storybooks/storybook/pull/1527 | ||
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did
addonKnobs
come back? is this a bad merge?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my bad indeed, good catch